详情请进入 湖南阳光电子学校 已关注:人 咨询电话:0731-85579057 微信号:yp941688, yp94168
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 代码。
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 < 10000; i++) { optimizer.minimize(() => 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 运行一次推理:
.(编辑:新泰电工培训学校)