背景
机械学习是目前比较热门的技术,它的英文名称叫做Machine Learning
简称ML。
早在2017年WWDC上,Apple公司就宣布其提供的框架Core ML
已经被每个主流ML平台支持,并可以将现有的训练好的模型转换成Core ML
支持的模型。
Turi Create
在2017年WWDC之后被收购,其简化了定制机器学习模型的开发,降低了开发门槛。开发者无需成为机器学习专家,就可以进行机械训练,导出Core ML
支持的模型。但是它使用的语言是Python。
2018年WWDC上,apple宣布了新的ML开发工具Create ML
,这次使用的是自己的语言swift并集成到Xcode中。虽然目前只完成了Turi Create
的部分功能,但后续会不断扩展优化。
本文就是介绍使用Create ML
和Core ML
框架,体验一次机械学习从无到有的过程。
开发环境
想要使用Create ML
需要满足2个条件:
- 一台Mac,运行macOS 10.14 Mojave beta
- Xcode 10.x beta
写这篇文章的时候 Mojave 版本是10.14 beta 8,Xcode 10 beta 6。下载链接:https://developer.apple.com/download/
创建一个自己训练的模型
准备机械学习的数据样本
我想做一个自动识别各种动物的神经模块,因此,我准备了一些动物的图片,作为数据样本。因为时间原因,从百度上下80张动物图片,分别为兔子、猫、狗、老虎,每个种类各20张。这里对图片有些要求,尽量清晰,并且最好只有一个动物。
数据样本越多,训练的效果越好,不过相对的训练的时间也越长。
图片分类.png准备机械学习效果验证的数据样本
有了学习数据样本后,还需要准备一个验证样本,来验证机械学习训练结果的准确性,目录结构和之前一样,每个动物我准备了10个图片。
测试数据.png开始机械训练
用xcode10创建机械学习库
打开xcode10,创建一个macOS版的playground。
macOS_playground.png然后输入以下代码:
import CreateMLUI
let builder = MLImageClassifierBuilder()
builder.showInLiveView()
点击运行并打开辅助界面就可以看到Create ML的训练界面。
机械训练界面.png导入样本数据进行训练
将之前准备的数据样本,pets文件夹拖入右侧的虚线框就可以自动进行训练。
pets文件夹里面有很多字文件夹,每个文件夹成为数据集,里面是同一类图片数据,字文件夹的名称就是这一类的输出结果。字文件夹名字不能用中文,会在后面集成自己APP的时候输出乱码,应该有其他方法解决。
训练结果.png上面这张图片是我80个测试数据样本的训练结果,第一个表格是有3个表格头,分别是Images Processed
、 Elapsed Time
、Percent Complete
代表的是图片总个数、花费时间和完成进度。在我的电脑配置下,80个图片大约用了14秒。
每次训练完成,系统会在样本数据中随机抽取10%的数据样本进行准确度验证,第二个表格是验证结果。我的样本数据得到了100%的验证结果。
从上面这个训练过程可以看出,我们并不需要进行代码编写机械学习的算法,这些Create ML都帮我们实现了,并且提供了一套优秀的提取图片特征算法,我们只需要提供样本数据就能得到训练后的模型,因此的确不需要专业的机械学习知识。
进行准确度验证
经过以上步骤,我们能够得到一个初步的神经模型,但是我们还需要测试其是否准确,是否达到我们的要求,因此还需要进行验证。将之前准备好的pets-test文件夹(目录结构和pets一致)拖入右上角虚线框就可以进行验证。
验证结果.png可以看到,这次训练的模型结果有一张图片出错,我传进去是猫的图片,它是被成了兔子。准确率只有98%。根据这个结果,我们可以选择是否使用这个模型。
提高模型准确性
提供准确性有很多方法,加大数据样本数量,优化样本数据等等。Create ML提供一些优化方法可以在训练之前设置,如下图:
增加样本.png我们可以给图片样本增加参数,如翻转flipping, 旋转rotating, 斜切shearing或改变曝光exposure等,打上勾就会增加效果并进行排列组合增加样本数量。
官方提供的解释.png我们还可以增加iterations的值提高准确性,这个应该和算法有关。不过这里需要注意的是,勾选越多就意味着样本数据越多,训练的时间也就越长。
下面是优化过的模型结果,正确率有一定提高。
正确率提高.png最后一步就是导出数据模型,我们下面将在工程中使用它。
保存数据模型.png在工程中使用训练好的模型
新建一个工程
导出的模型是一个以.mlmodel
结尾的文件,我的模型大小不太大,大概53KB左右。新建一个singleView工程,然后直接将该模型拖进来就可以直接使用。
.mlmodel文件会自动根据项目的语言转换成OC或者swift代码,点击中间紫色图标右边的箭头就可以进入查看对应的代码。
api代码.png从上图我们可以看到,主要有3个类animal
,animalInput
,animalOutput
,分别是主类,输入类和输出类。
animalOutput
是输出结果类,里面有个属性的名字叫做classLabel
就是相似度最高的结果,另外一个属性classLabelProbs
就是每个结果的可能性占比,占比越高可能性越大。
animalInput
是输入类,其支持一个初始化方法- (instancetype)initWithImage:(CVPixelBufferRef)image;
,可以看出需要把图片转换成CVPixelBufferRef
格式然后才能使用。
图片转化
前面我们已经说到不能直接使用UIImage格式,而需要转换成CVPixelBufferRef
格式下面是转换代码:
- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
CVPixelBufferRef pxbuffer = NULL;
CGFloat frameWidth = CGImageGetWidth(image);
CGFloat frameHeight = CGImageGetHeight(image);
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
frameWidth,
frameHeight,
kCVPixelFormatType_32ARGB,
(__bridge CFDictionaryRef) options,
&pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata,
frameWidth,
frameHeight,
8,
CVPixelBufferGetBytesPerRow(pxbuffer),
rgbColorSpace,
(CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
CGContextConcatCTM(context, CGAffineTransformIdentity);
CGContextDrawImage(context, CGRectMake(0,
0,
frameWidth,
frameHeight),
image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
这里还有一点需要主注意,从Model Evaluation Parameters的表格中可以看出,输入的图片规格需要时299 X 299,因此还需要将UIImage先转换成299 X 299大小再进行转换。
下面是转换代码:
- (UIImage *)scaleToSize:(CGSize)size image:(UIImage *)image {
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
模型的使用
在使用前别忘了加入头文件#import "animal.h"
我这里是使用从相册中选取一张图片,然后判断该图片是什么类型的动物,代码如下:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
//获取图片
UIImage *image = info[UIImagePickerControllerOriginalImage];
[self dismissViewControllerAnimated:YES completion:nil];
self.photoView.image = image;
UIImage * newSizeImage = [self scaleToSize:CGSizeMake(299, 299) image:image];
CVPixelBufferRef imageRef = [self pixelBufferFromCGImage:newSizeImage.CGImage];
NSError * error = nil;
animalOutput * outPut = [_netModel predictionFromImage:imageRef error:&error];
if (error == nil) {
NSNumber * num = [outPut.classLabelProbs objectForKey:outPut.classLabel];
NSString * resultStr = [NSString stringWithFormat:@"%@ : %.2lf",outPut.classLabel,[num doubleValue]];
self.resultLabel.text = resultStr;
}
else {
self.resultLabel.text = error.description;
}
}
网友评论