前言

  从前面的Tensorflow环境搭建到目标检测模型迁移学习,已经完成了一个简答的扑克牌检测器,不管是从图片还是视频都能从画面中识别出有扑克的目标,并标识出扑克点数。但是,我想在想让他放在浏览器上可能实际使用,那么要如何让Tensorflow模型转换成web格式的呢?接下来将从实践的角度详细介绍一下部署方法!

环境

  • Windows10
  • Anaconda3
  • TensorFlow.js converter

converter介绍

  converter全名是TensorFlow.js Converter,他可以将TensorFlow GraphDef模型(通过Python API创建的,可以先理解为Python模型) 转换成Tensorflow.js可读取的模型格式(json格式), 用于在浏览器上对指定数据进行推算。

converter安装

  为了不影响前面目标检测训练环境,这里我用conda创建了一个新的Python虚拟环境,Python版本3.6.8。在安装转换器的时候,如果当前环境没有Tensorflow,默认会安装与TF相关的依赖,只需要进入指定虚拟环境,输入以下命令。

pip install tensorflowjs

  

converter用法

tensorflowjs_converter --input_format=tf_saved_model --output_format=tfjs_graph_model --signature_name=serving_default --saved_model_tags=serve ./saved_model ./web_model

1. 产生的文件(生成的web格式模型)

转换器命令执行后生产两种文件,分别是model.json (数据流图和权重清单)和group1-shard\*of\* (二进制权重文件)

2. 输入的必要条件(命令参数和选项[带--为选项])

converter转换指令后面主要携带四个参数,分别是输入模型的格式,输出模型的格式,输入模型的路径,输出模型的路径,更多帮助信息可以通过以下命令查看,另附命令分解图。

tensorflowjs_converter --help

2.1. --input_format

要转换的模型的格式,SavedModel 为 tf_saved_model, frozen model 为 tf_frozen_model, session bundle 为 tf_session_bundle, TensorFlow Hub module 为 tf_hub,Keras HDF5 为 keras。

2.2. --output_format

输出模型的格式, 分别有tfjs_graph_model (tensorflow.js图模型,保存后的web模型没有了再训练能力,适合SavedModel输入格式转换),tfjs_layers_model(tensorflow.js层模型,具有有限的Keras功能,不适合TensorFlow SavedModels转换)。

2.3. input_path

saved model, session bundle 或 frozen model的完整的路径,或TensorFlow Hub模块的路径。

2.4. output_path

输出文件的保存路径。

2.5. --saved_model_tags

只对SavedModel转换用的选项:输入需要加载的MetaGraphDef相对应的tag,多个tag请用逗号分隔。默认为 serve

2.6. --signature_name

对TensorFlow Hub module和SavedModel转换用的选项:对应要加载的签名,默认为default

2.7. --output_node_names

输出节点的名字,每个名字用逗号分离。

3. 常用的两组命令行

1. covert from saved_model

tensorflowjs_converter --input_format=tf_saved_model --output_format=tfjs_graph_model --signature_name=serving_default --saved_model_tags=serve ./saved_model ./web_model

2. convert from frozen_model
tensorflowjs_converter --input_format=tf_frozen_model --output_node_names='num_detections,detection_boxes,detection_scores,detection_classes' ./frozen_inference_graph.pb ./web_modelk

开始实践

1. 找到通过export_inference_graph.py导出的模型

导出的模型在项目的inference_graph文件夹(models\research\object_detection)里,frozen_inference_graph.pb是 tf_frozen_model输入格式需要的,而saved_model文件夹就是tf_saved_model格式。在当前目录下新建web_model目录,用于存储转换后的web格式的模型。

2. 开始转换

在当前虚拟环境下,进入到inference_graph目录下,输入以下命令,之后就会在web_model生成一个json文件和多个权重文件。

tensorflowjs_converter --input_format=tf_saved_model --output_format=tfjs_graph_model --signature_name=serving_default --saved_model_tags=serve ./saved_model ./web_model

3. 浏览器端部署

3.1. 创建一个前端项目,将web_model放入其中。

3.2.编写代码

