Xamarin.iOS 中的 CoreML 简介

CoreML 将机器学习引入了 iOS – 应用可以利用经过训练的机器学习模型来执行各种任务,从解决问题到图像识别均可得到支持。

本简介涵盖以下内容:

CoreML 入门

以下步骤介绍了如何将 CoreML 添加到 iOS 项目。

火星栖息地价格预测器示例屏幕截图

1.将 CoreML 模型添加到项目

将 CoreML 模型(具有 .mlmodel 扩展名的文件)添加到项目的“Resources”目录中。

在模型文件的属性中,将其“生成操作”设置为 CoreMLModel。 这意味着在生成应用程序时,它将编译为 .mlmodelc 文件。

2.加载模型

使用 MLModel.Create 静态方法加载模型:

var assetPath = NSBundle.MainBundle.GetUrlForResource("NameOfModel", "mlmodelc");
model = MLModel.Create(assetPath, out NSError error1);

3.设置参数

使用实现 IMLFeatureProvider 的容器类传入和传出模型参数。

特征提供程序类的行为类似于字符串和 MLFeatureValue 字典,其中每个特征值可以是简单的字符串或数字、数组或数据,或者包含图像的像素缓冲区。

单值特征提供程序的代码如下所示:

public class MyInput : NSObject, IMLFeatureProvider
{
  public double MyParam { get; set; }
  public NSSet<NSString> FeatureNames => new NSSet<NSString>(new NSString("myParam"));
  public MLFeatureValue GetFeatureValue(string featureName)
  {
    if (featureName == "myParam")
      return MLFeatureValue.FromDouble(MyParam);
    return MLFeatureValue.FromDouble(0); // default value
  }

使用这样的类,可以通过 CoreML 能够理解的方式提供输入参数。 特征的名称(如代码示例中的 myParam)必须与模型的预期用途相匹配。

4.运行模型

使用模型要求实例化特征提供程序并设置参数,然后调用 GetPrediction 方法:

var input = new MyInput {MyParam = 13};
var outFeatures = model.GetPrediction(inputFeatures, out NSError error2);

5.提取结果

预测结果 outFeatures 也是 IMLFeatureProvider 的一个实例;可以使用 GetFeatureValue 和每个输出参数的名称(如 theResult)来访问输出值,如以下示例所示:

var result = outFeatures.GetFeatureValue("theResult").DoubleValue; // eg. 6227020800

将 CoreML 与视觉框架配合使用

CoreML 还可以与视觉框架结合使用,以对图像执行操作,例如形状识别、对象识别和其他任务。

以下步骤介绍如何结合使用 CoreML 和 Vision。 该示例将视觉框架中的矩形识别MNINSTClassifier CoreML 模型相结合,以识别照片中的手写数字。

数字 3 的图像识别数字 5 的图像识别

1.创建视觉 CoreML 模型

以下代码将加载 CoreML 模型 MNISTClassifier,然后将其包装在 VNCoreMLModel 中,从而使该模型可用于视觉任务。 此代码还将创建两个视觉请求:首先在图像中查找矩形,然后使用 CoreML 模型处理矩形:

// Load the ML model
var bundle = NSBundle.MainBundle;
var assetPath = bundle.GetUrlForResource("MNISTClassifier", "mlmodelc");
NSError mlErr, vnErr;
var mlModel = MLModel.Create(assetPath, out mlErr);
var model = VNCoreMLModel.FromMLModel(mlModel, out vnErr);

// Initialize Vision requests
RectangleRequest = new VNDetectRectanglesRequest(HandleRectangles);
ClassificationRequest = new VNCoreMLRequest(model, HandleClassification);

该类仍需要为视觉请求实现 HandleRectanglesHandleClassification 方法,如下面的步骤 3 和 4 所示。

2.启动视觉处理

以下代码将开始处理请求。 在 CoreMLVision 示例中,此代码将在用户选择一个图像后运行:

// Run the rectangle detector, which upon completion runs the ML classifier.
var handler = new VNImageRequestHandler(ciImage, uiImage.Orientation.ToCGImagePropertyOrientation(), new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(()=>{
  handler.Perform(new VNRequest[] {RectangleRequest}, out NSError error);
});

此处理程序会将 ciImage 传递给在步骤 1 中创建的视觉框架 VNDetectRectanglesRequest

3.处理视觉处理的结果

矩形检测完成后,它会执行 HandleRectangles 方法,该方法将裁剪图像以提取第一个矩形,将矩形图像转换为灰度,然后将其传递给 CoreML 模型来进行分类。

传递给此方法的 request 参数包含视觉请求的详细信息,并会在使用 GetResults<VNRectangleObservation>() 方法时返回在图像中找到的矩形列表。 此时将提取第一个矩形 observations[0] 并将其传递给 CoreML 模型:

void HandleRectangles(VNRequest request, NSError error) {
  var observations = request.GetResults<VNRectangleObservation>();
  // ... omitted error handling ...
  var detectedRectangle = observations[0]; // first rectangle
  // ... omitted cropping and greyscale conversion ...
  // Run the Core ML MNIST classifier -- results in handleClassification method
  var handler = new VNImageRequestHandler(correctedImage, new VNImageOptions());
  DispatchQueue.DefaultGlobalQueue.DispatchAsync(() => {
    handler.Perform(new VNRequest[] {ClassificationRequest}, out NSError err);
  });
}

ClassificationRequest 在步骤 1 中实现了初始化,以使用下一步中定义的 HandleClassification 方法。

4.处理 CoreML

传递给此方法的 request 参数包含 CoreML 请求的详细信息,并会在使用 GetResults<VNClassificationObservation>() 方法时返回按置信度排序的可能结果列表(置信度最高的排在最前面):

void HandleClassification(VNRequest request, NSError error){
  var observations = request.GetResults<VNClassificationObservation>();
  // ... omitted error handling ...
  var best = observations[0]; // first/best classification result
  // render in UI
  DispatchQueue.MainQueue.DispatchAsync(()=>{
    ClassificationLabel.Text = $"Classification: {best.Identifier} Confidence: {best.Confidence * 100f:#.00}%";
  });
}