Apple 机器学习框架 Core ML 教程
我是来自山区、朴实、不偷电瓶的AI算法工程师阿chai,给大家分享人工智能、自动驾驶、机器人、3D感知相关的知识
Core ML是Apple的机器学习框架,将机器学习模型集成到苹果的应用程序中。可使用coremltools 软件包将TensorFlow等框架训练的模型转换为Core ML格式。如果小伙伴想开发Core ML,最好先有一台Mac。
应用程序使用Core ML API和用户数据在用户设备上进行预测并微调模型。Core ML通过利用CPU,GPU和神经引擎来优化设备上的性能,同时最大程度地减少其内存占用空间和功耗。
安装与测试
1.安装
安装环境最好使用Conda,具体安装请参考阿chai之前的教程。
创建虚拟环境:
conda create --name coremltools-env
激活并安装:
# 激活环境
conda activate coremltools-env
# 安装
pip install --upgrade coremltools
2. 测试
测试以TF2.x复现的MobileNetV2模型为例:
import tensorflow as tf
import cv2
# 下载 MobileNetv2
keras_model = tf.keras.applications.MobileNetV2(
weights="imagenet",
input_shape=(224, 224, 3,),
classes=1000,
)
import urllib
label_url = 'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt'
class_labels = urllib.request.urlopen(label_url).read().splitlines()
class_labels = class_labels[1:]
assert len(class_labels) == 1000
for i, label in enumerate(class_labels):
if isinstance(label, bytes):
class_labels[i] = label.decode("utf8")
模型转换:
import coremltools as ct
image_input = ct.ImageType(shape=(1, 224, 224, 3,),
bias=[-1,-1,-1], scale=1/127)
classifier_config = ct.ClassifierConfig(class_labels)
model = ct.convert(
keras_model, inputs=[image_input], classifier_config=classifier_config,
)
CoreML可以设定一些描述模型特征的参数,在Xcode中使用可以查看部分信息,便于开发者使用。
model.author = 'xxxx'
model.license = 'xxxx'
model.short_description = 'xxxx'
model.version = 'xxxx'
保存与加载模型:
# 保存模型
model.save("MobileNetV2.mlmodel")
# 加载模型
loaded_model = ct.models.MLModel("MobileNetV2.mlmodel")
进行预测:
example_image = cv2.imread('dog.jpg')
# 预测
out_dict = model.predict({"input_1": example_image})
print(out_dict["classLabel"])
Xcode的使用教程请前往B站、油管等资源网站寻找。
模型转换
CoreML在iOS、iPad、Apple Watch上的模型加速效果非常棒,但是小伙伴们用的训练框架种类很多,那今天就来个大杂烩,都来一遍。
1. TensorFlow 2.x
这里的TF2.x并不是Keras。
import coremltools as ct
import tensorflow as tf
tf_model = tf.keras.applications.MobileNet()
model_from_tf = ct.convert(tf_model)
2. Keras
TF一定要注意版本,Theano做后端时会麻烦一些。
mport coremltools as ct
model = ct.converters.keras.convert('keras_model.h5')
from keras.models import load_model
keras_model = load_model("keras_model.h5")
model = ct.converters.keras.convert(keras_model)
3. PyTorch
PyTorch能直接转换,并不需要ONNX。
import coremltools as ct
import torch
import torchvision
model = torchvision.models.mobilenet_v2()
model.eval()
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)
traced_model.save("torchvision_mobilenet_v2.pt")
mlmodel = ct.convert("torchvision_mobilenet_v2.pt",
inputs=[ct.TensorType(shape=(1, 3, 224, 224))])
4.ONNX
ONNX与Core ML部分兼容,具体内容可以参考官方的git查看源码。
import coremltools as ct
model = ct.converters.onnx.convert(model='my_model.onnx')
5.Caffe
首先下载如下文件:
-
bvlc_alexnet.caffemodel -
deploy.prototxt -
class_labels.txt
import coremltools as ct
model = ct.converters.caffe.convert(
('bvlc_alexnet.caffemodel', 'deploy.prototxt'),
predicted_feature_name='class_labels.txt'
)
model.save('BVLCObjectClassifier.mlmodel')
量化方法
Core ML模型转换后的默认精度为FP32。FP16shi 官方认为最保险的方法。
import coremltools as ct
from coremltools.models.neural_network import quantization_utils
model_fp32 = coremltools.models.MLModel('model.mlmodel')
model_fp16 = quantization_utils.quantize_weights(model_fp32, nbits=16)
量化到8位可能会出现精度下降的情况。
# linear
model_8bit = quantize_weights(model_fp32, nbits=8)
# kmeans
model_8bit = quantize_weights(model_fp32, nbits=8,
quantization_mode="kmeans")
# linearsymmetric
model_8bit = quantize_weights(model_fp32, nbits=8,
quantization_mode="linear_symmetric")
linear:默认模式,对权重使用线性量化,并带有比例和偏差项。
linear_symmetric:对称量化,只有比例项。
kmeans_lut:使用Kmeans算法构造权重的查找表量化。
Core ML默认对所有具有权重参数的图层进行量化。由于模型的准确性可能对某些图层敏感,因此不应进行量化,因此可以选择跳过某些图层。
有两种方法可以执行此操作。一种是通过使用类,该类允许您设置简单的属性,例如图层类型,重量计数等。
from coremltools.models.neural_network.quantization_utils import AdvancedQuantizedLayerSelector
selector = AdvancedQuantizedLayerSelector(
skip_layer_types=['batchnorm', 'bias', 'depthwiseConv'],
minimum_conv_kernel_channels=4,
minimum_conv_weight_count=4096
)
quantized_model = quantize_weights(model,
nbits=8,
quantization_mode='linear_symmetric',
selector=selector)
编写自定义规则来通过扩展类来对图层进行量化。
from coremltools.models.neural_network.quantization_utils import QuantizedLayerSelector
class MyLayerSelector(QuantizedLayerSelector):
def __init__(self):
super(MyLayerSelector, self).__init__()
def do_quantize(self, layer, **kwargs):
ret = super(MyLayerSelector, self).do_quantize(layer)
if not ret or layer.name == 'dense_2':
return True
selector = MyLayerSelector()
quantized_model = quantize_weights(
mlmodel,
nbits = 8,
quantization_mode='linear',
selector=selector
)
机器学习
Core ML同时也支持一下机器学习的加速推理,例如一些回归、分类的模型。
1.Scikit-learn
最好不要下载最新版本,阿chai测试出现了一些问题。
from sklearn.linear_model import LinearRegression
import pandas as pd
# 导入数据
data = pd.read_csv('houses.csv')
# 训练模型
model = LinearRegression()
model.fit(data[["bedroom", "bath", "size"]], data["price"])
# 转换并保存
import coremltools as ct
coreml_model = ct.converters.sklearn.convert(
model, ["bedroom", "bath", "size"], "price")
coreml_model.save('HousePricer.mlmodel')
2.XGBoost
XGBoot在建议源码安装,经常有使用pip出问题。
import coremltools as ct
# 转换、保存
coreml_model = ct.converters.xgboost.convert(model)
coreml_model.save('my_model.mlmodel')
3.LIBSVM
当时看到支持LIBSVM的时候阿chai愣了一下,后来一想,也有道理。
import svmutil
problem = svmutil.svm_problem([0,0,1,1], [[0,1], [1,1], [8,9], [7,7]])
libsvm_model = svmutil.svm_train(problem, svmutil.svm_parameter())
import coremltools as ct
coreml_model = ct.converters.libsvm.convert(libsvm_model)
coreml_model.save('./my_model.mlmodel')
coreml_model = ct.converters.libsvm.convert(libsvm_model, input_names=['x', 'y'])
完整案例
前面对Core ML的安装测试、模型转换、量化以及结合机器学习框架等的方法进行了描述,下面我们根据小伙伴们常用的PyTorch来实现一个完成整的模型转换的案例。
以DeepLab v3为例,Xcode的操作以及分割效果放在代码下面。
import urllib
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
import torch
import torch.nn as nn
import torchvision
import json
from torchvision import transforms
from PIL import Image
import coremltools as ct
model = torch.hub.load('pytorch/vision:v0.6.0', 'deeplabv3_resnet101', pretrained=True).eval()
input_image = Image.open("test.jpg")
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225],
),
])
input_tensor = preprocess(input_image)
input_batch = input_tensor.unsqueeze(0)
with torch.no_grad():
output = model(input_batch)['out'][0]
torch_predictions = output.argmax(0)
class WrappedDeeplabv3Resnet101(nn.Module):
def __init__(self):
super(WrappedDeeplabv3Resnet101, self).__init__()
self.model = torch.hub.load('pytorch/vision:v0.6.0', 'deeplabv3_resnet101', pretrained=True).eval()
def forward(self, x):
res = self.model(x)
x = res["out"]
return x
traceable_model = WrappedDeeplabv3Resnet101().eval()
trace = torch.jit.trace(traceable_model, input_batch)
mlmodel = ct.convert(
trace,
inputs=[ct.TensorType(name="input", shape=input_batch.shape)],
)
mlmodel.save("SegmentationModel_no_metadata.mlmodel")
mlmodel = ct.models.MLModel("SegmentationModel_no_metadata.mlmodel")
labels_json = {"labels": ["background", "aeroplane", "bicycle", "bird", "board", "bottle", "bus", "car", "cat", "chair", "cow", "diningTable", "dog", "horse", "motorbike", "person", "pottedPlant", "sheep", "sofa", "train", "tvOrMonitor"]}
mlmodel.user_defined_metadata["com.apple.coreml.model.preview.type"] = "imageSegmenter"
mlmodel.user_defined_metadata['com.apple.coreml.model.preview.params'] = json.dumps(labels_json)
mlmodel.save("SegmentationModel_with_metadata.mlmodel")
到这里Core ML的教程就结束了,就是这样简单粗暴。其实框架都大同小异,Core ML其实是阿chai接触的第一个移动端推理的框架,用起来真的非常的方便。
后天有部分小伙伴们就要走进考场,一年一度的研究生统考将要拉开帷幕,不要紧张,相信自己没问题。今年过的真的很快,没什么感觉就年底了,Keras之父说现在不是人工智能的“寒冬”,但是阿chai觉得,一定是调包侠的寒冬了。我们一期努力,争取早日甩掉“CV”工程师的帽子,奥利给。