<!doctype html>
<head>
<link rel="stylesheet" href="tfjs-examples.css" />
<style>
canvas {outline: orange 2px solid; margin: 10px 0;}
</style>
</head> <body>
<div class="tfjs-example-container centered-container">
<section class='title-area'>
<h1>赌圣2023</h1>
</section>
<p class='section-head'>模型描述</p>
<p>我看你怎么出老千!</p>
<p class='section-head'>模型状态</p>
<div id="status">加载模型中...</div>
<div>
<p class='section-head'>效果展示</p>
<p></button><input type="file" accept="image/*" id="test"/></p>
<canvas id="data-canvas" width="300" height="1100"></canvas>
</div>
</div> </body> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script> <script>
const canvas = document.getElementById('data-canvas');
const status = document.getElementById('status');
const testModel = document.getElementById('test'); const BOUNDING_BOX_LINE_WIDTH = 3;
const BOUNDING_BOX_STYLE1 = 'rgb(0,0,255)';
const BOUNDING_BOX_STYLE2 = 'rgb(0,255,0)'; async function init() { const LOCAL_MODEL_PATH = './web_model/model.json'; // 将本地模型保存到浏览器
// tf.sequential().save // 加载本地模型
let model;
try {
model = await tf.loadGraphModel(LOCAL_MODEL_PATH);
testModel.disabled = false;
status.textContent = '成功加载本地模型!请亮出你的牌吧'; // 默认扑克牌
runAndVisualizeInference('./cam_image39.jpg', model) } catch (err) {
console.log('加载本地模型错误:', err);
status.textContent = '加载本地模型失败';
} testModel.addEventListener('change', (e) => {
runAndVisualizeInference(e, model)
});
} async function runAndVisualizeInference(e, model) { if (typeof e === 'string') {
await new Promise((resolve, reject) => {
// 图片显示在canvas中
var img = new Image;
img.src = e;
img.onload = function () { // 必须onload之后再画
let w = 500;
let h = img.height/img.width*500;
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(img,0,0,w,h);
resolve();
}
})
} else { // 上传图片并显示在canvas中
var file = e.target.files[0];
if (!/image\/\w+/.test(file.type)) {
alert("请确保文件为图像类型");
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file); // 转化成base64数据类型
await new Promise((resolve, reject) => {
reader.onload = function (e) {
// 图片显示在canvas中
var img = new Image;
img.src = this.result;
img.onload = function () { // 必须onload之后再画
let w = 500;
let h = img.height/img.width*500;
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(img,0,0,w,h);
resolve();
}
}
})
} // 模型输入处理
let image = tf.browser.fromPixels(canvas);
const t4d = image.expandDims(0); const outputDim = [
'num_detections', 'detection_boxes', 'detection_scores',
'detection_classes'
]; const labelMap = {
1: '九点',
2: '十点',
3: 'Jack',
4: 'Queen',
5: 'King',
6: 'Ace'
} let modelOut = {}, boxes = [], w = canvas.width, h = canvas.height;
console.log(model) for (const dim of outputDim) {
let tensor = await model.executeAsync({
'image_tensor': t4d
}, `${dim}:0`);
modelOut[dim] = await tensor.data();
}
console.log(modelOut) for (let i=0; i<modelOut['detection_scores'].length; i++) {
const score = modelOut['detection_scores'][i]; if (score < 0.5) break; // 置信度过滤 boxes.push({
ymin: modelOut['detection_boxes'][i*4]*h,
xmin: modelOut['detection_boxes'][i*4+1]*w,
ymax: modelOut['detection_boxes'][i*4+2]*h,
xmax: modelOut['detection_boxes'][i*4+3]*w,
label: labelMap[modelOut['detection_classes'][i]],
})
} console.log(boxes) // 可视化检测框
drawBoundingBoxes(canvas, boxes); // 张量运行内存清除
tf.dispose([image, modelOut]);
} function drawBoundingBoxes(canvas, predictBoundingBoxArr) {
for (const box of predictBoundingBoxArr) {
let left = box.xmin;
let right = box.xmax;
let top = box.ymin;
let bottom = box.ymax; const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.strokeStyle = box.label==='ZERO_DEV'?BOUNDING_BOX_STYLE1:BOUNDING_BOX_STYLE2;
ctx.lineWidth = BOUNDING_BOX_LINE_WIDTH;
ctx.moveTo(left, top);
ctx.lineTo(right, top);
ctx.lineTo(right, bottom);
ctx.lineTo(left, bottom);
ctx.lineTo(left, top);
ctx.stroke(); ctx.font = '24px Arial bold';
ctx.fillStyle = box.label==='zfc'?BOUNDING_BOX_STYLE2:BOUNDING_BOX_STYLE1;
ctx.fillText(box.label, left+8, top+8);
}
} init(); </script>

3.3. 运行结果

