写在前面:
在2017年的WWDC大会上,随着iOS 11的发布,随之而来的还有一系列新的特性和功能,同样也带来了独特的布局适配问题。在这次大会中,苹果推出了CoreML框架,能够将机器学习应用在移动端上,这等于在一些online的基础上提供了offline方式,可以说在实际的开发过程中,能在一些特定的业务需求上能提供极大的帮助。
什么是机器学习?
机器学习,也就是目前被大家经常提起的Machine Learning,也可以说是现在很火的一个技术,它也是人工智能最核心的内容。比如说横扫世界棋坛大名鼎鼎的阿尔法狗(AlphaGo),或者已经深入大家生活场景的图片识别、语言翻译、云歌曲推荐等等,这其实都是机器学习的具体实际应用的结果。
机器学习就是一种能让计算机不需要进行不断人工手动编程添加功能,而能自己学习的人工智能技术。它不是通过具体的编码算法,而是在大量的模型数据中找到一个合适的模式从而让计算机能够不断的发展和完善自身算法。
这个技术所要模拟的就是一个庞大而复杂的‘神经网络’,这个'神经网络'就需要大量的训练好的模型(model)来提供数据,使得这个'神经网络'能对各种输入(inputs)产生出一个对应的输出结果(outputs),并且还能通过不断的训练数据来提高自己的算法准确性。
这里的核心其实就是训练各种模型(model)来处理各种不同的情况和需求。比如说有了一个专门识别人脸的模型,给一个输入图片他就能把人脸位置输出出来等等等等,最后如果将无限多的训练好的模型都结合起来,那这个计算机可能就能像人一样应对各种情况还能不断地自我完善。下图是机器学习的一些应用场景:
CoreML是什么
Core ML根据官方文档里的这张图就可以看出,其实它的作用就是将一个训练好的ML模型,转换成我们的app工程可以直接使用的对象。利用该模型可以基于新的输入数据而进行预测,也就是利用了机器学习的结果。比如,如果一个模型在一个地区的历史房价数据上进行了训练,那么它就可能能够根据房子的卧室或客厅数量来预测房价。
Core ML 为设备性能进行了优化,从而减少了内存占用和功耗。严格在设备上运行能够确保用户数据的隐私,并且能保证你的应用在没有网络连接时也能够工作和响应。构建完成的Core ML又作为其他更高级框架的基础,比如支持用于图像分析的 Vision 框架,用于自然语言处理的 Foundation类,以及用于评估已经学习到的决策树的 GameplayKit。如下图:
- vision:高性能的图像分析和图像识别。这部分应用于人脸追踪,人脸识别,文本识别,区域识别,二维码识别,物体追踪,图像识别等。
- Nattural Language processing:自然语言处理。用于语言识别,分词,词性还原,词性判定等。
- GamePlayKit:游戏制作,构建游戏。用于常见的游戏行为如随机数生成、人工智能、寻路、和代理行为。
Vision是什么
Vision是一个高性能的图片分析库,他能识别在图片和视频中的人脸、特征、场景分类等。你如果打开Vision的官方文档看,官方对他包含的所有类做了分类,比如有Face Detection and Recognition(人脸检测识别)、Machine Learning Image Analysis(机器学习图片分析)、Barcode Detection(条形码检测)、Text Detection(文本检测)等等。
大概可以这样去理解:Vision库里就已经自带了很多训练好的模型,这些模型是针对上面提到的人脸识别、条形码检测等等功能,如果你要实现的功能刚好是Vision库本身就能实现的,那么你直接使用Vision库自带的一些类和方法就行。
而当你要使用一个你在网上找的训练好的模型或者你自己训练好的模型的时候,才需要CoreML来将这个相当于‘第三方’模型转换成app认得的类,之后才能使用这个模型,同时也结合上面提到的Vision的Machine Learning Image Analysis(机器学习图片分析)分类下的类和方法来使用这个模型进行图形分析或者Vision其它的一些模型进行一系列分析操作。
CoreML Samples
下面给大家介绍官网给出的一个Mars Habitat Pricer sample,用以预测火星上的殖民地价值
1.给项目中添加model
将已经编译好的一个以.modelc为后缀的model添加到Resources项目文件夹中,然后设置这个文件夹下所有文件的build action为BundleResource
2.加载model
在我们使用model之前,我们需要使用MLModel.Create
这个静态方法去加载model
var bundle = NSBundle.MainBundle;
var assetPath = bundle.GetUrlForResource("MarsHabitatPricer", "mlmodelc");
NSError mlErroe;
model = MLModel.Create(assetPath, out mlErroe);
3.设置参数
当我们开始使用这个模型之前,我们需要用Xcode打开我们的model,查看需要相应的inputs和outputs分别是什么,同时传入模型参数以及获取结果时都需要使用一个继承IMLFeatureProvider
的容器类,这个类相当于一个字典,其中包含string的key,以及与之相对应的MLFeatureValues
,每个feature value可以是string,number,array,data或者image buffer。
public class MarsHabitatPricerInput : NSObject, IMLFeatureProvider
{
public double SolarPanels { get; set; }
public double Greenhouses { get; set; }
public double Size { get; set; }
public NSSet<NSString> FeatureNames => new NSSet<NSString>(new NSString("solarPanels"), new NSString("greenhouses"), new NSString("size"));
public MLFeatureValue GetFeatureValue(string featureName)
{
switch (featureName)
{
case "solarPanels":
return MLFeatureValue.Create(SolarPanels);
case "greenhouses":
return MLFeatureValue.Create(Greenhouses);
case "size":
return MLFeatureValue.Create(Size);
default:
return MLFeatureValue.Create(0);
}
}
}
通过以上这种方式,我们的输入参数就可以被CoreML所识别,其中public NSSet<NSString> FeatureNames => new NSSet<NSString>(new NSString("solarPanels"), new NSString("greenhouses"), new NSString("size"));
中的FeatureNames NSSet必须跟model所要求的输入保持相同。
4.使用model
使用model需要实例化我们自定义的继承了IMLFeatureProvider
的容器类,将pickerview中三列的值传入MarsHabitatPricerInput,然后调用GetPrediction
方法,然后通过调用GetFeatureValue
方法,获取到相应的输出
void updatePredictedPrice()
{
var pricerInput = new MarsHabitatPricerInput()
{
SolarPanels = datasource.GetValue(pickerView.SelectedRowInComponent(0), Feature.SolarPanels),
Greenhouses = datasource.GetValue(pickerView.SelectedRowInComponent(1), Feature.Greenhouses),
Size = datasource.GetValue(pickerView.SelectedRowInComponent(2), Feature.Size)
};
// Use the ML model
NSError prErr;
var outFeatures = model.GetPrediction(pricerInput, out prErr);
var result = outFeatures.GetFeatureValue("price").DoubleValue;
priceLabel.Text = "Predicted Price (millions) " + priceFormatter.StringFor(new NSNumber(result));
Console.WriteLine(prErr == null ? $"result was {result}" : "Unexpected runtime error " + prErr.Description);
}
CoreML With Vision Framework Samples
CoreML也可以与Vision框架结合使用对图像进行操作,例如形状识别,人脸识别等其它操作。下面这个CoreML With Vision Samples中采用了CoreML和Vision 。该示例将Vision框架中的rectangles recognition与MNINSTClassifier.mlmodelc相结合,以识别照片中的手写数字。
1.创建一个Vision CoreML model
使用CoreML加载MNISTClassifier模型后,将其包装在一个VNCoreMLModel 模型中,使得该模型可用于图片处理。以下代码还创建了两个Vision请求:首先用于在图像中查找矩形,然后用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
RectangleRequest = new VNDetectRectanglesRequest(HandleRectangles);
ClassificationRequest = new VNCoreMLRequest(model, HandleClassification);
2.开始Vision处理
// Run the rectangle detector, which upon completion runs the ML classifier.
var handler = new VNImageRequestHandler(ciImage, uiImage.Orientation.ToCGImagePropertyOrientation(), new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(()=>{
NSError error;
handler.Perform(new VNRequest[] {RectangleRequest}, out error);
});
});
通过传入一个CIImage对象给Vision Framework,之后根据第一步创建的VNDetectRectanglesRequest请求,当矩形识别完毕后会执行相应的HandleRectangles回调函数。
3.处理Vision操作的结果
当开始执行HandleRectangles回调函数之后,裁剪图像以提取第一个矩形,将矩形图像转换为灰度,并将其传递给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);
});
}
4.使用CoreML
通过传入处理完成之后的CIImage对象给MNISTClassifier后,根据第一步创建的VNCoreMLRequest请求,当数字识别完毕后会执行相应的HandleClassification回调函数。
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}%";
});
}
传入的request参数中包含CoreML Request的详细信息,通过调用GetResults<VNClassificationObservation>()
方法返回可能的结果结合。
写在最后:
到此在Xamarin.iOS中使用CoreML和Vision的案例介绍就完成了,之后也会给大家带来CoreML with Azure Custom Vision Service的介绍,包括使用工具转化第三方Model的介绍。可以看出对于集成CoreML来说,其实不是特别复杂,但是其中的算法可以说是非常高深的,我也会继续保持对CoreML的关注,分享更多的相关内容给大家。
到这里Xamarin.iOS CoreML和Vision的介绍就完成了,希望能对您有所帮助。