iOS(swift): Core ML的使用
神经网络模型在移动端可以利用CPU加速,但是,如果算法同事那边为了更好的效果在尝试不同的模型,相应的在部署iOS移动端这块就需要不断的修改网络模型。Core ML的出现使部署移动端的任务量可以缩减到最少两行代码。
苹果官方给出了如何利用Core ML的demo,并且给出了两个例子。一个是根绝输入相关数据预测房价,另外一个是输入图片给出分类结果(结合了Vision框架)。打开Xcode ->window->Developer Documentation,输入Core ML,得到相应的官方介绍。
结合官方文档,首选任务是如何获取一个Core ML模型,该模型文件的后缀为.mlmodel。
Core ML Tool:
该工具是Python语言写的工具包,支持很多机器学习平台生成的模型转成mlmodel文件,如caffe、keras等,可惜不支持TensorFlow。如果使用TensorFlow,可利用GitHub上的第三方平台进行转换(tf-coreml),并且只支持部分OP操作。现在话题转移到TensorFlow模型转换成mlmodel的工具上。从该项目上下载代码后,暂时感觉有两个比较重要的功能,一个在inspect_pb.py文件里面,调用该文件里面的inspect方法(需要输入两个参数,第一个参数为pb文件路径,第二个为输出txt文件路径)。该方法是读取pb文件里所有OP操作的名字以及相应配置,并写入txt文件。读取txt文件信息你可以了解到该模型的每一次OP的名字,并且到这里tensor的shape是多少。拉到该txt文件的最下面,你还可以知道该模型每一个OP操作一共执行了多少次。如图所示:
另外一个比较重要的文件肯定是如何利用该工具将pb文件转成mlmodel文件了。在tests文件夹的tests_tf_converter.py的最后,可以看到使用tf_converter.convert()方法,点到convert()方法里面,可以看到后很多参数,但是必须输入的是前三个,tf模型路径,输出mlmodel的路径以及输出tensor的名字,这里感觉input_name_shape_dict也是需要给出的,毕竟如果该网络不是全卷机网络,那么该输入的图片尺寸就必须是固定的,那么你就应当给出输入tensor或者placeholder的具体shape。另外,这其中有个很容易忽略的参数,如果忽略了,那么在iOS采用Core ML进行模型推理的时候会变得很麻烦(稍后会解释),该参数就是image_input_names。该参数是一个string类型,表示一个tensor的名字,给与该参数赋值表明该tensor接受的是一个image(pixelBuffer)类型,因此一般是输入tensor的名字:例如:
模型的可视化:
我们查看模型的结构,除了使用netron该神器(可以查看很多机器学习平台生成的模型结构,caffe、TensorFlow、MXNet等等),也可以使用Core ML Tool,很简单,两行代码:
import coremltoolsmodel = coremltools.models.MLModel('HousePricer.mlmodel')model.visualize_spec()
mlmodel文件的使用
通过上述步骤,应该会顺利得到mlmodel文件。这里就只是展示了官方给的demo上的mlmodel文件进行说明。首先拖入到xcode后点击MobileNet.mlmodel会看到:
首先,红框地方表示输入的一些信息,可以看到输入的是一个image,尺寸为224x224。输入的是一个字典类型和一个classLabel总集。在这里之所以标红是因为上面说的image_input_names在pb文件转成mlmodel文件时,设置该参数的问题。如果不设置,那么你可能会看到类似这种输入信息:
该MultiArray输入类型在Python中的数组处理应该比较简单,Python本身很多图片处理框架读取一张图片直接就是三维数组的形式,但是在iOS中就比较麻烦。所以在转换模型的时候,image_input_names参数一定要设置好。
点击上图中红圈标记的地方后,会跳如mlmodel文件自动生成的一个同名swift文件。它是有三个类组成,一个是模型输入类、模型类、模型输出类。输出和输入这两个类的使用和创建还是比较简单的,他们都继承自MLFeatureProvider。而且他们的方法还都很类似,其中一个叫做MLFeatureValue,这个类很有意思。查看他的相关解释会发现,他几乎hold住了所有Core ML中相关数据类型的一个类,比如imageBufferValue,multiArrayValue等等。
这里应当注意的是,在accessing the value 这个解释下面,他的每个属性都是在他初始化传入数据格式时就已经确定,比如说初始化的时候为传入的数据为MLMutiArray,那么只有他的multiArrayValue这个属性不为空。曾经用到的时候,天真的以为初始化时传入MLMutiArray,那么通过他的imageBufferValue属性就可以得到pixelBuffer的图像格式,这样就省去了MLMutiArray到pixelBuffer格式转换的麻烦。所以当我们用到类似风格转换的神经网络图像处理时,输出来的是MLMutiArray的格式,只能老老实实的用相关方法转成image了。还好已经有大神为我们写好相关方法——CoreMLHelper,只是速度有点慢。利用CoreMLHelper项目中的转换方法,可以得出能够显示的image:
//image为从相册取出的image,imageToPixelBuffer是image->pixelBuffer的格式转换方法let pixBuffer = self.imageToPixelBuffer(image: image, width: 1280, height: 720)!guard let outModel = try?self.model.prediction(src_input__0: pixBuffer) else {fatalError("Visionular warning : Unexpected runtime error.")}let resultMultiArray = outModel.imgout__0let result_image = resultMultiArray.image(min:0,max:255)
不过,在仔细研究了Core MLtools后发现了即使输入和输出是MLMutiArray,但是通过该工具是可以在次转换的。即通过tf_coreml工具转换后,还可以继续使用苹果自家的Core ML Tool工具把格式以及一些描述信息给添加上。由于主要是输出的数据格式转换,那么这里就只给了输出的格式转换,因此还是要多关注一下Core ML Tool 具体的操作。
def export_coreml_image(image, array_shape):from coremltools.proto import FeatureTypes_pb2 as ftchannels, height, width = array_shapeif channels == 1:image.type.imageType.colorSpace = ft.ImageFeatureType.ColorSpace.Value('GRAYSCALE')elif channels == 3:image.type.imageType.colorSpace = ft.ImageFeatureType.ColorSpace.Value('RGB')else:raise ValueError("Channel Value %d not supported for image inputs" % channels)image.type.imageType.width = widthimage.type.imageType.height = heightif __name__ == '__main__':path = '/Users/MacBook/Desktop/v1.0.0.1_pb/Out_format_isImage.mlmodel'coreml_model = tf_converter.convert(tf_model_path="/Users/MacBook/Desktop/v1.0.0.1_pb/coustome.pb",mlmodel_path="/Users/MacBook/Desktop/v1.0.0.1_pb/out_model.mlmodel",image_input_names="src_input:0",output_feature_names=['imgout:0'],input_name_shape_dict={'src_input:0':[1, 720, 1280, 3]})spec = coreml_model.get_spec()toolmodel = coremltools.models.MLModel(spec)image_output = spec.description.output[0]output_array_shape = tuple(image_output.type.multiArrayType.shape)export_coreml_image(image_output, output_array_shape)toolmodel.save(path)
那么,在将转出来的模型利用xcode可以看到:
输出是image格式,第二个箭头处的description则是空白的,比如我们可用:
coreml_model.output_description[outImageName] = 'out_image'
outImageName是输出的tensor的名字,这里是imgout。好比代码中的:output_feature_names=['imgout:0']。
其他的信息设置还有:
coreml_model.author = 'John Smith'
coreml_model.license = 'BSD'
coreml_model.short_description = 'Predicts the price of a house in the Seattle area.'
# Set feature descriptions manually
model.input_description['bedroom'] = 'Number of bedrooms'
model.input_description['bathrooms'] = 'Number of bathrooms'
model.input_description['size'] = 'Size (in square feet)'
# Set the output descriptions
model.output_description['price'] = 'Price of the house'# Save the model
model.save('HousePricer.mlmodel')
mlmodel的瘦身与选择运行设备
在官网提供的方法中,默认直接利用的MobileNet()方法加载了mlmode模型。加入我们要选择设备运行方式呢,即:使用CPU还是GPU甚至NPU来对模型进行加速呢。苹果已经提供了相应的配置方法。这里就采用懒加载的方式在里面进行设置了:
lazy var model : MobileNet = {do{let config = MLModelConfiguration.init()config.computeUnits = MLComputeUnits.cpuAndGPUlet model = try MobileNet.init(configuration: config)return model}catch{fatalError("Failed to load MobileNet ML model: \(error)")}}()
通过MLModelConfiguration类可以对模型使用哪种设备来加速进行配置。MLComputeUnits有cpuOnly、cpuAndGPU、all。前面两个就比较好解释了,最后一个all是cpu、GPU、还有苹果自家芯片A11以及后代产品中自带的NPU。由此也可以看出,我们没有办法独自选择GPU或者NPU进行加速。在这里稍微提一下,如果采用带有NPU的设备,并且利用了NPU(也就是配置中选择了all,或者直接采用let mode = MobileNet()创建的model。)结果有可能不对(起码我在项目中遇到了该问题,配置选择cpuOnly或者CPUAndGPU没有问题),对于该问题,GitHub相关项目上也有人提到,很多人猜测可能是NPU中数据处理的格式类型有可能不对(比如说cpu中用到的是float32,而NPU用到的是float8等等,当然这也只是猜测)。
一般神网训练出来的模型比较大,在预测精度降低不是那么明显的情况下,选择量化方案可大大降低模型的大小。Core ML Tool自带了该工具。用法特别简单,直接在安装了Core ML Tool工具的Python包中调用相关API即可:
import coremltoolsfrom coremltools.models.neural_network.quantization_utils import *
urlPath = 'Path/model.mlmodel'
desPath = 'Path/model_8.mlmodel'
model = coremltools.models.MLModel(urlPath)
line_quant_model_8 = quantize_weights(model, 8, "linear")
line_quant_model_8.save(desPath)
主要是quantize_weights()该方法,第一个参数不用解释,第二个参数即量化的bit量,可以为16,8,4,甚至为2。第三个参数即量化方法,这里使用的是线性量化,其他的量化方法可点进去看一下,比如说kmeam量化方法等。
需要指出的是,在我测试的项目中,模型尽管变小了,但是计算速度并没有提高,甚至还有所下降。当然精度肯定是下降的。
iOS(swift): Core ML的使用相关推荐
- iOS 11: CORE ML—浅析
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/OWD5UEiVu5JpYArcd2H9ig 作者:l ...
- iOS 11 : CORE ML—浅析
导语:在刚刚过去的WWDC上,苹果发布了Core ML这个机器学习框架.现在,开发者可以轻松的使用Core ML把机器学习功能集成到自己的应用里,让应用变得更加智能,给用户更牛逼的体验. 苹果在 iO ...
- ios 11 CORE ML 学习入门
导语:在刚刚过去的WWDC上,苹果发布了Core ML这个机器学习框架.现在,开发者可以轻松的使用Core ML把机器学习功能集成到自己的应用里,让应用变得更加智能,给用户更牛逼的体验. 苹果在 iO ...
- 手把手教你在应用里用上iOS机器学习框架Core ML
2017-06-10 Cocoa开发者社区 2017年的WWDC上,苹果发布了Core ML这个机器学习框架.现在,开发者可以轻松的使用Core ML把机器学习功能集成到自己的应用里,让应用变得更加智 ...
- iOS Core ML与Vision初识
代码地址如下: http://www.demodashi.com/demo/11715.html 教之道 贵以专 昔孟母 择邻处 子不学 断机杼 随着苹果新品iPhone x的发布,正式版iOS 11 ...
- 使用YOLO Core ML模型构建对象检测iOS应用(七)
目录 在我们的应用程序中添加模型 在捕获的视频帧上运行目标检测 绘制边界框 实际应用 下一步? 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器 ...
- 为iOS Vision盒子架构建Core ML管道(五)
目录 介绍 去掉多余的盒子 构建管道 对管道的预测 下一步 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器(二) 使用数组操作解码YOLO C ...
- 将ONNX对象检测模型转换为iOS Core ML(一)
目录 介绍 使用YOLO进行物体检测 寻找正确的模型 将ONNX转换为Core ML 下一步 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器( ...
- AR Kit Core ML 将救百万iOS开发者于水深火热中
AR 市场到底有多大? 目前AR 的困境之处,主要是AR 穿戴设备这一个问题上.可以预知到,AR一旦有了成熟的设备问世, AR将会以迅雷不及掩耳之速普及市场. 支付宝对社交的渴望是路人皆知的,但此前的 ...
- 使用数组操作解码YOLO Core ML对象检测(三)
目录 介绍 解码YOLO输出的正确方式 下一步 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器(二) 使用数组操作解码YOLO Core ML ...
最新文章
- QT中无法使用10^n次方来计算
- 技术干货 | Native 页面下如何实现导航栏的定制化开发?
- shell 非_Shell基本操作(一)
- 网页 php pdf文件怎么打开是乱码,打开php文件乱码的解决方法
- c 修改mysql数据库_c 修改mysql数据库
- 快速理解设计模式六大原则
- 模块使用:time、datetime、calendar、sys、os、os.path、normcase和normapath、random、json、pickle...
- kotlin多继承_Kotlin继承
- 转发的 呀 犯法不 顶级 的 学学不错 【分享】各大资源论坛推荐及优势特点
- IGBT功率半导体器件
- 机械工业出版社6000册图书都有哪些?
- 经纬度转GeoHash
- 聊一聊如何把SSL证书安装到小鸟云服务器上
- mac笔记本电脑外接显示器没有声音
- z-buffer算法
- MEMS mic之PDM mic(二)
- 性能测试——CPU占用率的计算原理
- python3_面向对象
- faq页面 html csdn,jQuery和css3简单实用的FAQ问答页面模板
- 220V转5V非隔离2W电源--超低成本