这是我参与「第四届青训营 」笔记创作活动的第9天
端智能技术演进与实践
课程回顾
这里回顾一下码率(比特率) 表示单位时间内传送 bit 的数目,单位bps,表示是单位时间播放连续的媒体如压缩后的音视频的bit数量,也称为码流。
这种bps的单位电信领域上表示速度,就是我们常说的网速了。比如 100Mbps(兆位每秒),要换算成一般下载时显示的速度则除以 8,即 100 / 8 = 12.5mb/s 。
端智能是什么
- 端智能(On-Device Machine Learning)是指把机器/深度学习算法模型应用和部署到端设备上,这里“端设备”是相对于云服务而言的,可以是手机,也可以是物联网IoT设备。
- Google对端智能的介绍 developers.google.com/learn/topic…
案例如:抖音换装特效,离线文字识别,肢体检测,手势识别等
机器学习已进入生活中各个方面,在移动端上也有着非常多的应用场景:
- 视觉:扫码、人脸手势识别、肢体姿态估计、目标检测跟踪、图像分割、OCR文字识别提取、图片视频实时超分等
- 语音:语音分类识别等
- 文本:翻译、对话系统、文本分类、智能回复等
- 其他:推荐精排、无人驾驶、运动检测、智能预加载、AR、VR等
- Google提供的端上机器学习能力介绍 developers.google.com/learn/topic…
为什么要做端智能
-
低延迟、实时性高(Low Latency) :特征收集、模型推理、业务逻辑均在端侧完成,无需网络交互,端侧也更能够实时感应用户状态。
-
保护隐私(Privacy) :数据只在端侧使用,无需上传云端,可更好地保护用户隐私数据。
-
算力(Power) :移动端设备越来越强大,算力越来越高。
-
可离线(Offline) :可以离线使用。
-
低成本(Low Cost) :在端侧计算,利用端侧算力和存储空间,可节省大量的云端计算和存储资源。
-
端云协同: 端智能并不是云智能的替代,是云端机器学习的延伸,是要结合云和端各自的优势,在云端之间合理分配任务以获取问题最优解。
- 端设备上算力、内存、存储和功耗受限,运行的模型大小有限制;云端有海量数据和充足算力资源,两者配合协同可以发挥各自优势;典型的场景如移动端上的智能精排场景。
端智能的发展历程
-
2006年,深度学习被提出,又得益于大数据的发展和硬件算力提升,深度学习算法和框架也不断演进,人工智能领域迎来了一次大发展。
-
与此同时,端侧设备在算力、算法和框架上同样有突飞猛进的发展,各类端侧框架和案例层出不穷。
- 2015年Tensorflow 推出Mobile版SDK,随后2017年开源,腾讯NCNN开源,各大互联网公司相继推出自己的移动端机器学习框架,开启了移动端计算框架开源潮。
端侧机器学习框架
- Google:Tensorflow Lite、ML Kit
- Meta:PyTorch Mobile、PyTorch Live
- Apple: CoreML
- 腾讯:NCNN、TNN,(NCNN和TNN不得不说的故事)
- 阿里:MNN
- 百度:Paddle-Lite
- 华为: HiAI 、ML Kit
- 小米:Mace
- 其他:字节(ByteNN、Pitaya),快手(KwaiNN、Ykit)……
端智能技术案例
手写数字识别
数字识别是很多机器学习的入门第一个案例,相关资料很多如:
www.tensorflow.org/tutorials/q… (全连接模型)
此例完整代码和数据集已存于 github.com/ahcyd008/Di…
需求背景
- App要做一个手写输入法模块,支持输入数字0~9,如何实现?
- 效果类似手机上的手写输入法
端智能案例落地套路
-
分三个步骤
- 首先,把问题描述和定义清楚,并调研出通过机器学习解决问题的方法。
- 然后,设计和训练出机器学习模型,并针对端侧设备优化和转换模型。
- 最后,把优化后模型部署和集成到端侧设备应用中,执行推理预测,并以进预测结果解决定义的问题。
问题和方案
-
问题:App要做一个手写输入法模块,支持输入数字0~9。
-
解决方案:
- 训练一个可以识别手写数字的机器学习模型。
- 将此模型部署应用到App中,实现手写输入到识别的过程,并将识别结果供给用户选择输入。
-
机器学习部分:
- 输入:手写输入数字(图片)
- 输出:其可能代表的数字数值,多种可能时给出各自置信度(0.0~1.0)。
训练AI模型
数据收集
-
数据收集来源方式
- ~~开源数据 - ~~~ MNIST~
-
合成数据- 如将各种字体下的数字写在黑板上生成图片,作为样本。
-
人工收集和标注的数据 (本次模型训练仅使用此种方式)
- 设计和实际需求贴合的一个数据采集程序
- 兼顾不同年龄段、性别、左手/右手等
-
收集的数据被保存在收集sdcard中;同时为方便数据回收,会同步上传到云端。
-
数据从手机sdcard中导出的命令
-
adb pull /storage/emulated/0/Android/data/com.clientai.recog.digital/files/Track/ ./ 复制代码 -
数据上传的云端为 http://129.204.41.76:8000/
- 临时供课程学习收集数据使用,web数据存储服务介绍参考github.com/ahcyd008/Da…
-
-
数据增广
-
对原始图片进行旋转、平移、缩放变换,扩充更多数据集,增强模型适应性。
- 第一张是原图,其他15张为增广图片。
-
模型设计和训练
-
模型设计
-
先看一个可以在线模拟演示神经网络模型设计神奇网站,playground.tensorflow.org/。
- 模型的设计就像一个搭积木的过程,通过调整神经元个数和层数让预测更精确;神经元和层数越多相应耗时也会增加,需要综合权衡考虑。
-
模型训练
-
完整参考代码 notebook/digital_recognition.ipynb (notebook代码包括了运行结果缓存)
-
搭建训练环境
- 在vscode中安装jupyter notebook运行环境 code.visualstudio.com/docs/datasc…
- 安装Tensorflow和相关依赖
pip install matplotlib numpy Pillow tensorflow torch torchvision
训练样本处理
图片通过旋转、平移、缩放、剪切、翻转增广16倍,并缩放到28x28大小,转成numpy array 作为输入样本
org = Image.open(file)
# 需要数据增广
w, h, c = (*org.size, len(org.mode))
# 数据增广配置
trans = torchvision.transforms.Compose([
torchvision.transforms.RandomAffine(translate=(0.25, 0.25), scale=(0.8, 1.2), degrees=40, interpolation=torchvision.transforms.functional.InterpolationMode.NEAREST),
torchvision.transforms.RandomHorizontalFlip(p=0.2),
torchvision.transforms.RandomCrop(size=(h, w))])
# 增广15倍,带原图16张
for i in range(16):
if i == 0:
img = org
else:
img = trans(org)
img = img.resize((28, 28), Image.ANTIALIAS)
gray = img.convert("L")
x = np.asarray(gray)/255.
y = label
X.append(x)
Y.append(y)
模型构建-Keras
模型训练
# 全连接网络
def creat_nn(print_summary=False):
model = Sequential()
model.add(layers.Flatten(input_shape=(28, 28)))
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
if print_summary:
model.summary()
return model
train_x = X
# 将label转成向量,如 2 => [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
train_y = tf.keras.utils.to_categorical(Y, num_classes=10)
model.fit(train_x, train_y, batch_size=24, epochs=16, verbose=1)
验证模型准确度
y_pred = model.predict(valid_x)
// 用y_pred预测值与真值对比,计算准确度
模型压缩和转换
-
为什么要做模型转换?
- 移动端使用的是被优化的推理引擎,可以在不同CPU和GPU架构下高效的执行模型推理计算。
-
这里我们使用Tensorflow Lite作为移动端上推理引擎。
- TensorFlow Lite 的设计旨在在各种设备上高效执行模型。这种高效部分源于在存储模型时,采用了一种特殊的格式。
- TensorFlow模型在被TensorFlow Lite 使用前,必须转换成这种格式。
- Tensorflow Lite 提供转换器 TFLite Convert。
-
#save tflite model converter = tf.lite.TFLiteConverter.from_keras_model(model) tflite_model = converter.convert() open(tflite_name, "wb").write(tflite_model) 复制代码
AI模型在移动端部署和应用
- Tensorflow Lite 提供了很多样例供大家学习参考 (其中也包括了手写数字识别)
- github.com/tensorflow/…
模型部署到移动端
-
核心:让移动端可以加载到前面转化的模型
- 简单做法:放在App包体内assets目录下。
-
- 进阶做法:通过url动态下载,支持动态更新,同时减少包体积。
-
在移动端加载模型,Tensorflow Lite官方给出了指引
- www.tensorflow.org/lite/guide/…
- 代码参考 DigitalClassifier
- Tensorflow Lite 将模型的加载和执行封装在Interpreter类中
-
// 引入tensorflow lite 依赖 implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT' // 从文件加载模型 public Interpreter(File modelFile, Options options) // 将模型读取到bytebuffer,从bytebuffer加载模型 public Interpreter(ByteBuffer byteBuffer, Options options) 复制代码
移动端推理预测
-
推理预测是指设备上执行 TensorFlow Lite 模型
- 代码位于 DigitalClassifier
- www.tensorflow.org/lite/guide/… (官方指导)
-
加载模型
-
var model: ByteBuffer = load(mymodel.tflite) val interpreter = Interpreter(model, options) // 可通过 interpreter 查看输入和输出格式 // inputShape:[1, 28, 28], outputShape:[1, 10]
-
-
构造模型输入
- 模型的输入28x28单通道灰度图,而用手写输入是数据是存在bitmap中
- 需要将bitmap图片 resize 缩放到28x28像素,转灰度,再转成bytebuffer,这是 interpreter 接受的输入格式。
-
执行推理预测
- 构造输出buffer,调用run执行计算
-
val result = Array(1) { FloatArray(10) } // outputShape:[1, 10] interpreter.run(inputByteBuffer,result)
-
获取推理预测结果
- result中的10个数值代表手写输入是 0~9 这10个数字置信度分值,对分值进行排序,把排序前三的数字作为预测输出,供用户选择。
拿到结果执行业务策略
- 视频中可以看出在输入8时不够准确,这受限于数据不足、模型简单。在实际场景中我们落地一个场景后,也需要不断迭代优化,让我们的智能方案更佳完善。
- 在demo中也提供了cnn版本的优化模型,准确率更高一些。
小结
- 一个端智能案例的落地套路流程
架构部分:问题发现和定义 -> 设计解决方案
算法部分:训练数据收集 -> 训练数据收集 -> 算法设计 -> 模型训练 -> 模型压缩/转换(云端) -> 迭代调优
工程部分:模型部署(云端) -> 预测样本采集 -> 推理预测 -> 业务调用
最后:结果应用
左右手智能识别和应用(抖音案例)
左右手识别案例在GitHub上也有一份样例可参考 github.com/ahcyd008/Op…
案例Demo中放置的数据不多,模型准确率不高,作为同学们课后作业,继续:
- 搭建好左右手识别案例Demo运行环境
- 收集更多左右手训练数据,优化模型让其准确率更高,适应性更好。
- 将模型替换到案例Demo中,实测效果。
需求背景
-
很多App会以右手习惯来设计交互,并以此去引导用户点击它们期望的选项。
-
存在问题:用户左手使用手机时,引导效果会变差,有没有更智能更个性化的交互体验方式?
- 左手和右手单手拇指操作时的舒适区是相反的,针对右手的UI交互可能对左手并不友好。特别随着屏幕尺寸再不断增大,这种差异更明显。
- 另外一些数据统计看左手用的比例并不低。
- 依照前卖了提到的端智能场景落地套路,我们继续来拆解这个场景。
问题和方案
-
问题:设计一种方法检测用户是左手在操作手机、还是右手在操作手机,然后依据检测结果动态调整交互,提升用户体验。
- 如识别到右手时,交互设计保持右手适配模式;识别到左手时,交互设计更改为左手适配模式。
调研:手指在屏幕滑动轨迹识别左右手
-
机器学习方案:
- 训练一个二分类的CNN神经网络模型来识别用户是左手 or 右手操作。
- 输入:用户在屏幕上的滑动轨迹
- 输出:左手 or 右手
训练AI模型
数据收集
-
数据格式:
- X样本:[p0, p1, p2, p3, p4, … ] ,p=(x, y, w, h, density, dt)。
- Y样本:left / right
-
收集方式:(特殊客户端,内测用户收集)
- 滑动轨迹:拦截Activity的dispatchTouchEvent
- 事件,缓存手指滑动产生的MotionEvent序列。
左右手标签:
- 开启左手样本收集时,只用左手持机操作,只录制左手滑动数据。
- 开启右手样本收集时,只用右手持机操作,只录制右手滑动数据。
模型设计
- 二分类模型( Left or Right ),卷积神经网络。
# 卷积神经网络
def creat_cnn(input_shape=(9, 6), print_summary=False):
model = Sequential()
model.add(layers.Conv1D(6, kernel_size=3, input_shape=input_shape, padding='same', activation='relu'))
model.add(layers.Conv1D(12, kernel_size=3, padding='same', activation='relu'))
model.add(layers.Conv1D(24, kernel_size=3, strides=2, padding='same', activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
if print_summary:
model.summary()
return model
模型训练和转换
-
训练样本处理
- 滑动轨迹X样本需要采样对齐成9个固定点输入方式
-
def getX(points): size = len(points) if size < 6 : # 过滤误触 return None sample_count = 9 tensor_size = 6 step = size * 1.0 / sample_count x = [] for i in range(sample_count): p = points[int(i*step)] if len(p) == 6: x.append(p) # x, y, w, h, density, dtime return x
-
模型训练
- 完整案例代码参考 notebook/ohr_recognition.ipynb
-
验证模型准确度
-
模型转换
- 在Demo案例我们继续用Tensorflow Lite 提供的转换器 TFLite Convert,将模型转为移动端模型。
- 在抖音使用的端上推理计算框架是ByteNN,其也提供了相应的Tensorflow Lite模型进一步转成ByteNN模型的工具。
移动端推理预测 & 应用
模型部署到移动端
- 在抖音中模型是通过url下发的,动态更新,需要更新模型时也可以通过Libra实验进行对比。
- 在案例Demo中,是和案例1一样,放在安装包assets目录下。
移动端推理预测
-
接入模型后,在用户滑动后触发预测,将预测结果缓存,业务使用时获取最近识别结果。
-
案例中我们继续使用Tensorflow Lite作为推理引擎,加载和执行模型预测。
- 抖音中使用ByteNN推理引擎执行推理预测。
-
拿到结果执行业务策略
- 当App拥有了识别左右手能力后,也就有了更精细的优化用户体验的手段,譬如:
端智能工程师学习长路线
入门
-
达成:对端智能技术有一定认识,可以协作完成端智能技术的需求落地
- 了解端智能技术是什么、可以做什么
- 掌握移动端开发、Machine Learning 基础知识,了解业内端智能框架
- 理解怎么做端智能,可以协作完成端智能技术解决实际业务问题的需求落地
-
学习资料:
- 了解端智能可以做哪些事情:Google MLKit、华为 MLKit
- 机器学习入门: Tensorflow入门、机器学习速成课、微软AI-EDU
- 机器学习在移动端应用:TensorflowLite入门
- 机器学习原理:吴恩达课程
进阶
- 达成:对移动端技术、端智能技术和负责业务有更深入的理解,可以站在更全面的视野上设计端上智能解决方案,建设端上智能架构。
课程总结
-
什么是端智能技术
- 端智能是什么 (what):是将AI算法模型部署和应用到端侧
- 为什么要做端智能 (why):端智能的优势 Latency、Privacy、Power、Offline、Cost
- 端智能的发展历程
-
端智能技术实践案例 (how)
- 手写数字识别
- 左右手智能识别和应用(抖音案例)
-
端智能工程师学习长路线
- 端智能技术落地完整流程
- 入门:对端智能技术有一定认识,可以协作完成端智能技术的需求落地。
- 进阶:对移动端技术、端智能技术和负责业务有更深入的理解,可以站在更全面的视野上设计端上智能解决方案,建设端上智能架构。