百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程文章 > 正文

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

qiyuwang 2024-10-31 15:51 28 浏览 0 评论

作者:jthomas

黑胡桃实验室敲制

在本文中,作者将介绍如何在Node.js环境下使用TensorFlow.js,并使用MobileNet模型来完成一个分类任务。

前言

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

TensorFlow.js可以使用预先训练的模型,这意味着开发人员现在可以通过几行JavaScript 轻松执行复杂的任务,如视觉识别生成音乐或姿态估计

TensorFlow.js作为Web浏览器的前端库,最近增加了对Node.js的支持。这允许TensorFlow.js在后端JavaScript应用程序中使用,而无需使用Python。

不幸的是,官网提供的大多数文档和示例代码都在浏览器中使用TensorFlow.js库。为了简化加载和使用预先训练的模型而提供的项目实用程序尚未添加对Node.js的支持。最后,我花了很多时间阅读库中的源代码。

经过了几天的研究,我设法完成了下面这个教程。欢呼!

① 安装TensorFlow.js的库

这里,我们可以直接使用NPM进行安装

@tensorflow/tfjs TensorFlow.js核心库@tensorflow/tfjs-node TensorFlow.js的Node.js扩展库@tensorflow/tfjs-node-gpu 支持GPU的TensorFlow.js的扩展库

npm install @tensorflow/tfjs @tensorflow/tfjs-node
// or...
npm install @tensorflow/tfjs @tensorflow/tfjs-node-gpu

Node.js扩展都使用本地依赖项,这些依赖项将会被在本地进行编译。

加载TensorFlow库

先导入TensorFlow.js的核心库,再导入Node.js的扩展库。

const tf = require('@tensorflow/tfjs')// 导入CPU版的
require('@tensorflow/tfjs-node')// 导入GPU版的
require('@tensorflow/tfjs-node-gpu')

③加载TensorFlow模型

TensorFlow.js提供了一个NPM库(tfjs-models),使用它可以轻松地加载经过转换的预训练模型,可以用于图像分类,姿态估计和KNN分类器等。

这里我们将使用用于图像分类的MobileNet模型,这个模型是经过预训练的,可以识别1000个不同类别物体的深度神经网络。

import * as mobilenet from '@tensorflow-models/mobilenet';// 导入模型.
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类,而不是调用模块的加载方法,则可以使用本地模型文件的路径来覆盖存有模型文件的HTTP地址的路径变量。完成此操作后,在实例上调用 load() 方法将触发文件系统加载器类,而不是使用基于浏览器的HTTP加载器类。

const path = "mobilenet/model.json"
const mn = new mobilenet.MobileNet(1, 1);// 这里替换成模型文件在磁盘上的路径
mn.path = `file://${path}`
await mn.load()

太棒了,它开始工作了!

但是,模型文件是来源于哪里呢?

下载模型文件

TensorFlow.js的模型由两种文件类型组成,一种是存储在JSON中的模型配置文件,另一种是二进制格式的模型权重。模型权重通常被分片为多个文件,以便浏览器更好地进行缓存。

查看 MobileNet模型的加载代码,发现模型的配置文件和权重分配都存储在公共的数据存储空间中。

https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v${version}_${alpha}_${size}/

URL中的 version 参数可以填下面的模型版本。每个版本的分类准确性结果也显示在该页面上。

在源代码中,只能使用tensorflow-models/mobilenet库加载MobileNet v1模型。

HTTP检索代码将从此URL加载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

然后我们将模型配置文件model.json保存下来,放入到jupyter中查看模型文件的结构。

从中可以看出,权重分片共有54个(图中没有显示完全),第一个权重分片叫做 group1-shard10f1 。可以通过以下URL来进行下载

https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group1-shard1of1

但是共有54个权重分片,手动下载起来很麻烦,我们准备了一个下载脚本,来自动化下载模型文件这个过程。

import urllib.request
import json
## 加载 model.js文件
with open("model.json", encoding='utf-8-sig') as json_file:
 json_data = json.load(json_file)
 ## 模型下载地址
url = "https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/"
weights = json_data['weightsManifest']
## 下载权重分片
for index in range(len(weights)):
 filename = weights[index]['paths'][0]
 response = urllib.request.urlopen(url + filename)
 data = response.read() # a `bytes` object
 with open("model/" + filename, 'wb') as f:
 f.write(data)

进行图像分类

参考TensorFlow.js中的示例代码,加载图像并对图像进行分类

const img = document.getElementById('img');// 对图像进行分类.
const predictions = await model.classify(img);

由于缺少DOM对象,这在Node.js上并不能使用

MobileNet的实例对象的classify()方法接收一个DOM对象(Canvas,Video,Img),并自动检索这些对象中的图像字节并将其转换为 tf.Tensor3D 类型,作为模型的输入。也可以直接向 classify()方法中直接传入 tf.Tensor3D 类型的变量。

我没有尝试使用外部包来模拟Node.js中的DOM元素,而是采用手动构建 tf.Tensor3D 的变量,因为这样更加容易

利用下面的代码,可以将一个图像数组转换为相应的Tensor3D的变量。

const values = new Int32Array(image.height * image.width * numChannels);
// 整理输出变量的形状
const outShape = [image.height, image.width, numChannels];
const input = tf.tensor3d(values, outShape, 'int32');

values 是一个int32类型的2D数组,其包含了每个像素通道值的顺序列表,numChannels是每个像素的通道值。

jpeg-js 是一个可以在Node.js上使用的JavaScript JPEG编码器和解码器,使用该库可以提取每个像素的RGB值。

