使用TensorFlow.js在Node.js中进行机器学习
qiyuwang 2024-10-31 15:51 32 浏览 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
本文由黑胡桃实验室敲制,转载请获得授权。
相关推荐
- 基于Docker方式安装与部署Camunda流程引擎
-
1Camunda简介官网:https://docs.camunda.org/manual/7.19/installation/docker/Camunda是一个轻量级、开源且高度灵活的工作流和决策自...
- 宝塔Linux面板如何部署Java项目?(宝塔面板 linux)
-
通过宝塔面板部署Java还是很方便的,至少不需要自己输入tomcat之类的安装命令了。在部署java项目前,我还是先说下目前的系统环境,如果和我的系统环境不一样,导致部署不成功,那你可能需要去找其他资...
- 浪潮服务器如何用IPMI安装Linux系统
-
【注意事项】此处以浪潮服务器为例进行演示所需使用的软件:Chrome浏览器个人PC中需要预先安装java,推荐使用jdk-8u181-windows-x64.exe【操作步骤】1、在服务器的BIOS中...
- Centos7环境Hadoop3集群搭建(hadoop集群环境搭建实验报告)
-
由于项目需要存储历史业务数据,经过评估数据量会达到100亿以上,在原有mongodb集群和ES集群基础上,需要搭建Hbase集群进行调研,所以首先总结一下Hadoop集群的搭建过程。一、三个节点的集群...
- Hadoop高可用集群搭建及API调用(hadoop高可用原理)
-
NameNodeHA背景在Hadoop1中NameNode存在一个单点故障问题,如果NameNode所在的机器发生故障,整个集群就将不可用(Hadoop1中虽然有个SecorndaryNameNo...
- 使用Wordpress搭建一个属于自己的网站
-
现在开源的博客很多,但是考虑到wordpress对网站的seo做的很好,插件也多。并且全世界流量排名前1000万的网站有33.4%是用Wordpress搭建的!所以尝试用Wordpress搭建一个网站...
- Centos 安装 Jenkins(centos 安装ssh)
-
1、Java安装查看系统是否已安装Javayumlistinstalled|grepjava...
- Java教程:gitlab-使用入门(java中的git)
-
1导读本教程主要讲解了GitLab在项目的环境搭建和基本的使用,可以帮助大家在企业中能够自主搭建GitLab服务,并且可以GitLab中的组、权限、项目自主操作...
- Dockerfile部署Java项目(docker部署java应用)
-
1、概述本文主要会简单介绍什么是Docker,什么是Dockerfile,如何安装Docker,Dockerfile如何编写,如何通过Dockerfile安装jar包并外置yaml文件以及如何通过do...
- 如何在Eclipse中搭建Zabbix源码的调试和开发环境
-
Zabbix是一款非常优秀的企业级软件,被设计用于对数万台服务器、虚拟机和网络设备的数百万个监控项进行实时监控。Zabbix是开放源码和免费的,这就意味着当出现bug时,我们可以很方便地通过调试源码来...
- Java路径-02-Java环境配置(java环境搭建及配置教程)
-
1Window环境配置1.1下载...
- 35.Centos中安装python和web.py框架
-
文章目录前言1.Centos7python:2.Centos8python:3.进行下载web.py框架然后应用:4.安装好之后进行验证:5.总结:前言...
- 《我的世界》服务器搭建(我的世界服务器如何搭建)
-
1.CentOS7环境1.1更改YUM源#下载YUM源文件curl-o/etc/yum.repos.d/CentOS-Base.repohttps://mirrors.aliyun.com...
- CentOS 7 升级 GCC 版本(centos7.4升级7.5)
-
1.GCC工具介绍GCC编译器:...
- Linux安装Nginx详细教程(linux安装配置nginx)
-
环境准备1.因为Nginx依赖于gcc的编译环境,所以,需要安装编译环境来使Nginx能够编译起来。命令:yuminstallgcc-c++显示完毕,表示安装完成:2.Nginx的http模块需要...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 基于Docker方式安装与部署Camunda流程引擎
- 宝塔Linux面板如何部署Java项目?(宝塔面板 linux)
- 浪潮服务器如何用IPMI安装Linux系统
- Centos7环境Hadoop3集群搭建(hadoop集群环境搭建实验报告)
- Hadoop高可用集群搭建及API调用(hadoop高可用原理)
- 使用Wordpress搭建一个属于自己的网站
- Centos 安装 Jenkins(centos 安装ssh)
- Java教程:gitlab-使用入门(java中的git)
- Dockerfile部署Java项目(docker部署java应用)
- 如何在Eclipse中搭建Zabbix源码的调试和开发环境
- 标签列表
-
- navicat无法连接mysql服务器 (65)
- 下横线怎么打 (71)
- flash插件怎么安装 (60)
- lol体验服怎么进 (66)
- ae插件怎么安装 (62)
- yum卸载 (75)
- .key文件 (63)
- cad一打开就致命错误是怎么回事 (61)
- rpm文件怎么安装 (66)
- linux取消挂载 (81)
- ie代理配置错误 (61)
- ajax error (67)
- centos7 重启网络 (67)
- centos6下载 (58)
- mysql 外网访问权限 (69)
- centos查看内核版本 (61)
- ps错误16 (66)
- nodejs读取json文件 (64)
- centos7 1810 (59)
- 加载com加载项时运行错误 (67)
- php打乱数组顺序 (68)
- cad安装失败怎么解决 (58)
- 因文件头错误而不能打开怎么解决 (68)
- js判断字符串为空 (62)
- centos查看端口 (64)