打造第一个自训练模型的Core ML应用

苹果爸爸的新玩具

Posted by Forrest Lam on 2018-08-20

Core ML是iOS11的新特性,赋予iOS App更多AI的能力,例如垃圾短信识别、Siri、人脸识别、场景识别等等,过去集成在iOS系统的AI能力终于通过Core ML开放给第三方开发者了。随后苹果在今年WWDC发布了Create ML,这个苹果自家人工智能模型训练平台,苹果人工智能生态系统正逐渐形成,今天我们就借着一个简单的Core ML应用简单窥探一下。

介绍

Core ML 是iOS系统中人工智能模型的运行环境,开发者可以将自己训练好的模型转换为mlmodel,然后就可以应用内调用模型进行分类或预测了,目前支持转换的模型有caffe、keras、scikit-learn等。至于Core ML的能耐本文也不详细介绍了,参考苹果自己封装的图像处理分析框架vision和NLP框架就知道了。

准备工具

为了简单起见,数据处理和模型的训练本文使用Python编写,以下都是机器学习常用类库,均可通过pip install xxx安装。
模型训练工具:scikit-learn
数据处理:pandas
模型转换工具:linear_model

生成数据

由于本文编写的只是一个demo,所以数据是本地随机生成的,生成脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random
import pandas as pd
if __name__ == '__main__':
params_count = 4
params = []
for i in range(params_count):
params.append(random.random())
df = pd.DataFrame(columns=['x1', 'x2', 'x3', 'y'])
for i in range(10000):
X = []
for j in range(params_count - 1):
X.append(random.randint(0, 100))
y = sum([X[i] * params[i] for i in range(params_count - 1)])
y += params[-1]
line = X
line.append(y)
df.loc[i] = line
df.to_csv('random_data.txt', index=False, sep=',')
print('params = %s\n'%(','.join(map(str, params))))

训练模型

我们将生成的数据分为训练数据和测试数据,对于训练数据,我们用最简单的线性回归模型训练,训练过程中我们用交叉数据验证下模型的准确率,最后保存到文件中,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from sklearn.cross_validation import KFold
import pandas as pd
from sklearn import linear_model
import numpy as np
from sklearn.externals import joblib
if __name__ == '__main__':
train_data = pd.read_table('random_train_data.txt', sep=',')
X_train = train_data.ix[:, [0, 1, 2]]
y_train = train_data[['y']]
kf = KFold(y_train.shape[0], n_folds=5)
residuals, scores = [], []
for train_index, test_index in kf:
clf = linear_model.LinearRegression()
clf.fit(X_train.iloc[train_index, :], y_train.iloc[train_index, :])
residual = np.mean(clf.predict(X_train.iloc[test_index, :]) - y_train.iloc[test_index, :]) ** 2
print('Residual sum of squares = %.2f'%(residual))
residuals.append(residual)
score = clf.score(X_train.iloc[test_index, :], y_train.iloc[test_index, :])
print('Score = %.2f'%(score))
scores.append(score)
print('\n')
print('Mean Residual sum of squares = %.2f' % np.mean(residuals))
print('Mean score = %.2f' % np.mean(scores))
clf = linear_model.LinearRegression()
clf.fit(X_train, train_data['y'])
joblib.dump(clf, 'linear_regression.pkl')

转换模型

我们得到scikit-learn模型后还不能直接在iOS中调用,需要经过苹果的工具coremltools进行转换,代码如下,关键是convert函数和save函数,其他都是关于模型的描述,可以不设置,可以说非常符合苹果API风格,简单易用。

1
2
3
4
5
6
7
8
9
10
11
12
13
import coremltools
from sklearn.externals import joblib
from sklearn import linear_model
if __name__ == '__main__':
clf = joblib.load('linear_regression.pkl')
coreml_model = coremltools.converters.sklearn.convert(clf, ["x1", "x2", "x3"], "y")
coreml_model.author = "forrestlin"
coreml_model.license = "BSD"
coreml_model.input_description['x1'] = 'x1 in [0, 100)'
coreml_model.input_description['x2'] = 'x2 in [0, 100)'
coreml_model.input_description['x3'] = 'x3 in [0, 100)'
coreml_model.output_description['y'] = 'result'
coreml_model.save('linear_regression.mlmodel')

应用模型

得到mlmodel文件后,我们可以直接将其拖入xcode工程中,选中模型文件会显示模型信息,如下图所示:

在导入模型后,xcode会自动生成模型类,以模型文件名为类名,创建模型实例后,我们调用prediction方法即可得到预测结果,十分简单,代码如下:

1
2
3
4
5
6
7
8
let linearRegression = linear_regression()
let x1 = Double.init(x1TextField.text ?? "0") ?? 0.0
let x2 = Double.init(x2TextFied.text ?? "0") ?? 0.0
let x3 = Double.init(x3TextField.text ?? "0") ?? 0.0
guard let resultOutput = try? linearRegression.prediction(x1: x1, x2: x2, x3: x3) else {
fatalError("Unexpected runtime error.")
}
resultLabel.text = "预测结果:\(String.init(format: "%.3f", resultOutput.y))"

运行界面如下,由于是自己就是根据线性模型生成的数据,所以预测结果和真实结果完全一致,2333~

总结

demo虽小,但五脏俱全,希望以此打开苹果人工智能生态系统的大门,也希望对各位读者有用,App demo源码见附件