使用 TensorFlow.js 在 Node.js 中进行机器学习
TensorFlow.js是广受欢迎的开源库的新版本,它将深度学习引入 JavaScript。开发者现在可以使用高级库 API定义、训练和运行机器学习模型。
预先训练的模型意味着开发人员现在只需几行 JavaScript即可轻松执行复杂的任务,如视觉识别、生成音乐或检测人体姿势。
TensorFlow.js 最初是 Web 浏览器的前端库,最近的更新增加了对 Node.js 的实验性支持。这使得 TensorFlow.js 可以在后端 JavaScript 应用程序中使用,而无需使用 Python。
阅读有关该库的信息后,我想通过一个简单的任务来测试它... 🧐
使用 TensorFlow.js 通过 Node.js 中的 JavaScript 对图像进行视觉识别
遗憾的是,大部分文档和示例代码都是在浏览器中使用该库的。项目提供的用于简化加载和使用预训练模型的实用程序尚未扩展 Node.js 支持。为了实现这一点,我花了很多时间阅读该库的 Typescript 源文件。👎
不过,经过几天的折腾,我终于完成了!太棒了!🤩
在深入研究代码之前,让我们先概述一下不同的 TensorFlow 库。
TensorFlow
TensorFlow是一个用于机器学习应用的开源软件库。TensorFlow 可用于实现神经网络和其他深度学习算法。
TensorFlow 由 Google 于 2015 年 11 月发布,最初是一个Python 库。它使用基于 CPU 或 GPU 的计算来训练和评估机器学习模型。该库最初设计用于在配备昂贵 GPU 的高性能服务器上运行。
最近的更新扩展了该软件在移动设备和网络浏览器等资源受限的环境中运行的功能。
TensorFlow Lite
Tensorflow Lite是适用于移动和嵌入式设备的轻量级库版本,于 2017 年 5 月发布。同时发布的还有一系列用于视觉识别任务的预训练深度学习模型,名为MobileNet。MobileNet 模型旨在在移动设备等资源受限的环境中高效工作。
TensorFlow.js
继 Tensorflow Lite 之后,TensorFlow.js于 2018 年 3 月发布。该库版本旨在在浏览器中运行,基于早期项目deeplearn.js构建。WebGL 提供对该库的 GPU 访问。开发者使用 JavaScript API 来训练、加载和运行模型。
TensorFlow.js 最近扩展为在 Node.js 上运行,使用了名为的扩展库tfjs-node
。
Node.js 扩展是一个 alpha 版本,仍在积极开发中。
将现有模型导入 TensorFlow.js
现有的 TensorFlow 和 Keras 模型可以使用 TensorFlow.js 库执行。执行前,模型需要使用此工具转换为新格式。Github上提供了用于图像分类、姿态检测和 K 最近邻的预训练和转换模型。
在 Node.js 中使用 TensorFlow.js
安装 TensorFlow 库
@tensorflow/tfjs
-核心 TensorFlow.js 库@tensorflow/tfjs-node
-TensorFlow.js Node.js扩展@tensorflow/tfjs-node-gpu
- TensorFlow.js Node.js 扩展,支持 GPU
npm install @tensorflow/tfjs @tensorflow/tfjs-node
// or...
npm install @tensorflow/tfjs @tensorflow/tfjs-node-gpu
这两个 Node.js 扩展都使用本机依赖项,这些依赖项将根据需要进行编译。
加载 TensorFlow 库
TensorFlow 的JavaScript API从核心库中公开。用于启用 Node.js 支持的扩展模块不会公开额外的 API。
const tf = require('@tensorflow/tfjs')
// Load the binding (CPU computation)
require('@tensorflow/tfjs-node')
// Or load the binding (GPU computation)
require('@tensorflow/tfjs-node-gpu')
加载 TensorFlow 模型
TensorFlow.js 提供了一个NPM 库( ),以便于加载用于图像分类、姿势检测和k 最近邻的tfjs-models
预训练和转换模型。
用于图像分类的MobileNet 模型是一个经过训练可以识别 1000 个不同类别的深度神经网络。
在项目的README中,使用以下示例代码来加载模型。
import * as mobilenet from '@tensorflow-models/mobilenet';
// Load the model.
const model = await mobilenet.load();
我遇到的第一个挑战是这在 Node.js 上不起作用。
Error: browserHTTPRequest is not supported outside the web browser.
查看源代码,该mobilenet
库是对底层类的包装tf.Model
。当load()
调用该方法时,它会自动从外部 HTTP 地址下载正确的模型文件,并实例化 TensorFlow 模型。
Node.js 扩展尚不支持通过 HTTP 请求动态检索模型。因此,必须手动从文件系统加载模型。
在阅读了该库的源代码后,我设法创建了一个解决方法......
从文件系统加载模型
load
如果类是手动创建的,则无需调用模块的方法,而是可以使用本地文件系统路径覆盖包含模型 HTTP 地址的MobileNet
自动生成变量。完成此操作后,在类实例上调用该方法将触发文件系统加载器类,而不是尝试使用基于浏览器的 HTTP 加载器。path
load
const path = "mobilenet/model.json"
const mn = new mobilenet.MobileNet(1, 1);
mn.path = `file://${path}`
await mn.load()
太棒了,它有效!
但是模型文件从何而来?
MobileNet 模型
TensorFlow.js 的模型包含两种文件类型:以 JSON 格式存储的模型配置文件和二进制格式的模型权重。为了便于浏览器缓存,模型权重通常会被分片到多个文件中。
查看MobileNet 模型的自动加载代码,模型配置和权重分片是从此地址的公共存储桶中检索的。
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v${version}_${alpha}_${size}/
URL 中的模板参数指的是此处列出的模型版本。该页面上还显示了每个版本的分类准确率结果。
根据源代码,只能使用该库加载 MobileNet v1 模型tensorflow-models/mobilenet
。
HTTP 检索代码model.json
从此位置加载文件,然后递归获取所有引用的模型权重分片。这些文件的格式为groupX-shard1of1
。
手动下载模型
通过检索模型配置文件、解析引用的权重文件并手动下载每个权重文件,可以将所有模型文件保存到文件系统。
我想使用 alpha 值为 1.0 且图像大小为 224 像素的 MobileNet V1 模块。这为我提供了以下模型配置文件的URL 。
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/model.json
一旦该文件被下载到本地,我就可以使用该jq
工具解析所有权重文件名。
$ cat model.json | jq -r ".weightsManifest[].paths[0]"
group1-shard1of1
group2-shard1of1
group3-shard1of1
...
使用该sed
工具,我可以在这些名称前加上 HTTP URL 前缀来为每个权重文件生成 URL。
$ cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//'
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group1-shard1of1
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group2-shard1of1
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group3-shard1of1
...
使用parallel
和curl
命令,我可以将所有这些文件下载到我的本地目录。
cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' | parallel curl -O
图像分类
此示例代码由 TensorFlow.js 提供,用于演示如何返回图像的分类。
const img = document.getElementById('img');
// Classify the image.
const predictions = await model.classify(img);
由于缺少 DOM,这在 Node.js 上不起作用。
该classify
方法接受多个 DOM 元素(canvas
、video
、image
),并将自动从这些元素中检索图像字节并将其转换为类tf.Tensor3D
,用作模型的输入。或者,也tf.Tensor3D
可以直接传递输入。
我发现,与尝试使用外部包来模拟 Node.js 中的 DOM 元素相比,手动构建更容易tf.Tensor3D
。
从图像生成 Tensor3D
阅读将 DOM 元素转换为 Tensor3D 类的方法的源代码,以下输入参数用于生成 Tensor3D 类。
const values = new Int32Array(image.height * image.width * numChannels);
// fill pixels with pixel channel bytes from image
const outShape = [image.height, image.width, numChannels];
const input = tf.tensor3d(values, outShape, 'int32');
pixels
是一个二维数组(Int32Array),其中包含每个像素的通道值顺序列表。numChannels
是每个像素的通道值数量。
为 JPEG 创建输入值
该jpeg-js
库是一个纯 JavaScript 的 JPEG 编码器和解码器,适用于 Node.js。使用该库可以提取每个像素的 RGB 值。
const pixels = jpeg.decode(buffer, true);
这将返回一个包含每个像素 ( ) 的Uint8Array
四个通道值 ( ) 的数组。MobileNet 模型仅使用三个颜色通道 ( ) 进行分类,忽略了 Alpha 通道。此代码将四通道数组转换为正确的三通道版本。RGBA
width * height
RGB
const numChannels = 3;
const numPixels = image.width * image.height;
const values = new Int32Array(numPixels * numChannels);
for (let i = 0; i < numPixels; i++) {
for (let channel = 0; channel < numChannels; ++channel) {
values[i * numChannels + channel] = pixels[i * 4 + channel];
}
}
MobileNet 模型输入要求
所使用的MobileNet 模型用于对宽高均为 224 像素的图像进行分类。输入张量必须包含介于 -1 和 1 之间的浮点值,用于三个通道的像素值。
不同尺寸图像的输入值在分类之前需要重新调整大小。此外,JPEG 解码器的像素值范围是0 - 255,而不是-1 到 1。这些值在分类之前也需要转换。
TensorFlow.js 提供了库方法来简化这个过程,但幸运的是,tfjs-models/mobilenet
库会自动处理这个问题! 👍
开发者可以将 Tensor3D 类型和不同维度的输入传递int32
给该classify
方法,它会在分类之前将输入转换为正确的格式。这意味着无需执行任何操作……太棒了🕺🕺🕺。
获取预测
Tensorflow 中的 MobileNet 模型经过训练,可以识别ImageNet数据集中前 1000 个类别的实体。这些模型输出每个实体出现在待分类图像中的概率。
所用模型的训练类别的完整列表可在此文件中找到。
该tfjs-models/mobilenet
库公开了一个classify
类方法MobileNet
,用于从图像输入中返回概率最高的前 X 个类。
const predictions = await mn_model.classify(input, 10);
predictions
是以下格式的 X 类和概率的数组。
{
className: 'panda',
probability: 0.9993536472320557
}
例子
在研究了如何在 Node.js 上使用 TensorFlow.js 库和 MobileNet 模型之后,该脚本将对作为命令行参数给出的图像进行分类。
源代码
- 将此脚本文件和包描述符保存到本地文件。
测试一下
mobilenet
按照上述说明将模型文件下载到目录中。- 使用 NPM 安装项目依赖项
npm install
- 下载示例 JPEG 文件进行分类
wget http://bit.ly/2JYSal9 -O panda.jpg
- 使用模型文件和输入图像作为参数运行脚本。
node script.js mobilenet/model.json panda.jpg
如果一切正常,则应在控制台上打印以下输出。
classification results: [ {
className: 'giant panda, panda, panda bear, coon bear',
probability: 0.9993536472320557
} ]
该图像被正确分类为包含熊猫,概率高达 99.93%!🐼🐼🐼
结论
TensorFlow.js 为 JavaScript 开发者带来了深度学习的强大功能。结合使用 TensorFlow.js 库中的预训练模型,可以轻松扩展 JavaScript 应用程序,使其能够执行复杂的机器学习任务,并且只需极少的精力和代码。
TensorFlow.js 最初是基于浏览器的库,现在已扩展至 Node.js,但并非所有工具和实用程序都支持新的运行时。经过几天的调试,我终于能够将该库与 MobileNet 模型结合使用,对本地文件中的图像进行视觉识别。
在 Node.js 运行时中运行它意味着我现在可以开始我的下一个想法了……让它在无服务器函数中运行!欢迎回来阅读我接下来的 TensorFlow.js 冒险之旅。👋
文章来源:https://dev.to/ibmdeveloper/machine-learning-in-nodejs-with-tensorflowjs-1g1p