如何基于 ES6 的 JavaScript 进行 TensorFlow.js 的开发

tensorflow.js 是 tensorflow 的 javascript 版本,支持 gpu 硬件加速,可以运行在 node.js 或浏览器环境中。它不但支持完全基于 javascript 从头开发、训练和部署模型,也可以用来运行已有的 python 版 tensorflow 模型,或者基于现有的模型进行继续训练。
tensorflow.js 支持 gpu 硬件加速。在 node.js 环境中,如果有 cuda 环境支持,或者在浏览器环境中,有 webgl 环境支持,那么 tensorflow.js 可以使用硬件进行加速。
微信小程序
微信小程序也提供了官方插件,封装了 tensorflow.js 库,利用小程序 webgl api 给第三方小程序调用时提供 gpu 加速。
本章,我们将基于 tensorflow.js 1.0,向大家简单地介绍如何基于 es6 的 javascript 进行 tensorflow.js 的开发,然后提供两个例子,并基于例子进行详细的讲解和介绍,最终实现使用纯 javascript 进行 tensorflow 模型的开发、训练和部署。
章节代码地址
本章中提到的 javascript 版 tensorflow 的相关代码,使用说明,和训练好的模型文件及参数,都可以在作者的 github 上找到。
地址:https://github.com/huan/tensorflow-handbook-javascript
浏览器中使用 tensorflow.js 的优势
tensorflow.js 可以让我们直接在浏览器中加载 tensorflow,让用户立即通过本地的 cpu/gpu 资源进行我们所需要的机器学习运算,更灵活地进行 ai 应用的开发。
浏览器中进行机器学习,相对比与服务器端来讲,将拥有以下四大优势:
不需要安装软件或驱动(打开浏览器即可使用);
可以通过浏览器进行更加方便的人机交互;
可以通过手机浏览器,调用手机硬件的各种传感器(如:gps、电子罗盘、加速度传感器、摄像头等);
用户的数据可以无需上传到服务器,在本地即可完成所需操作。
通过这些优势,tensorflow.js 将给开发者带来极高的灵活性。比如在 google creative lab 在 2018 年 7 月发布的 move mirror 里,我们可以在手机上打开浏览器,通过手机摄像头检测视频中用户的身体动作姿势,然后通过对图片数据库中类似身体动作姿势的检索,给用户显示一个最能够和他当前动作相似的照片。在 move mirror 的运行过程中,数据没有上传到服务器,所有的运算都是在手机本地,基于手机的 cpu/gpu 完成的,而这项技术,将使 servreless 与 ai 应用结合起来成为可能。
move mirror
https://experiments.withgoogle.com/move-mirror
move mirror 所使用的 posenet
https://github.com/tensorflow/tfjs-models/tree/master/posenet
tensorflow.js 环境配置
在浏览器中使用 tensorflow.js
在浏览器中加载 tensorflow.js ,最方便的办法是在 html 中直接引用 tensorflow.js 发布的 npm 包中已经打包安装好的 javascript 代码。
在 node.js 中使用 tensorflow.js
服务器端使用 javascript ,首先需要按照nodejs.org官网的说明,完成安装最新版本的 node.js 。
然后,完成以下四个步骤即可完成配置:
1. 确认 node.js 版本(v10 或更新的版本):
$ node --verion v10.5.0 $ npm --version 6.4.1
2. 建立 tensorflow.js 项目目录:
$ mkdir tfjs $ cd tfjs
3. 安装 tensorflow.js:
# 初始化项目管理文件 package.json $ npm init -y # 安装 tfjs 库,纯 javascript 版本 $ npm install @tensorflow/tfjs # 安装 tfjs-node 库,c binding 版本 $ npm install @tensorflow/tfjs-node # 安装 tfjs-node-gpu 库,支持 cuda gpu 加速 $ npm install @tensorflow/tfjs-node-gpu
4. 确认 node.js 和 tensorflow.js 工作正常:
$ node > require('@tensorflow/tfjs').version { 'tfjs-core': '1.3.1', 'tfjs-data': '1.3.1', 'tfjs-layers': '1.3.1', 'tfjs-converter': '1.3.1', tfjs: '1.3.1' } >
如果你看到了上面的 tfjs-core, tfjs-data, tfjs-layers 和 tfjs-converter 的输出信息,那么就说明环境配置没有问题了。
然后,在 javascript 程序中,通过以下指令,即可引入 tensorflow.js:
import * as tf from '@tensorflow/tfjs' console.log(tf.version.tfjs) //output: 1.3.1
使用import加载 javascript 模块
import 是 javascript es6 版本新开始拥有的新特性。粗略可以认为等价于 require。比如:import * as tf from '@tensorflow/tfjs'和 const tf = require('@tensorflow/tfjs')对上面的示例代码是等价的。希望了解更多的读者,可以访问mdn 文档(https://developer.mozilla.org/en-us/docs/web/javascript/reference/statements/import)。
在微信小程序中使用 tensorflow.js
tensorflow.js 微信小程序插件封装了 tensorflow.js 库,用于提供给第三方小程序调用。
在使用插件前,首先要在小程序管理后台的 “设置 - 第三方服务 - 插件管理” 中添加插件。开发者可登录小程序管理后台,通过 appid _wx6afed118d9e81df9_ 查找插件并添加。本插件无需申请,添加后可直接使用。
例子:tfjs mobilenet:物体识别小程序
https://github.com/tensorflow/tfjs-wechat/tree/master/demo/mobilenet
tensorflow.js 微信小程序官方文档地址
https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx6afed118d9e81df9
tensorflow.js 微信小程序教程
为了推动微信小程序中人工智能应用的发展,google 专门为微信小程序打造了最新 tensorflow.js 插件,并联合 google 认证机器学习专家、微信、腾讯课堂 next 学院,联合推出了 “next 学院:tensorflow.js 遇到小程序” 课程,帮助小程序开发者带来更加易于上手和流畅的 tensorflow.js 开发体验。
上述课程主要介绍了如何将 tensorflow.js 插件嵌入到微信小程序中,并基于其进行开发。课程中以一个姿态检测的模型 posenet 作为案例,介绍了 tensorflow.js 插件导入到微信小程序开发工具中后,在项目开发中的配置,功能调用,加载模型等方法应用;此外,还介绍了在 python 环境下训练好的模型如何转换并载入到小程序中。
本章作者也参与了课程制作,课程中的案列简单有趣易上手,通过学习,可以快速熟悉 tensorflow.js 在小程序中的开发和应用。有兴趣的读者可以前往 next 学院,进行后续深度学习。
课程地址
https://ke.qq.com/course/428263
tensorflow.js 模型部署
在浏览器中加载 python 模型
一般 tensorflow 的模型,会被存储为 savedmodel 格式。这也是 google 目前推荐的模型保存最佳实践。savedmodel 格式可以通过 tensorflowjs-converter 转换器转换为可以直接被 tensorflow.js 加载的格式,从而在 javascript 语言中进行使用。
1. 安装tensorflowjs_converter
$ pip install tensorflowjs
tensorflowjs_converter的使用细节,可以通过--help参数查看程序帮助:
$ tensorflowjs_converter --help
2. 以下我们以 mobilenetv1 为例,看一下如何对模型文件进行转换操作,并将可以被 tensorflow.js 加载的模型文件,存放到/mobilenet/tfjs_model 目录下。
转换 savedmodel:将/mobilenet/saved_model 转换到/mobilenet/tfjs_model
tensorflowjs_converter --input_format=tf_saved_model --output_node_names='mobilenetv1/predictions/reshape_1' --saved_model_tags=serve /mobilenet/saved_model /mobilenet/tfjs_model
转换完成的模型,保存为了两类文件:
model.json:模型架构
group1-shard*of*:模型参数
举例来说,我们对 mobilenet v2 转换出来的文件,如下:
/mobilenet/tfjs_model/model.json /mobilenet/tfjs_model/group1-shard1of5 … /mobilenet/tfjs_model/group1-shard5of5
3. 为了加载转换完成的模型文件,我们需要安装tfjs-converter和@tensorflow/tfjs模块:
$ npm install @tensorflow/tfjs
4. 然后,我们就可以通过 javascript 来加载 tensorflow 模型了!
import * as tf from '@tensorflow/tfjs' const model_url = '/mobilenet/tfjs_model/model.json' const model = await tf.loadgraphmodel(model_url) const cat = document.getelementbyid('cat') model.execute(tf.browser.frompixels(cat))
转换 tfhub 模型
将 tfhub 模型https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1转换到/mobilenet/tfjs_model:
tensorflowjs_converter --input_format=tf_hub 'https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1' /mobilenet/tfjs_model
在 node.js 中执行原生 savedmodel 模型
除了通过转换工具 tfjs-converter 将 tensorflow savedmodel、tfhub 模型或 keras 模型转换为 javascript 浏览器兼容格式之外,如果我们在 node.js 环境中运行,那么还可以使用 tensorflow c++ 的接口,直接运行原生的 savedmodel 模型。
在 tensorflow.js 中运行原生的 savedmodel 模型非常简单。我们只需要把预训练的 tensorflow 模型存为 savedmodel 格式,并通过@tensorflow/tfjs-node 或 tfjs-node-gpu 包将模型加载到 node.js 进行推理即可,无需使用转换工具 tfjs-converter。
预训练的 tensorflow savedmodel 可以通过一行代码在 javascript 中加载模型并用于推理:
const model = await tf.node.loadsavedmodel(path) const output = model.predict(input)
也可以将多个输入以数组或图的形式提供给模型:
const model1 = await tf.node.loadsavedmodel(path1, [tag], signaturekey) const outputarray = model1.predict([inputtensor1, inputtensor2]) const model2 = await tf.node.loadsavedmodel(path2, [tag], signaturekey) const outputmap = model2.predict({input1: inputtensor1, input2:inputtensor2})
此功能需要@tensorflow/tfjs-node 版本为 1.3.2 或更高,同时支持 cpu 和 gpu。它支持在 tensorflow python 1.x 和 2.0 版本中训练和导出的 tensorflow savedmodel。由此带来的好处除了无需进行任何转换,原生执行 tensorflow savedmodel 意味着您可以在模型中使用 tensorflow.js 尚未支持的算子。这要通过将 savedmodel 作为 tensorflow 会话加载到 c++ 中进行绑定予以实现。
使用 tensorflow.js 模型库
tensorflow.js 提供了一系列预训练好的模型,方便大家快速地给自己的程序引入人工智能能力。
模型库中模型分类包括图像识别、语音识别、人体姿态识别、物体识别、文字分类等。
模型库 github 地址
https://github.com/tensorflow/tfjs-models
由于这些 api 默认模型文件都存储在谷歌云上,直接使用会导致中国用户无法直接读取。在程序内使用模型 api 时要提供 modelurl 的参数,可以指向谷歌中国的镜像服务器。
谷歌云的 base url 是https://storage.googleapis.com,中国镜像的 base url 是https://www.gstaticcnapps.cn,模型的 url path 是一致的。以 posenet 模型为例:
谷歌云地址
https://storage.googleapis.com/tfjs-models/savedmodel/posenet/mobilenet/float/050/model-stride16.json
中国镜像地址
https://www.gstaticcnapps.cn/tfjs-models/savedmodel/posenet/mobilenet/float/050/model-stride16.json
在浏览器中使用 mobilenet 进行摄像头物体识别
这里我们将通过一个简单的 html 页面,来调用 tensorflow.js 和与训练好的 mobilenet ,在用户的浏览器中,通过摄像头来识别图像中的物体是什么。
1. 我们建立一个 html 文件,在头信息中,通过将 npm 模块转换为在线可以引用的免费服务 unpkg.com,来加载@tensorflow/tfjs 和@tensorflow-models/mobilenet 两个 tfjs 模块:
2. 我们声明三个 html 元素:用来显示视频的,用来显示我们截取特定帧的,和用来显示检测文字结果的:
3. 我们通过 javascript ,将对应的 html 元素进行初始化:video, image, status 三个变量分别用来对应, , 三个 html 元素,canvas 和 ctx 用来做从摄像头获取视频流数据的中转存储。model 将用来存储我们从网络上加载的 mobilenet:
const video = document.queryselector('video') const image = document.queryselector('img') const status = document.queryselector(p) const canvas = document.createelement('canvas') const ctx = canvas.getcontext('2d') let model
4. main()用来初始化整个系统,完成加载 mobilenet 模型,将用户摄像头的数据绑定这个 html 元素上,最后触发 refresh()函数,进行定期刷新操作:
async function main () { status.innertext = model loading... model = await mobilenet.load() status.innertext = model is loaded! const stream = await navigator.mediadevices.getusermedia({ video: true }) video.srcobject = stream await video.play() canvas.width = video.videowidth canvas.height = video.videoheight refresh() }
5. refresh()函数,用来从视频中取出当前一帧图像,然后通过 mobilenet 模型进行分类,并将分类结果,显示在网页上。然后,通过 settimeout,重复执行自己,实现持续对视频图像进行处理的功能:
async function refresh(){ ctx.drawimage(video, 0,0) image.src = canvas.todataurl('image/png') await model.load() const predictions = await model.classify(image) const classname = predictions[0].classname const percentage = math.floor(100 * predictions[0].probability) status.innerhtml = percentage + '%' + ' ' + classname settimeout(refresh, 100) }
整体功能,只需要一个文件,几十行 html/javascript 即可实现。可以直接在浏览器中运行,完整的 html 代码如下:
运行效果截图如下。可以看到,水杯被系统识别为了 “beer glass” 啤酒杯,置信度 90% :
tensorflow.js 模型训练 *
与 tensorflow serving 和 tensorflow lite 不同,tensorflow.js 不仅支持模型的部署和推断,还支持直接在 tensorflow.js 中进行模型训练。
在 tensorflow 基础章节中,我们已经用 python 实现过,针对某城市在 2013-2017 年的房价的任务,通过对该数据进行线性回归,即使用线性模型 y=ax+b 来拟合上述数据,此处 a 和 b 是待求的参数。
下面我们改用 tensorflow.js 来实现一个 javascript 版本。
首先,我们定义数据,进行基本的归一化操作。
const xsraw = tf.tensor([2013, 2014, 2015, 2016, 2017]) const ysraw = tf.tensor([12000, 14000, 15000, 16500, 17500]) // 归一化 const xs = xsraw.sub(xsraw.min()) .div(xsraw.max().sub(xsraw.min())) const ys = ysraw.sub(ysraw.min()) .div(ysraw.max().sub(ysraw.min()))
接下来,我们来求线性模型中两个参数 a和 b的值。
使用 loss()计算损失;使用 optimizer.minimize()自动更新模型参数。
javascript 中的胖箭头函数 (fat arrow function)
从 javascript 的 es6 版本开始,允许使用箭头函数(=>)来简化函数的声明和书写,类似于 python 中的 lambda 表达式。例如,以下箭头函数:
const sum = (a, b) => { return a + b }
在效果上等价为如下的传统函数:
const sum = function (a, b) { return a + b }
不过箭头函数中没有自己的 this 和 arguments,不可以被当做构造函数 (new),也不可以被当做 generator (无法使用 yield)。感兴趣的读者可以参考mdn 文档 以了解更多。
mcn 文档:https://developer.mozilla.org/en-us/docs/web/javascript/reference/functions/arrow_functions
tensorflow.js 中的datasync()系列数据同步函数
它的作用是把 tensor 数据从 gpu 中取回来,可以理解为与 python 中的.numpy()功能相当,即将数据取回,供本地显示,或本地计算使用。感兴趣的读者可以参考tensorflow.js 文档 以了解更多。
tensorflow.js 文档:https://js.tensorflow.org/api/latest/#tf.tensor.datasync
tensorflow.js 中的sub()系列数学计算函数
tensorflow.js 支持tf.sub(a, b)和a.sub(b)两种方法的数学函数调用。其效果是等价的,读者可以根据自己的喜好来选择。感兴趣的读者可以参考tensorflow.js 文档 (https://js.tensorflow.org/api/latest/#sub)以了解更多。
const a = tf.scalar(math.random()).variable() const b = tf.scalar(math.random()).variable() // y = a * x + b. const f = (x) => a.mul(x).add(b) const loss = (pred, label) => pred.sub(label).square().mean() const learningrate = 1e-3 const optimizer = tf.train.sgd(learningrate) // 训练模型 for (let i = 0; i loss(f(xs), ys)) } // 预测 console.log(`a: ${a.datasync()}, b: ${b.datasync()}`) const preds = f(xs).datasync() const trues = ys.arraysync() preds.foreach((pred, i) => { console.log(`x: ${i}, pred: ${pred.tofixed(2)}, true: ${trues[i].tofixed(2)}`) })
从下面的输出样例中我们可以看到,已经拟合得比较接近了。
a: 0.9339302778244019, b: 0.08108722418546677 x: 0, pred: 0.08, true: 0.00 x: 1, pred: 0.31, true: 0.36 x: 2, pred: 0.55, true: 0.55 x: 3, pred: 0.78, true: 0.82 x: 4, pred: 1.02, true: 1.00
可以直接在浏览器中运行,完整的 html 代码如下:
tensorflow.js 性能对比
关于 tensorflow.js 的性能,google 官方做了一份基于 mobilenet 的评测,可以作为参考。具体评测是基于 mobilenet 的 tensorflow 模型,将其 javascript 版本和 python 版本各运行两百次,其评测结论如下。
手机浏览器性能:(单位:毫秒 ms)
tensorflow.js 在手机浏览器中运行一次推理:
在 iphonex 上需要时间为 22ms
在 pixel3 上需要时间为 100ms
与 tensorflow lite 代码基准相比,手机浏览器中的 tensorflow.js 在 iphonex 上的运行时间为基准的 1.2 倍,在 pixel3 上运行的时间为基准的 1.8 倍。
台式机浏览器性能:(单位:毫秒 ms)
在浏览器中,tensorflow.js 可以使用 webgl 进行硬件加速,将 gpu 资源使用起来。
tensorflow.js 在浏览器中运行一次推理:
在 cpu 上需要时间为 97ms
在 gpu (webgl) 上需要时间为 10ms
与 python 代码基准相比,浏览器中的 tensorflow.js 在 cpu 上的运行时间为基准的 1.7 倍,在 gpu (webgl) 上运行的时间为基准的 3.8 倍。
node.js 性能:
在 node.js 中,tensorflow.js 可以用 javascript 加载转换后模型,或使用 tensorflow 的 c++ binding ,分别接近和超越了 python 的性能。
tensorflow.js 在 node.js 运行一次推理:
在 cpu 上运行原生模型时间为 19.6ms
在 gpu (cuda) 上运行原生模型时间为 7.68ms
与 python 代码基准相比,node.js 的 tensorflow.js 在 cpu 和 gpu 上的运行时间都比基准快 4% 。

原文标题:【抽奖送书】简单粗暴 tensorflow.js:从安装到训练全程实例教学
文章出处:【微信公众号:tensorflow】欢迎添加关注!文章转载请注明出处。

realme Buds Air真无线耳机将于2020年1月7日正式发布
新型的送货机器人怎样才能工作好
Cuk 拓扑电源原理及工作过程解析
.NET8性能优化之线程
前瞻6G趋势 三大运营商扬帆创新征途
如何基于 ES6 的 JavaScript 进行 TensorFlow.js 的开发
日本研究人员开发出一个由LED芯片构成的可植入式装置,可有效地治疗肿瘤
加速传感器ADXL150特性及其精度影响因素
可编程语音芯片IVR1061应用电路图
时刻继电器的类型与构造原理简析
浪漫经济正在成为拉动GDP的一股新生力量
基于空闲检测机制的电力集中抄表系统设计
智能油井在线监控解决方案,第一时间掌握所有动态
区块链正在缓慢的主导世界经济
智慧交通未来有哪一些机遇
英特尔推出基于FPGA的全新可编程加速卡
三星拟投59亿美元到LCD显示产品线
火酷震机械键盘拆解评测 逼格很高拆解方便
2020年28nm需求复苏时间或延后 对晶圆代工厂商的依赖度将提升
Lexar雷克沙 633x MicroSD从容应对“宅”时光