用 tensorflow.js 做了一个动漫分类的功能(二)
前言:
前面已经通过采集拿到了图片,并且也手动对图片做了标注。接下来就要通过 Tensorflow.js 基于 mobileNet 训练模型,最后就可以实现在采集中对图片进行自动分类了。
这种功能在应用场景里就比较多了,比如图标素材站点,用户通过上传一个图标,系统会自动匹配出相似的图标,还有二手平台,用户通过上传闲置物品图片,平台自动给出分类等,这些也都是前期对海量图片进行了标注训练而得到一个损失率极低的模型。下面就通过简答的代码实现一个小的动漫分类。

环境:
Node
Http-Server
Parcel
Tensorflow

编码:
1. 训练模型
1.1. 创建项目,安装依赖包
npm install @tensorflow/tfjs --legacy-peer-deps
npm install @tensorflow/tfjs-node-gpu --legacy-peer-deps1.2. 全局安装 Http-Server
npm install i http-server1.3. 下载 mobileNet 模型文件 (网上有下载)
1.4. 根目录下启动 Http 服务 (开启跨域),用于 mobileNet 和训练结果的模型可访问
http-server--cors-p8080
1.5. 创建训练执行脚本 run.js
const tf = require('@tensorflow/tfjs-node-gpu');const getData = require('./data');
const TRAIN_PATH = './动漫分类/train';
const OUT_PUT = 'output';
const MOBILENET_URL = 'http://127.0.0.1:8080/data/mobilenet/web_model/model.json';(async () => {const { ds, classes } = await getData(TRAIN_PATH, OUT_PUT);console.log(ds, classes);//引入别人训练好的模型const mobilenet = await tf.loadLayersModel(MOBILENET_URL);//查看模型结构mobilenet.summary();const model = tf.sequential();//截断模型,复用了86个层for (let i = 0; i < 86; ++i) {const layer = mobilenet.layers[i];layer.trainable = false;model.add(layer);}//降维,摊平数据model.add(tf.layers.flatten());//设置全连接层model.add(tf.layers.dense({units: 10,activation: 'relu'//设置激活函数,用于处理非线性问题}));model.add(tf.layers.dense({units: classes.length,activation: 'softmax'//用于多分类问题}));//设置损失函数,优化器model.compile({loss: 'sparseCategoricalCrossentropy',optimizer: tf.train.adam(),metrics:['acc']});//训练模型await model.fitDataset(ds, { epochs: 20 });//保存模型await model.save(`file://${process.cwd()}/${OUT_PUT}`);
})();1.6. 创建图片与 Tensor 转换库 data.js
const fs = require('fs');
const tf = require("@tensorflow/tfjs-node-gpu");const img2x = (imgPath) => {const buffer = fs.readFileSync(imgPath);//清除数据return tf.tidy(() => {//把图片转成tensorconst imgt = tf.node.decodeImage(newUint8Array(buffer), 3);//调整图片大小const imgResize = tf.image.resizeBilinear(imgt, [224, 224]);//归一化return imgResize.toFloat().sub(255 / 2).div(255 / 2).reshape([1, 224, 224, 3]);});
}const getData = async (traindir, output) => {let classes = fs.readdirSync(traindir, 'utf-8');fs.writeFileSync(`./${output}/classes.json`, JSON.stringify(classes));const data = [];classes.forEach((dir, dirIndex) => {fs.readdirSync(`${traindir}/${dir}`).filter(n => n.match(/jpg$/)).slice(0, 1000).forEach(filename => {const imgPath = `${traindir}/${dir}/${filename}`;data.push({ imgPath, dirIndex });});});console.log(data);//打乱训练顺序,提高准确度tf.util.shuffle(data);const ds = tf.data.generator(function* () {const count = data.length;const batchSize = 32;for (let start = 0; start < count; start += batchSize) {const end = Math.min(start + batchSize, count);console.log('当前批次', start);yield tf.tidy(() => {const inputs = [];const labels = [];for (let j = start; j < end; ++j) {const { imgPath, dirIndex } = data[j];const x = img2x(imgPath);inputs.push(x);labels.push(dirIndex);}const xs = tf.concat(inputs);const ys = tf.tensor(labels);return { xs, ys };});}});return { ds, classes };
}module.exports = getData;1.7. 运行执行文件
noderun.js
2. 调用模型
2.1. 全局安装 parcel
npminstall i parcel2.2. 创建页面 index.html
<scriptsrc="script.js"></script><inputtype="file"onchange="predict(this.files[0])"><br>2.3. 创建模型调用预测脚本 script.js
import * as tf from'@tensorflow/tfjs';
import { img2x, file2img } from'./utils';const MODEL_PATH = 'http://127.0.0.1:8080/t7';
const CLASSES = ["假面骑士","奥特曼","海贼王","火影忍者","龙珠"];window.onload = async () => {const model = await tf.loadLayersModel(MODEL_PATH + '/output/model.json');window.predict = async (file) => {const img = await file2img(file);document.body.appendChild(img);const pred = tf.tidy(() => {const x = img2x(img);return model.predict(x);});const index = pred.argMax(1).dataSync()[0];console.log(pred.argMax(1).dataSync());let predictStr = "";if (typeof CLASSES[index] == 'undefined') {predictStr = BRAND_CLASSES[index];} else {predictStr = CLASSES[index];}setTimeout(() => {alert(`预测结果:${predictStr}`);}, 0);};
};2.4. 创建图片 tensor 格式转换库 utils.js
import * as tf from'@tensorflow/tfjs';exportfunctionimg2x(imgEl){return tf.tidy(() => {const input = tf.browser.fromPixels(imgEl).toFloat().sub(255 / 2).div(255 / 2).reshape([1, 224, 224, 3]);return input;});
}exportfunctionfile2img(f) {returnnewPromise(resolve => {const reader = new FileReader();reader.readAsDataURL(f);reader.onload = (e) => {const img = document.createElement('img');img.src = e.target.result;img.width = 224;img.height = 224;img.onload = () => resolve(img);};});
}2.5. 打包项目并运行
parcelindex.html
2.6. 运行效果