const pixels = 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模型将宽度和高度为224像素的图像进行分类。对于三个通道像素值中的每一个,输入张量必须是介于-1和1之间的浮点值。

因此,在分类之前,需要重新调整不同尺寸图像的输入值。另外,来自JPEG解码器的像素值在0到255范围内 ,而不是 -1到1。这些值还需要在进行分类之前进行转换。

TensorFlow.js库中有方法使这个过程更容易,但幸运的是,tfjs-models/mobilenets 会自动处理这个问题!

开发人员可以将类型为int32和不同维度的Tensor3D输入传递给classify方法,并在分类之前将输入转换为正确的格式。超级。

最后,对代码进行整理,最终结果如下:

// 导入相应的库
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
}
// 将 4通道的图像数组 转换为 3通道的图像数组
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
}
// 将图片数组转换为 Tensor3D类型 
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)
 // 将图片数组 转换为 Tensor3D类型的变量
 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])

测试模型

下载示例图片,准备进行分类。

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% 。

原文链接:https://dev.to/jthomas/machine-learning-in-nodejs-with-tensorflowjs-1g1p


本文由黑胡桃实验室敲制,转载请获得授权。

相关推荐

windows开启telnet服务,检测远程服务端口是否可以连通

本文介绍windwos开启telnet服务,telnet服务一般可以用于检测远程主机的某个端口服务是否可以连通,在日常的工作中,我们经常会遇到在本地的windows检测远程服务端口是否可以连通。win...

仅在Web登录新华三交换机条件下启用设备Telnet登录方式

概述Web登录新华三交换机可以在“网络-服务”页面中启用设备Telnet服务或SSH服务,也可以在“设备-管理员”设置管理员用户的可用服务,然而,在设备Web页面中,无法设置lineVTY用户线【l...

思科交换机,路由器如何关闭telnet 开启ssh服务

SSH为建立在应用层基础上的安全协议。SSH是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用SSH协议可以有效防止远程管理过程中的信息泄露问题。今天我们就来说说思科交换机,路...

智能化弱电行业常用的DOS命令,掌握了你也能成为...

前言在做智能化弱电项目时,前端摄像头设备安装结束后,我们会对网络摄像头进行调试,调试过程中会遇到前端摄像头没有图像或者图像出来了画面卡顿的现象。我们会采用ping命令来测试网络的连通性和网络承载能力。...

「干货」eNSP模拟器之配置Telnet登录

配置说明:配置Telnet,使R2(模拟PC)通过SW1登录到R1进行管理和配置。操作步骤:system-view##进入系统视图[Huawei]sysnameR1##改名为R1[R1]int...

win11开启telnet服务怎么操作 win11打开telent指令是什么

telnet服务是我们在进行远程连接的时候,必须要打开的一项功能。但是有不少用户们不清楚在windows11系统中怎么开启telnet服务。今天小编就使用详细的图文教程,来给大家说明一下打开telen...

华三(H3C)交换机Telnet的远程登陆

一,配置交换机管理IP[SW1]vlan20//创建管理vlan[SW1]interfacevlan20//进入vlan接口[SW1-Vlanif20]ipaddress192.168....

win10 telnet命令怎么查看端口是否打开

可能大家也会遇到这个问题,win10telnet命令查看端口是否打开的步骤是什么?具体方法如下:1、键盘输入快捷键WIN+R,打开运行窗口。2、输入cmd,点击确定按钮。3、弹出cmd命令行窗...

Windows 7如何打开Telnet功能(win7系统打开telnet)

Windows7默认安装后是没有开启telnet客户端功能的,例如,我们在开始菜单中输入cmd,然后使用telnet命令,会弹出下图提示:‘telnet’不是内部或外部命令,也不是可运行程序或批处理文...

为锐捷路由器交换机开启web和telnet,实现轻松管理

笔者上一篇文章写了关于锐捷二层交换机配置教程,那么接下来讲一下锐捷的路由交换设备配置web、telnet技巧。同样,今天的教程也是基于命令行,比较简单,适合新手小白进行学习。准备工作配置前准备:con...

一文学会telnet命令的用途和使用方法

Telnet是一个古老的远程登录协议,可以让本地计算机获得远程计算机的工作能力。它采用了TCP的可靠连接方式,可以连接任何网络互通的远程计算机。不过由于它采用了明文传输方式,存在安全风险,目前已经很少...

Telnet命令是什么?如何使用?(telnet命令在哪里开启)

telnet命令是一个常用的远程登陆工具,使用它,我们可以快捷地登陆远程服务器进行操作。那么如何使用telnet命令呢?首先,我们需要打开telnet功能,任何电脑默认是关闭此功能的,开启方式如下:打...

win11系统如何开启telnet服务(拷贝版本)

  我们要知道,Telnet协议是Internet远程登陆服务的标准协议,可以使用户在本地计算机上完成远程主机的工作,不过对于一些刚接触win11中文版系统的用户来说,可能还不知道telnet服务在哪...

如何开启telnet客户端(如何开启telnet服务)

Telnet协议是TCP/IP协议家族中的一员,是Internet远程登陆服务的标准协议和主要方式,Telnet是常用的远程控制Web服务器的方法。工作中经常用到telnet客户端,但在windows...

Telnet 是什么,如何启用它?(telnet有什么用)

对于Internet等TCP/IP网络,Telnet是一个终端仿真程序。Telnet软件在您的系统上运行并将您的个人计算机链接到网络服务器。它将所有数据转换为纯文本这一事实被认为是易受...

取消回复欢迎 发表评论: