最近几年,学术界、工业界、投资界各方一起发力,人工智能发展得如火如荼,硬件、算法与数据共同发展,带来了各行各业的深度应用。而我们前端er更像一个事不关己的旁观者。 在前端领域,我们如何乘上这个风口,又有什么样的方法可以用AI赋能我们的老本行。 文章没有啰嗦,只有code和干货。
众所周知,前端相关的业务相当于整个业务的用户体验前哨站。
除了在性能优化、动画等传统的体验上做努力,我们又如何在:目标(手势、肢体)识别、语音识别分析、无障碍、语音分析、增强现实、情绪识别、画像细分等等,基于人工智能的交互体验上,尽自己的一份力呢?
本文分为 第三方接口、重头训练一个模型、使用成熟模型、再次训练 4个部分来展开前端应用人工智能的方法。
希望可以抛转引玉,给大家带来一些思考。如果能对实际工作带来帮助,那就更好不过了。
下面开始正文:
一:使用第三方应用接口
使用第三方接口就跟普通的业务没太大区别,都是 【用户输入数据 ->请求接口->解析接口内容】,难点主要在于把解析后的数据玩出花样。
比如之前刷爆朋友圈的你画我猜,就是先让用户在canvas上画出图形后,把图形上传到自己的服务器,然后做出相应的预测,你画我猜类似版本体验:https://quickdraw.withgoogle.com/。
但是google并没有开放类似的使用接口,tensorflow的团队也明确表示不打算做类似的服务(我所理解的,tensorflow的愿景现阶段是尽可能的降低AI的使用门槛)。所以我收集了一些国内比较专业的AI服务商,并且尝试总结了他们的能力区别(只代表我本人的主观判断,如有错误请联系我改正):
平台 | 图像处理 | 语音 | 文本处理 | 视频 |
优图、ai开放平台 | ★★★★ | ★★★★ | ★★★★ | - |
百度大脑 | ★★★★ | ★★★★ | ★★★ | ★★ |
face++ | ★★★★★ | - | - | - |
科大讯飞 | - | ★★★★★ | - | - |
虽然第三方门槛非常低、预测结果也基本上非常可靠,但是可定制程度低、不适合在前端对视频做实时预测、收费(如果要采购敏感的外部供应商可能需要流程报备?)等等缺陷。
如果你觉得有些缺陷不能接受,跟我一起来看下第二种解决方案:重头训练一个新的模型。
二:重头训练一个新的模型
重头训练一个模型需要大量的专业知识,但是这并不影响我开始这部分的介绍 :p,我会以一个简单的例子开始,你可以测试一下你是否有兴趣深入下去。
大家请看这个例子:
x = [-1.0,0.0,1.0,2.0,3.0,4.0
]
y = [-3.0,-1.0,1.0,3.0,5.0,7.0
],
请用一点时间推导一下X和Y的关系公式:
3...
2...
1...
相信大家经过试错和思考已经找到答案了:【y=2x-1】。
这个就是神经网络的原理(我所理解的大白话):设计好神经网络之后,输入的数据根据正确答案,经过某些次数的训练(试错)之后,拟合到一个最终的值(参数)。把值(参数)保存下来,以方便其他类似场景使用。
那么落地到tensorflow代码中又是怎样的呢?我们又如何设计这个神经网络呢?请看代码(代码基于tensorflow 1.9.0):
#加载模块依赖
import tensorflow as tf
import numpy as np
from tensorflow import keras
#添加一层神经网络,输入的参数是一维向量
model = keras.Sequential([keras.layers.Dense(units=1,input_shape=[1])])
#为模型添加sgd优化器 损失函数为均方误差
model.compile(optimizer='sgd',loss='mse')
#输入的数据及正确的数据
xs = np.array([-1.0,0.0,1.0,2.0,3.0,4.0],dtype=float)
ys = np.array([-3.0,-1.0,1.0,3.0,5.0,7.0],dtype=float)
#训练模型50轮
model.fit(xs,ys,epochs=500)
#输出模型详细信息
model.summary()
#保存模型
model.save('model1.h5')
#预测某个数字的结果
print(model.predict([654615]))
[[1307159.4]]
接下来,在模型调试成功之后,把keras模型转为tfjs可以使用的模型就可以在网页中预测了(在第4部分有讲到具体操作方法)。
如果你是一个没有接触tensorflow的同学,看完这段代码应该大概率懵逼了,没错,我也是懵逼的。
而这只是一个非常简单的只有一个全连接层的入门例子(人都可以短时间推导出来),但是人工智能往往需要做特别复杂的预测,比如票房预测、无人机飞行控制,人类手动计算各项输入几乎没办法完成。那网络的设计将比这个复杂的多。(手动狗头)
初了完美的网络设计以外,如果你还希望预测的准确率高一些,很完善的数据集也是必不可少的。比如之前提到的快速涂鸦的例子,仅"飞机"一个分类的数据集就有高达13万张图片数据(https://quickdraw.withgoogle.com/data/airplane)。
所以重头训练一个新的模型,是一个学习周期很长、成本相当高的方案。如果希望短时间内用AI赋能你的业务,最好先看下其他三种方案有没有适合你的需求,或者问下AI部门的同事,他们有没有兴趣和你一起干。
如果你对此很有兴趣想要深入学习下去,推荐你看吴恩达的最新课程(开始的例子也是出自这个课程):https://www.coursera.org/specializations/tensorflow-in-practice (旁听免费)
三:使用成熟模型
除了很多限制的使用第三方接口和门槛很高的重头训练以外,我们还可以选择使用成熟的模型,tensorflow已经有js版本了,并且已经有成熟的开源模型和类库(前端开源的相关应用几乎全是基于tfjs的)。
但是几乎每个例子的demo为了展示能力,都预置了参数调整和复杂的交互逻辑,代码晦涩难懂(至少我是这么认为的)。
我把社区中开源的前端AI能力,又重新用直白的语言写了一遍,每个DEMO下有原项目地址链接,有兴趣应用的可以研究更精确的参数。
为了照顾没有摄像头的用户,我为每个例子都写了上传图像的版本。
也为了保持demo的单独性和便于理解,没有抽离公用模块,基本开箱即用:
抽取图像上的特征应用到其他图片
可识别的分类:雏菊、蒲公英、玫瑰、向日葵、郁金香
- 人脸检测
支持摄像头
识别人脸、情绪、年龄
识别人体手部
- 图像分类
支持摄像头
可识别的分类:https://github.com/tensorflow/tfjs-models/blob/master/mobilenet/src/imagenet_classes.ts
- 目标识别
支持摄像头
可识别的目标:https://github.com/tensorflow/tfjs-models/blob/master/coco-ssd/src/classes.ts
- 人物分割1.0
支持摄像头
可识别人体轮廓
- 人物分割2.0
支持摄像头
可同时识别多个人体轮廓
- 姿态检测
支持摄像头
识别人体关键点
除了在浏览器中支持以外,tfjs官方也推出了支持小程序的插件:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx6afed118d9e81df9&token=612578398&lang=zh_CN。有兴趣的同学可以学习公司同事 @xiaoxiwang 出品的TFJS小程序的视频教程。
成熟模型带来了免费、视频实时预测等等优点,同时也带来了无法定制识别自己的分类等缺点。
接下来是最后一种方法:再次训练
四:再次训练
有的时候你的需求,需要的AI能力仅仅只需要识别一个标志物体或者目标的坐标,比如某个LOGO、某幅画。那么可以在前人的训练好的模型基础上再次训练。
在没有强大数据集和AI团队支持的情况下,使用前人训练好的参数和模型设计基础上,再次训练不失为一种不错的选择。(这种方法也称为迁移学习)
下面以高度封装的tensorflow-for-poets-2为例,介绍
训练图片分类的详细步骤(只需7步):
1. clone 预训练源代码
git clone https://github.com/googlecodelabs/tensorflow-for-poets-2
cd tensorflow-for-poets-2
2. 下载测试数据集 (解压到 tensorflow-for-poets-2/tf_files
)
http://download.tensorflow.org/example_images/flower_photos.tgz
3. 开始训练 基于tensorflow 1.15.x环境
python -m scripts.retrain ^
--bottleneck_dir=tf_files/bottlenecks ^
--how_many_training_steps=2000 ^
--model_dir=tf_files/models/ ^
--summaries_dir=tf_files/training_summaries/mobilenet_0.50_224 ^
--output_graph=tf_files/retrained_graph.pb ^
--output_labels=tf_files/retrained_labels.txt ^
--architecture=mobilenet_0.50_224 ^
--image_dir=tf_files/flower_photos
mac下命令连接符是 \,win下是 ^
4. 开始训练 基于tensorflow 1.15.x环境
python -m scripts.label_image --graph=tf_files/retrained_graph.pb --image=xxx
#正常情况下会有类似输出:
daisy (score = 0.xxxx)
sunflowers (score = 0.xxxx)
5. 优化PB文件
python scripts/quantize_graph.py ^
--input=tf_files/retrained_graph.pb ^
--output=tf_files/quantized_graph.pb ^
--output_node_names=final_result ^
--mode=weights_rounded
6. 优化PB文件 基于tensorflow.js 1.15.x环境
tensorflowjs_converter ^
--input_format=tf_frozen_model ^
--output_node_names=final_result ^
tf_files/quantized_graph.pb ^
tf_files/web
7. 转成PB文件到json文件
git clone git@github.com:tensorflow/tfjs.git
cd tfjs/tfjs-converter
yarn
cross-env ts-node tools/pb2json_converter.ts ^
/绝对路径/tensorflow-for-poets-2/tf_files/web/ ^
/绝对路径/tensorflow-for-poets-2/tf_files/web_model/ ^
到这里,全部步骤已经完成了。我也使用刚才的tfjs-converter转换之后的
model.json写了一个示例: https://allan5.com/FE-AI/flower.html
和使用成熟模型最大的不同是,需要自己处理传递给模型的图像参数。
//初始输入信息
const image = tf.browser.fromPixels(pic);
//把初始化为224x224的大小
const resized_image =tf.image.resizeBilinear(image, [224,224]).toFloat();
//把向量转换为0~1的数值
const offset = tf.scalar(255.0);
const normalized = tf.scalar(1.0).sub(resized_image.div(offset));
//把输入的数据转换为[0,224,224,3]的标准格式
const batchedImage = normalized.expandDims(0);
const result = await model.predict(batchedImage).data();
//根据评分排序结果
let text = label.map((label, index) => ({ label, score: result[index] })).sort((a,b)=>b.score - a.score)
因为篇幅的关系,就不仔细拆解目标识别(带物体具体的坐标信息的预测)的训练步骤了,如果有兴趣,可以试着看下面这个项目:
到这里,有同学可能要问:为什么你一个小前端要选择python而不是熟悉的nodejs或者浏览器中的js来训练模型呢?
在我看来语言只是一种实现需求的手段,而前端跟其他职位只是面对的业务需求不同,选择的语言不同而已。毕竟大道至简,语言相通。
而现阶段如果要深入机器学习,python有自己得天独厚的优势,比如社区丰富、有大规模训练的解决方案、图像处理和数学计算等nodejs或js不能替代的模块。所以本文中的一些示例用了python语言。
不过tf.js现在也在飞速发展,tensorflow官方除了开源社区,也投入了数个全职人力开发。相信不久的将来,tf.js除了适合前端应用以外,对训练、部署这些周边支撑也会有高效的解决方案!
结语:
- 四种应用方案各有利弊,具体选用哪种,就要case by case来评估了。
- 随着前端算力的逐渐进化,会有更多成熟的模型和算法移植到前端的领域,比如tensorflow的facemesh模型已经在内部审核当中,预计今年底明年初就可以使用了。到时会有更细致的面部会识别出更细致的网状结构,前端可以自己做更加深入的交互了。
- 模型的加载是一个问题,像目标识别模型分类多一些的有超过20M大小。现阶段如果应用比较复杂的预测,还是比较适合在资源预载的场景(线下、打包到移动APP、桌面端软件)使用。但是未来5G的发展,可能会逐渐弱化这个劣势。
但是这些都是客观原因,如何用现在的技术和自己本身的领域结合,做出更多花样,才是前端同胞们需要一直思考的地方。