如何将训练好的Python模型给JavaScript使用?的更多相关文章

  1. mxnet的训练过程——从python到C++

    mxnet的训练过程--从python到C++ mxnet(github-mxnet)的python接口相当完善,我们可以完全不看C++的代码就能直接训练模型,如果我们要学习它的C++的代码,从pyt ...

  2. 【6】TensorFlow光速入门-python模型转换为tfjs模型并使用

    本文地址:https://www.cnblogs.com/tujia/p/13862365.html 系列文章: [0]TensorFlow光速入门-序 [1]TensorFlow光速入门-tenso ...

  3. LUSE: 无监督数据预训练短文本编码模型

    LUSE: 无监督数据预训练短文本编码模型 1 前言 本博文本应写之前立的Flag:基于加密技术编译一个自己的Python解释器,经过半个多月尝试已经成功,但考虑到安全性问题就不公开了,有兴趣的朋友私 ...

  4. 如何使用 Yolov4 训练人脸口罩检测模型

    前言 疫情当下,出入医院等公共场所都被要求佩戴口罩.这篇博客将会介绍如何使用 Yolov4,训练一个人脸口罩检测模型(使用 Yolov4 的原因是目前只复现到了 v4 ),代码地址为 https:// ...

  5. 机器学习在入侵检测方面的应用 - 基于ADFA-LD训练集训练入侵检测判别模型

    1. ADFA-LD数据集简介 ADFA-LD数据集是澳大利亚国防学院对外发布的一套主机级入侵检测数据集合,包括Linux和Windows,是一个包含了入侵事件的系统调用syscall序列的数据集(以 ...

  6. Tensorflow Mask-RCNN训练识别箱子的模型运行结果(练习)

    Tensorflow Mask-RCNN训练识别箱子的模型

  7. python中执行javascript代码

    python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext()     ctxt.enter()     ...

  8. Python实现类似JavaScript 的Json对象

    Python实现类似JavaScript 的Json对象 用过js的都知道 js中json也是一个对象,所以可以直接通过class.attr 取值,当attr不存在时也不会报错,那么Python可不可 ...

  9. 我用python训练了一个拳皇模型,从此在各地游戏厅再也没输过!

    ​ 从世界瞩目的围棋游戏 AlphaGo ​ ​ ​ 突然袭来的回忆杀~ 今天为大家介绍一个在街机游戏<街头霸王 3>中进行模拟来训练改进强化学习算法的工具包.不仅在 MAME 游戏模拟器 ...

  10. 吴裕雄 python 神经网络——TensorFlow训练神经网络:全模型

    import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data INPUT_NODE = 784 ...

随机推荐

  1. JSP 的本质原理解析:"编写的时候是JSP,心里想解读的是 java 源码"

    JSP 的本质原理解析:"编写的时候是JSP,心里想解读的是 java 源码" @ 目录 JSP 的本质原理解析:"编写的时候是JSP,心里想解读的是 java 源码&q ...

  2. vue3 + vite 多项目多模块打包

    vue3 + vite 多项目多模块打包 本示例基于vite-plugin-html插件,实现多个独立项目共存,共享组件和依赖,运行.打包互不干扰. npm create vite@latest 兼容 ...

  3. 扯什么kafka顺序消费,然后呢?古尔丹,代价是什么

    著名面试八股文之kafka为什么读写效率高,写的答案之一是partition顺序写,因而能保证分区内的不连续的有序性. 这里的重点是有序追加到磁盘,而不是严格意义上的完全有序性. 几年前参加了一大数据 ...

  4. 关于Mybatis

    一:Mybatis的优缺点 优点: 1.与JDBC相比,减少了百分之五十的代码量. 2.Mybatis是最简单的持久层框架,简单易学. 3.Mybatis灵活,不会对应用程序和现数据库设计强加任何影响 ...

  5. nginx配置文件编写及日志文件相关操作

    nginx配置文件编写及日志文件相关操作 目录 nginx配置文件编写及日志文件相关操作 nginx主配置文件扩展详解 部署nginx网站 注意事项 Nginx虚拟主机 nginx配置虚拟主机的三种方 ...

  6. 老夫的正则表达式大成了,桀桀桀桀!!!【Python 正则表达式笔记】

    一.正则表达式语法 (一) 字符与字符类 特殊字符 \.^$?+*{}[]()| 为特殊字符,若想要使用字面值,必须使用 \ 进行转义 字符类 [] [] 匹配包含在方括号中的任何字符.它也可以指定范 ...

  7. 2022-08-31:以下go语言代码输出什么?A:江苏;B:v[“province“]取值错误;C:m.Store存储错误;D:不知道。 package main import ( “fm

    2022-08-31:以下go语言代码输出什么?A:江苏:B:v["province"]取值错误:C:m.Store存储错误:D:不知道. package main import ...

  8. 2020-10-16:CAS知道么?底层实现? 会引发什么问题?如何解决ABA问题?

    福哥答案2020-10-16:#福大大架构师每日一题# 简单回答:cmpxchg原子指令.aba,循环开销大,一个共享变量. [知乎](https://www.zhihu.com/question/4 ...

  9. 2022-06-11:注意本文件中,graph不是邻接矩阵的含义,而是一个二部图。 在长度为N的邻接矩阵matrix中,所有的点有N个,matrix[i][j]表示点i到点j的距离或者权重, 而在二部

    2022-06-11:注意本文件中,graph不是邻接矩阵的含义,而是一个二部图. 在长度为N的邻接矩阵matrix中,所有的点有N个,matrix[i][j]表示点i到点j的距离或者权重, 而在二部 ...

  10. Django4全栈进阶之路12 render 函数和 redirect 函数

    在 Django 中,你可以使用 render 函数来渲染模板并将其返回给客户端,也可以使用 redirect 函数来重定向到其他 URL. 在 Django 中,render 函数和 redirec ...