Press "Enter" to skip to content

使用TensorFlow.js在Node.js中进行机器学习

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

TensorFlow.js是流行开源库的新版本,它为JavaScript带来了深度学习。 开发人员现在可以使用高级库API来定义,训练和运行机器学习模型。

 

开发人员利用预训练的模型,仅用几行JavaScript即可轻松执行复杂的任务,例如视觉识别,生成音乐或检测人体姿势。

 

从Web浏览器的前端库开始,最近的更新增加了对Node.js的实验性支持。 这使得TensorFlow.js可以在后端JavaScript应用程序中使用,而不必使用Python。

 

阅读有关该库的信息,我想通过一个简单的任务对其进行测试…

 

使用TensorFlow.js通过Node.js进行图像识别

 

不幸的是,大多数文档和示例代码都是使用浏览器中的库。 Node.js尚未扩展用于简化加载和使用预训练模型的项目程序。 完成这项工作的确使我花了很多时间阅读该库的Typescript源文件。 :-1:

 

但是,经过几天的夜以继日的学习,我完成了! 欢呼!

 

在深入研究代码之前,让我们先概述一下不同的TensorFlow库。

 

TensorFlow

 

TensorFlow 是一个用于机器学习应用程序的开源软件库。 TensorFlow 可用于实现神经网络和其他深度学习算法。

 

TensorFlow 于2015年11月由 Google 发布,最初是一个 Python 库。 它使用基于CPU或GPU的计算来训练和评估机器学习模型。 该库最初旨在在具有昂贵GPU的高性能服务器上运行。

 

最近的更新已将软件扩展到如移动设备和Web浏览器环境中运行。

 

TensorFlow Lite

 

Tensorflow Lite 是移动和嵌入式设备库的轻量级版本,于2017年5月发布。该版本随附了一系列针对视觉识别任务的全新预训练深度学习模型,称为 MobileNetMobileNet 模型旨在在资源受限的环境(例如移动设备)中高效运行。

 

 

Tensorflow Lite 之后, TensorFlow.js 于2018年3月发布。该版本的库旨在在浏览器中运行,建立在一个名为 deeplearn.js 的早期项目上。 WebGL提供对库的GPU访问。 开发人员使用 JavaScript API 训练,加载和运行模型。

 

TensorFlow.js 最近通过 tfjs-node 的扩展库在 上运行。

 

Node.js扩展是一个 Alpha 版本,仍处于积极开发中

 

将已有模型引入Tensorflow.js

 

可以使用 TensorFlow.js 库执行现有的 TensorFlowKeras 。 模型需要在执行之前使用此工具转换为新格式。 Github提供了用于图像分类,姿势检测和k近邻的预训练和转换模型。

 

在nodejs中使用tensorflow.js

 

安装tensorflow库

 

TensorFlow.jsNPM 库中进行安装.

 

@tensorflow/tfjs核心TensorFlow.js包

 

@tensorflow/tfjs-nodeTensorFlow.js的Node.js 扩展

 

@tensorflow/tfjs-node-gpuTensorFlow.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
...

 

然后,使用 parallelcurl 命令,可以将所有这些文件下载到本地目录中。

 

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)的 Uint8ArrayMobileNet 模型仅使用三个颜色通道(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 库可以自动处理此问题! :+1:

 

开发人员可以将 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%的熊猫! :panda_face::panda_face::panda_face:

 

结论

 

TensorFlow.jsJavaScript 开发人员带来了深度学习的力量。 在 TensorFlow.js 库中使用经过预训练的模型,可以轻松地以最少的工作量和代码来扩展具有复杂机器学习任务的 JavaScript 应用程序。

 

TensorFlow.js 已作为基于浏览器的库发布,现已扩展为可在 Node.js 上运行,尽管并非所有工具和实用程序都支持新的运行时。 经过几天的研究,我可以将库与 MobileNet 模型一起使用,以便对本地文件中的图像进行视觉识别。

 

让它在 Node.js 运行时中运行意味着我现在继续下一步…使它在无服务器功能内运行! 很快回来阅读有关 TensorFlow.js 的下一次冒险。

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注