83TensorFlow 2 模型部署方法实践--使用 TensorFlow.js 部署模型

使用 TensorFlow.js 部署模型

TensorFlow.js 介绍

TensorFlow.js 是一个 JavaScript 库,用于在浏览器或 Node.js 训练和部署机器学习模型。TensorFlow.js 的优点有:
不用安装驱动器和软件,通过链接即可分享程序。
网页应用,交互性强。
有访问 GPS,Camera,Microphone,Accelerator,Gyroscope 等传感器的标准 API。
安全性,因为数据都保存在客户端。

本节实验将学习 TensorFlow.js 基本语法,并部署 MobileNetV2 图像识别的应用。

在 JavaScript 项目中获取 TensorFlow.js 的主要方法有两种:
通过脚本标签导入:<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"> </script>。
使用 NPM 安装 TensorFlow.js:npm install @tensorflow/tfj。

在本节实验中我们主要使用通过脚本标签导入的方法。
在桌面下创建 HTML 文件 demo.html,我们将在此文件中介绍 TensorFlow.js 的核心概念。

张量

TensorFlow.js 的数据单元是张量(Tensor):一组数值存储于一维或者多维数组里。一个张量的实例有 shape 的属性用于构造多维数组。其中最主要的 Tensor 的构造函数是 tf.tensor ,同时为了方便书写,还有 tf.tensor2d,tf.tensor3d,tf.scalar,tf.zeros 等函数,这样也会增强代码的可读性。

<html>
  <head>
    <!-- 导入 TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"></script>

    <!-- 在下方实现 TensorFlow.js 的代码 -->
    <script>
      const shape = [2, 3]; // 先定义张量的形状
      const a = tf.tensor([1, 2, 3, 4, 5, 6], shape); //使用 tf.tensor 定义一个 2 * 3 的张量
      a.print(); //在浏览器的控制台中打印结果
      // 输出为:[[1, 2, 3],
      //         [4, 5, 6]]
      const b = tf.tensor2d([
        [6, 5, 4],
        [3, 2, 1],
      ]); //使用 tf.tensor2d 定义一个 2 * 3 的张量
      b.print();
      // 输出为:[[6, 5, 4],
      //         [3, 2, 1]]
      const c = tf.scalar(3.5); // 使用 tf.scalar 定义常数
      c.print();
      // 输出为:3.5
      const d = tf.zeros([2, 2]); // 使用 tf.zeros 定义一个 2 * 2, 值全为 0 的张量
      d.print();
      // 输出为:[[0, 0],
      //         [0, 0]]
    </script>
  </head>
</html>

以 Chrome 浏览器为例:选择 demo.html 文件,右键,选择 Open With,选择使用 Preview 打开。在界面任意位置点击右键,选择检查打开控制台,点击上边栏的 Console,就可以看到程序的输出了。

运算

使用张量去存储数据,那么运算(Operation)允许你去利用这些数据。TensorFlow.js 提供了一整套适用于线性代数和机器学习的操作函数。

<html>
  <head>
    <!-- 导入 TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"></script>

    <!-- 在下方实现 TensorFlow.js 的代码 -->
    <script>
      const shape = [2, 3]; // 先定义张量的形状
      const a = tf.tensor([1, 2, 3, 4, 5, 6], shape); //使用 tf.tensor 定义一个 2 * 3 的张量
      a.print(); //在浏览器的控制台中打印结果
      // 输出为:[[1, 2, 3],
      //           [4, 5, 6]]
      const b = tf.tensor2d([
        [6, 5, 4],
        [3, 2, 1],
      ]); //使用 tf.tensor2d 定义一个 2 * 3 的张量
      b.print();
      // 输出为:[[6, 5, 4],
      //           [3, 2, 1]]
      const c = tf.scalar(2.0); // 使用 tf.scalar 定义常数
      c.print();
      // 输出为:2
      const a_plus_b = a.add(b); // 进行 a + b 的运算
      a_plus_b.print();
      // 输出为:[[7, 7, 7],
      //          [7, 7, 7]]
      const reshape = a_plus_b.reshape([3, 2]); // 修改张量的形状
      reshape.print();
      // 输出为:[[7, 7],
      //          [7, 7],
      //          [7, 7]]

      //同时 TensorFlow.js 也支持链式写法:
      const a_sub_div_c = a.sub(c).div(c); // 进行 (a - c) / c 的运算
      a_sub_div_c.print();
      // 输出为:[[-0.5, 0, 0.5],
      //          [1, 1.5, 2]]
    </script>
  </head>
</html>

同样,选择 demo.html 文件,右键,选择 Open With,选择使用 Preview 打开。在界面任意位置点击右键,选择检查打开控制台,点击上边栏的 Console,就可以看到程序的输出了。
下面是视频演示:
https://labfile.oss.aliyuncs.com/courses/1435/4-1.mp4

模型转换

环境配置
使用一个 Web 服务器为模型文件提供服务时,需要将服务器配置为允许跨源资源共享(CORS), 以允许在 JavaScript 中提取文件。
进入之前实验所新建的虚拟环境(如果没有虚拟环境则需要先执行 virtualenv -p /usr/bin/python3.6 pyenv 进行安装),安装 TensorFlow.js 用于模型转换,安装 Flask-CORS 用于跨源资源共享。

$ . pyenv/bin/activate
$ pip install tensorflowjs==1.4.0 flask_cors==3.0.8

下载预训练模型,并将其放于 ~/.keras/models 目录下,如果实验了上节实验的保存环境,则可以跳过此步骤。

$ wget https://labfile.oss.aliyuncs.com/courses/1435/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5
$ mkdir -p ~/.keras/models
$ cp mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5 ~/.keras/models

