Apple 机器学习框架 Core ML 教程

Jack Cui

共 8143字,需浏览 17分钟

 · 2020-12-28



我是来自山区、朴实、不偷电瓶的AI算法工程师阿chai,给大家分享人工智能、自动驾驶、机器人、3D感知相关的知识



今天是12.24号,阿chai在这里祝福大家平安夜快乐。一说到平安夜,会想到平安果——苹果,那今天阿chai就出一期Apple公司的机器学习框架Core ML的教程,喜欢的小伙伴可以传递下去,祝愿大家“手中有卡、眼里有丹”


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=(2242243,),
    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=(12242243,),
                           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(13224224)
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=(13224224))])

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.4850.4560.406],
        std=[0.2290.2240.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”工程师的帽子,奥利给。

浏览 140
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报