Apple 機(jī)器學(xué)習(xí)框架 Core ML 教程
我是來(lái)自山區(qū)、樸實(shí)、不偷電瓶的AI算法工程師阿chai,給大家分享人工智能、自動(dòng)駕駛、機(jī)器人、3D感知相關(guān)的知識(shí)
。

Core ML是Apple的機(jī)器學(xué)習(xí)框架,將機(jī)器學(xué)習(xí)模型集成到蘋(píng)果的應(yīng)用程序中。可使用coremltools 軟件包將TensorFlow等框架訓(xùn)練的模型轉(zhuǎn)換為Core ML格式。如果小伙伴想開(kāi)發(fā)Core ML,最好先有一臺(tái)Mac。

應(yīng)用程序使用Core ML API和用戶數(shù)據(jù)在用戶設(shè)備上進(jìn)行預(yù)測(cè)并微調(diào)模型。Core ML通過(guò)利用CPU,GPU和神經(jīng)引擎來(lái)優(yōu)化設(shè)備上的性能,同時(shí)最大程度地減少其內(nèi)存占用空間和功耗。
安裝與測(cè)試
1.安裝
安裝環(huán)境最好使用Conda,具體安裝請(qǐng)參考阿chai之前的教程。
創(chuàng)建虛擬環(huán)境:
conda?create?--name?coremltools-env
激活并安裝:
#?激活環(huán)境
conda?activate?coremltools-env
#?安裝
pip?install?--upgrade?coremltools
2. 測(cè)試
測(cè)試以TF2.x復(fù)現(xiàn)的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")
模型轉(zhuǎn)換:
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可以設(shè)定一些描述模型特征的參數(shù),在Xcode中使用可以查看部分信息,便于開(kāi)發(fā)者使用。
model.author?=?'xxxx'
model.license?=?'xxxx'
model.short_description?=?'xxxx'
model.version?=?'xxxx'
保存與加載模型:
#?保存模型
model.save("MobileNetV2.mlmodel")
??????????????????
#?加載模型
loaded_model?=?ct.models.MLModel("MobileNetV2.mlmodel")
進(jìn)行預(yù)測(cè):
example_image?=?cv2.imread('dog.jpg')
#?預(yù)測(cè)
out_dict?=?model.predict({"input_1":?example_image})
print(out_dict["classLabel"])
Xcode的使用教程請(qǐng)前往B站、油管等資源網(wǎng)站尋找。
模型轉(zhuǎn)換
CoreML在iOS、iPad、Apple Watch上的模型加速效果非常棒,但是小伙伴們用的訓(xùn)練框架種類(lèi)很多,那今天就來(lái)個(gè)大雜燴,都來(lái)一遍。
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做后端時(shí)會(huì)麻煩一些。
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能直接轉(zhuǎn)換,并不需要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部分兼容,具體內(nèi)容可以參考官方的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模型轉(zhuǎn)換后的默認(rèn)精度為FP32。FP16shi 官方認(rèn)為最保險(xiǎn)的方法。
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位可能會(huì)出現(xiàn)精度下降的情況。
#?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:默認(rèn)模式,對(duì)權(quán)重使用線性量化,并帶有比例和偏差項(xiàng)。
linear_symmetric:對(duì)稱量化,只有比例項(xiàng)。
kmeans_lut:使用Kmeans算法構(gòu)造權(quán)重的查找表量化。
Core ML默認(rèn)對(duì)所有具有權(quán)重參數(shù)的圖層進(jìn)行量化。由于模型的準(zhǔn)確性可能對(duì)某些圖層敏感,因此不應(yīng)進(jìn)行量化,因此可以選擇跳過(guò)某些圖層。
有兩種方法可以執(zhí)行此操作。一種是通過(guò)使用類(lèi),該類(lèi)允許您設(shè)置簡(jiǎn)單的屬性,例如圖層類(lèi)型,重量計(jì)數(shù)等。
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)
編寫(xiě)自定義規(guī)則來(lái)通過(guò)擴(kuò)展類(lèi)來(lái)對(duì)圖層進(jìn)行量化。
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
)
機(jī)器學(xué)習(xí)
Core ML同時(shí)也支持一下機(jī)器學(xué)習(xí)的加速推理,例如一些回歸、分類(lèi)的模型。
1.Scikit-learn
最好不要下載最新版本,阿chai測(cè)試出現(xiàn)了一些問(wèn)題。
from?sklearn.linear_model?import?LinearRegression
import?pandas?as?pd
#?導(dǎo)入數(shù)據(jù)
data?=?pd.read_csv('houses.csv')
#?訓(xùn)練模型
model?=?LinearRegression()
model.fit(data[["bedroom",?"bath",?"size"]],?data["price"])
#?轉(zhuǎn)換并保存
import?coremltools?as?ct
coreml_model?=?ct.converters.sklearn.convert(
??model,?["bedroom",?"bath",?"size"],?"price")
coreml_model.save('HousePricer.mlmodel')
2.XGBoost
XGBoot在建議源碼安裝,經(jīng)常有使用pip出問(wèn)題。
import?coremltools?as?ct
#?轉(zhuǎn)換、保存
coreml_model?=?ct.converters.xgboost.convert(model)
coreml_model.save('my_model.mlmodel')
3.LIBSVM
當(dāng)時(shí)看到支持LIBSVM的時(shí)候阿chai愣了一下,后來(lái)一想,也有道理。
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'])
完整案例
前面對(duì)Core ML的安裝測(cè)試、模型轉(zhuǎn)換、量化以及結(jié)合機(jī)器學(xué)習(xí)框架等的方法進(jìn)行了描述,下面我們根據(jù)小伙伴們常用的PyTorch來(lái)實(shí)現(xiàn)一個(gè)完成整的模型轉(zhuǎn)換的案例。
以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的教程就結(jié)束了,就是這樣簡(jiǎn)單粗暴。其實(shí)框架都大同小異,Core ML其實(shí)是阿chai接觸的第一個(gè)移動(dòng)端推理的框架,用起來(lái)真的非常的方便。


后天有部分小伙伴們就要走進(jìn)考場(chǎng),一年一度的研究生統(tǒng)考將要拉開(kāi)帷幕,不要緊張,相信自己沒(méi)問(wèn)題。今年過(guò)的真的很快,沒(méi)什么感覺(jué)就年底了,Keras之父說(shuō)現(xiàn)在不是人工智能的“寒冬”,但是阿chai覺(jué)得,一定是調(diào)包俠的寒冬了。我們一期努力,爭(zhēng)取早日甩掉“CV”工程師的帽子
,奧利給。
