TensorFlow.js是流行开源库的新版本,它为JavaScript带来了深度学习。 开发人员现在可以使用高级库API来定义,训练和运行机器学习模型。
开发人员利用预训练的模型,仅用几行JavaScript即可轻松执行复杂的任务,例如视觉识别,生成音乐或检测人体姿势。
从Web浏览器的前端库开始,最近的更新增加了对Node.js的实验性支持。 这使得TensorFlow.js可以在后端JavaScript应用程序中使用,而不必使用Python。
阅读有关该库的信息,我想通过一个简单的任务对其进行测试...
使用TensorFlow.js通过Node.js进行图像识别
不幸的是,大多数文档和示例代码都是使用浏览器中的库。 Node.js尚未扩展用于简化加载和使用预训练模型的项目程序。 完成这项工作的确使我花了很多时间阅读该库的Typescript源文件。 👎
但是,经过几天的夜以继日的学习,我完成了! 欢呼! 🤩
在深入研究代码之前,让我们先概述一下不同的TensorFlow库。
TensorFlow
TensorFlow
是一个用于机器学习应用程序的开源软件库。 TensorFlow
可用于实现神经网络和其他深度学习算法。
TensorFlow
于2015年11月由Google
发布,最初是一个Python
库。 它使用基于CPU或GPU的计算来训练和评估机器学习模型。 该库最初旨在在具有昂贵GPU的高性能服务器上运行。
最近的更新已将软件扩展到如移动设备和Web浏览器环境中运行。
TensorFlow Lite
Tensorflow Lite
是移动和嵌入式设备库的轻量级版本,于2017年5月发布。该版本随附了一系列针对视觉识别任务的全新预训练深度学习模型,称为MobileNet
。MobileNet
模型旨在在资源受限的环境(例如移动设备)中高效运行。
TensorFlow.js
在Tensorflow Lite
之后,TensorFlow.js
于2018年3月发布。该版本的库旨在在浏览器中运行,建立在一个名为deeplearn.js
的早期项目上。 WebGL提供对库的GPU访问。 开发人员使用JavaScript API
训练,加载和运行模型。
TensorFlow.js
最近通过tfjs-node
的扩展库在Node.js
上运行。
Node.js扩展是一个Alpha
版本,仍处于积极开发中
将已有模型引入Tensorflow.js
可以使用TensorFlow.js
库执行现有的TensorFlow
和Keras
模型。 模型需要在执行之前使用此工具转换为新格式。 Github提供了用于图像分类,姿势检测和k近邻的预训练和转换模型。
在nodejs中使用tensorflow.js
安装tensorflow库
TensorFlow.js
在NPM
库中进行安装.
@tensorflow/tfjs
- 核心TensorFlow.js包
@tensorflow/tfjs-node
- TensorFlow.js的Node.js 扩展
@tensorflow/tfjs-node-gpu
- TensorFlow.js 的GPU支持的nodejs扩展
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
库(tfjs-models
),可轻松加载用于图像分类,姿势检测和k近邻的预训练和转换后的模型。
用于图像分类的MobileNet
模型是经过训练1000个不同类别的深度神经网络。
在项目的自述文件中,以下示例代码用于加载模型。
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
请求以动态检索模型。 相反,必须从文件系统手动加载模型。
阅读了库的源代码后,我设法创建了一种解决方法……
从文件系统加载模型
如果手动创建了MobileNet
类,则无需调用模块的load
方法,而是可以使用本地文件系统路径覆盖包含模型的HTTP地址的自动生成的路径变量。 完成此操作后,在类实例上调用load方法将触发文件系统加载器类,而不是尝试使用基于浏览器的HTTP
加载器。
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中的模板参数是指此处列出的模型版本。 该页面还显示了每个版本的分类准确性结果。
根据源代码,使用tensorflow-models / mobilenet
库只能加载MobileNet v1
模型。
HTTP检索代码从该位置加载model.json
文件,然后以递归方式获取所有引用的模型权重分片。 这些文件的格式为groupX-shard1of1
。
手动下载模型
通过检索模型配置文件,解析引用的权重文件并手动下载每个权重文件,可以将所有模型文件保存到文件系统中。
我想使用1.0的alpha值和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元素(画布,视频,图像),并将自动从这些元素检索图像字节并将其转换为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');
pixel
是类型为(Int32Array)
的2D数组,其中包含每个像素的通道值的顺序列表。 numChannels
是每个像素的通道值数量。
为JPEG创建输入值
jpeg-js
库是Node.js
的纯JavaScript JPEG
编码器和解码器。 使用此库,可以提取每个像素的RGB
值。
const pixel = jpeg.decode(buffer,true);
这将为每个像素(宽度*高度)返回一个具有四个通道值(RGBA)的Uint8Array
。 MobileNet
模型仅使用三个颜色通道(RGB)进行分类,而忽略了alpha
通道。 此代码将四通道数组转换为正确的三通道版本。
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
库可以自动处理此问题! 👍
开发人员可以将int32
类型和不同维度的Tensor3D
输入传递给分类方法,然后在分类之前将输入转换为正确的格式。这意味着超级🕺🕺🕺。
预测
Tensorflow
中的MobileNet
模型经过训练,可以识别ImageNet
数据集中前1000个类别中的实体。模型输出这些实体中的每个实体在被分类图像中的概率。
可以在此文件中找到正在使用的模型的训练有素的课程的完整列表。
tfjs-models / mobilenet
库在MobileNet
类上公开了一个分类方法,以从图像输入中返回概率最高的前X个类。
const predictions = await mn_model.classify(input, 10);
predictions
是X类和概率形式的数组,格式如下。
{
className: 'panda',
probability: 0.9993536472320557
}
例子
研究了如何在Node.js上
使用TensorFlow.js
库和MobileNet
模型之后,此脚本将对作为命令行参数给出的图像进行分类。
源代码 将此脚本文件和程序包描述符保存到本地文件。
//package.json
{
"name": "tf-js",
"version": "1.0.0",
"main": "script.js",
"license": "MIT",
"dependencies": {
"@tensorflow-models/mobilenet": "^0.2.2",
"@tensorflow/tfjs": "^0.12.3",
"@tensorflow/tfjs-node": "^0.1.9",
"jpeg-js": "^0.3.4"
}
}
//script.js
const tf = require('@tensorflow/tfjs')
const mobilenet = require('@tensorflow-models/mobilenet');
require('@tensorflow/tfjs-node')
const fs = require('fs');
const jpeg = require('jpeg-js');
const NUMBER_OF_CHANNELS = 3
const readImage = path => {
const buf = fs.readFileSync(path)
const pixels = jpeg.decode(buf, true)
return pixels
}
const imageByteArray = (image, numChannels) => {
const pixels = image.data
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];
}
}
return values
}
const imageToInput = (image, numChannels) => {
const values = imageByteArray(image, numChannels)
const outShape = [image.height, image.width, numChannels];
const input = tf.tensor3d(values, outShape, 'int32');
return input
}
const loadModel = async path => {
const mn = new mobilenet.MobileNet(1, 1);
mn.path = `file://${path}`
await mn.load()
return mn
}
const classify = async (model, path) => {
const image = readImage(path)
const input = imageToInput(image, NUMBER_OF_CHANNELS)
const mn_model = await loadModel(model)
const predictions = await mn_model.classify(input)
console.log('classification results:', predictions)
}
if (process.argv.length !== 4) throw new Error('incorrect arguments: node script.js <MODEL> <IMAGE_FILE>')
classify(process.argv[2], process.argv[3])
测试
-
按照上述说明将模型文件下载到
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
的下一次冒险。 👋