转换 Keras 模型

在桌面创建文件脚本 convert.py,将 Keras 模型转换为 TensorFlow.js 需要的格式。

import tensorflowjs as tfjs
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2
# 初始化 Keras 的 MobileNet 模型,并导入 ImageNet 权重
model = MobileNetV2(weights='imagenet')
# 进行转换,将转换后的模型保存在 model 文件夹下
tfjs.converters.save_keras_model(model, 'model/')

在终端输入 python convert.py 执行转换程序。

开启 CORS

在桌面创建文件脚本 cors.py,CORS 功能将在此文件中实现。其中,我们初始化 CORS,以允许对所有路由上的所有域进行 CORS。

from flask import Flask
from flask_cors import CORS

# 创建 Flask 实例
app = Flask(__name__,
            static_url_path='/model',
            static_folder='model')

# 初始化 CORS,以允许对所有路由上的所有域进行 CORS
cors = CORS(app)

# 注册路由
@app.route("/")
def hello():
    return "Hello Shiyanlou!"

# 开启服务
if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8080', debug=True)

在这个应用中,我们把 URL 路径 /model 映射到了文件目录 model(相对于本文件),外界通过 {host}/model 就能访问到 model 内的文件。
在终端输入 python cors.py 开启 CORS 服务。
此时点击 Web 服务,在浏览器地址栏里显示的 URL 就是 host 的地址,在这里域名部分 c8ce7fff3a04-service 每个人都不同,需要实际运行中进行替换。

image.png

这样我们就可以通过访问 https://c8ce7fff3a04-service.simplelab.cn/model 来访问文件。

使用 TensorFlow.js 进行预测

导入模型
在 TensorFlow.js 中导入模型的方法如下,即通过提供 model.json 文件的 URL 将模型加载到 TensorFlow.js 中。

const model = await tf.loadLayersModel('http://***/model.json');

在上述语句中关键词 await 的意思是等待,即需要等到模型加载完成后再执行后面的语句。同时 await 只能在 async 函数中使用,不能在常规函数中使用,不能工作在顶级作用域。
在桌面创建文件脚本 tfjs.html,在此文件中将实现 TensorFlow.js 的全部功能。

<html>
  <!-- 导入 TensorFlow.js -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.8/dist/tf.min.js"></script>
  <!-- 在下方实现 TensorFlow.js 的代码 -->
  <script>
    // 首先定义 model
    let model;
    // 定义异步函数 demo,在这个函数中执行所有处理
    const demo = async () => {
      // 载入模型,记得将域名替换为自己的
      model = await tf.loadLayersModel(
        'https://c8ce7fff3a04-service.simplelab.cn/model/model.json'
      );
      // 定义一个 1 * 224 * 224 * 3 的全 0 张量,用于测试模型是否可用
      const batched = tf.zeros([1, 224, 224, 3]);
      // 打印模型的预测结果
      console.log(model.predict(batched).data());
    };
    // 运行 demo 函数
    demo();
  </script>
</html>

对结果进行预览
以 Chrome 浏览器为例:选择 tfjs.html 文件,右键,选择 Open With,选择使用 Preview 打开。在界面任意位置点击右键,选择检查打开控制台,点击上边栏的 console 就可以看到模型输出了。
https://labfile.oss.aliyuncs.com/courses/1435/4-2.mp4

导入图片

接下来我们导入之前实验中使用的图片进行预测,为方便操作,我们直接通过终端下载图片和 ImageNet 对应的类别标签。
新开一个终端窗口,在此终端中下载文件。

$ wget https://labfile.oss.aliyuncs.com/courses/1435/image.jpg
$ wget https://labfile.oss.aliyuncs.com/courses/1435/imagenet_classes.js

接下来,我们在 tfjs.html 文件中导入图片,并进行预测,输出结果。

<html>
  <!-- 创建图片元素,设置 id 属性为 image,以供 js 读取调用 -->
  <img src="image.jpg" id="image" width="224" height="224" />
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.8/dist/tf.min.js"></script>
  <!-- 创建一个标题元素,用于显示预测结果 -->
  <h5 id="output">正在预测...</h5>
  <script type="module">
    // 从 imagenet_classes.js 中获取标签列表
    import { IMAGENET_CLASSES } from './imagenet_classes.js';
    let model;
    const demo = async () => {
      // 载入模型,记得将域名替换为自己的
      model = await tf.loadLayersModel(
        'https://c8ce7fff3a04-service.simplelab.cn/model/model.json'
      );
      // 通过 getElementById 获取图片元素
      const imageElement = document.getElementById('image');
      // 将图片元素转换为 float 格式
      const img = tf.browser.fromPixels(imageElement).toFloat();
      // 将图片像素每个位置减去 127.5 再除以 127.5 以归一化到 [-1, 1] 之间
      const offset = tf.scalar(127.5);
      const normalized = img.sub(offset).div(offset);
      // 将归一化后的图片 reshape 到模型需要的输入形状
      const batched = normalized.reshape([1, 224, 224, 3]);
      // 进行预测
      const pred = model.predict(batched);
      // 获取预测结果最大值所在索引
      const index = await tf.argMax(pred, 1).data();
      // 从 IMAGENET_CLASSES 获取所对应的标签
      const label = IMAGENET_CLASSES[index];
      // 将标签输出到 h5 元素中显示
      document.getElementById('output').innerHTML = label;
    };
    // 运行 demo 函数
    demo();
  </script>
</html>

对结果进行预览
选择 tfjs.html 文件,右键,选择 Open With,选择使用 Preview 打开。
https://labfile.oss.aliyuncs.com/courses/1435/4-3.mp4

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容