注意:
1. 模型训练过程报错
Input to reshape is a tensor with 50176 values, but the requested shape has 150528
1.1. 原因
张量 reshape 不对,实际输入元素个数与所需矩阵元素个数不一致,就是采集过来的图片有多种图片格式,而不同格式的通道不同 (jpg3 通道,png4 通道,灰色图片 1 通道),在将图片转换 tensor 时与代码里的张量形状不匹配。
1.2. 解决方法
一种方法是删除灰色或 png 图片,其二是修改代码 tf.node.decodeImage (new Uint8Array (buffer), 3)

相关文章:
用 tensorflow.js 做了一个动漫分类的功能(二)
前言:前面已经通过采集拿到了图片,并且也手动对图片做了标注。接下来就要通过 Tensorflow.js 基于 mobileNet 训练模型,最后就可以实现在采集中对图片进行自动分类了。这种功能在应用场景里就比较多了,比如图标素材站点࿰…...
小林coding
一、图解网络 问大家,为什么要有TCP/Ip网络模型? 对于同一台设备上的进程通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,对于不同设备上的进程通信,就需要有网络通信,而设备是…...
操作系统真相还原_第6章:完善内核
文章目录6.1 函数调用约定简介6.2 汇编语言和C语言混合编程汇编调用CC调用汇编6.3 实现打印函数流程程序编译并写入硬盘执行6.4 内联汇编简介汇编语言AT&T语法基本内联汇编扩展内联汇编6.1 函数调用约定简介 调用约定: calling conventions 调用函数时的一套约…...
SmoothNLP新词发现算法的改进实现
SmoothNLP新词发现算法的改进实现 背景介绍 新词发现也叫未登录词提取,依据 《统计自然语言处理》(宗成庆),中文分词有98%的错误来自"未登录词"。即便早就火遍大江南北的Bert也不能解决"未登录词"的Encoding问题,便索性…...
实时渲染为什么快,能不能局域网部署点量云
提到渲染很多有相关从业经验的人员可能会想起,自己曾经在电脑上渲染一个模型半天或者更长的 时间才能完成的经历。尤其是在项目比较着急的时候,这种煎熬更是难受。但现在随着实时渲染和云渲染行业的发展,通过很多方式可以提升渲染的时间和效率…...
网络游戏该如何防护ddos/cc攻击
现在做网络游戏的企业都知道服务器的安全对于我们来说很重要!互联网上面的 DDoS 攻击和 CC 攻击等等无处不在,而游戏服务器对服务器的防御能力和处理能力要求更高,普通的服务器则是比较注重各方面能力的均衡。随着游戏行业的壮大,…...
项目管理体系1-4练习题1-10答案
题目1 每周一次的项目会议上,一位团队成员表示在修订一项可交付成果时,一名销售经理对客户服务过程想出一项变更讨论,影响到整个项目,项目经理对销售参与到项目可交付成果感到吃惊,经理事先应该怎么做去阻止这些情况&…...
sHMIctrl智能屏幕使用记录
手上有个案子,“按压机器人”,功能是恒定一个力按下一定时间。 屏幕选型使用“sHMIctrl”,一下记录使用过程中遇到的问题以及解决方法。 目录 问题1:按键控件做定时触发,模拟运行时触发不了。 问题2:厂家…...
2.20 crm day01 配置路由router less使用 axios二次封装
需求: 目录 1.配置路由 2.less使用 vue2使用以下版本 3.axios二次封装 1.配置路由 1.1.1 官方链接:安装 | Vue Router npm i vue-router3.6.5 注意:vue2项目不能用vue-router四版本以上 1.2.1.创建router/index.js 在该文件中 //1.引…...
【LeetCode】剑指 Offer 10- I. 斐波那契数列 p74 -- Java Version
题目链接: 1. 题目介绍() 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: F(0) 0, F(1) 1F(N) F(N - 1) F…...
论文笔记:DropMessage: Unifying Random Dropping for Graph Neural Networks
(AAAI 23 优秀论文) 1 intro GNN的一个普遍思路是,每一层卷积层中,从邻居处聚合信息 尽管GNN有显著的进步,但是在大规模图中训练GNN会遇到各种问题: 过拟合 过拟合之后,GNN的泛化能力就被限制…...
木鱼cms系统审计小结
MuYuCMS基于Thinkphp开发的一套轻量级开源内容管理系统,专注为公司企业、个人站长提供快速建站提供解决方案。 环境搭建 我们利用 phpstudy 来搭建环境,选择 Apache2.4.39 MySQL5.7.26 php5.6.9 ,同时利用 PhpStorm 来实现对项目的调试 …...
软件测试面试-一线大厂必问的测试思维面试题
五、测试思维5.1 打电话功能怎么去测?我们会从几个方面去测试:界面、功能、兼容性、易用性、安全、性能、异常。1)界面我们会测试下是否跟界面原型图一致,考虑浏览器不同显示比例,屏幕分辨率。2)功能&#…...
企业级分布式应用服务 EDAS
什么是企业级分布式应用服务EDAS企业级分布式应用服务EDAS(Enterprise Distributed Application Service)是一个应用托管和微服务管理的云原生PaaS平台,提供应用开发、部署、监控、运维等全栈式解决方案,同时支持Spring Cloud和Ap…...
弄懂 Websocket 你得知道的这 3 点
1. WebSocket原理 WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简…...
Appium构架及工作原理
一、appium结构简单来说appium充当一个中间服务器的功能,接收来自我们代码的请求,然后发送到手机上进行执行。二、初步认识appium工作过程1.appium是c/s模式的2.appium是基于webdriver协议添加对移动设备自动化api扩展而成的,所以具有和webdr…...
软件架构中“弹性”的多种含义
在软件架构领域的中文文档、书籍中,经常可以看到“弹性”这个专业术语,但在不同的语境下含义可能会不同。 在英语中,elastic 和 resilient 两个单词都可以翻译为“弹性的”,但是它们在软件架构中代表的含义却完全不同,…...
JAVA练习57- 罗马数字转整数、位1的个数
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目1-罗马数字转整数 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 二、题目2-位1的个数 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 …...
C#把图片放到picturebox上的指定位置,PointToClient与PointToScreen解读
1、C#中如何把图片放到picturebox上的指定位置 构造一个跟picturebox1一样大小的Bitmap, 设置给picturebox1, 然后在上面画图 Bitmap image new Bitmap(picturebox1.Size.Width, picturebox1.Size.Height); Graphics device Graphics.FromImage(imag…...
【论文笔记】Manhattan-SDF==ZJU==CVPR‘2022 Oral
Neural 3D Scene Reconstruction with the Manhattan-world Assumption 本文工作:基于曼哈顿世界假设,重建室内场景三维模型。 1.1 曼哈顿世界假设 参考阅读文献:Structure-SLAM: Low-Drift Monocular SLAM in Indoor EnvironmentsIEEE IR…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
