TensorFlow.js:将 Python SavedModel 转换为 TensorFlow.js 格式

1. 简介

您已经使用 TensorFlow.js 迈出了第一步,尝试了我们预制的模型,甚至自己构建了模型 - 但你看到了一些尖端的 Python 研究,你很想知道它能否在网络浏览器中运行,让你以可扩展的方式将这个很酷的想法变为现实。听起来很熟悉?如果是这样,那么这就是适合您的 CodeLab!

TensorFlow.js 团队开发了一款便捷的工具,可以通过命令行转换器将 SavedModel 格式的模型转换为 TensorFlow.js,这样您便能够享受通过网页覆盖面和规模使用这些模型所带来的便利。

学习内容

在此 Codelab 中,您将学习如何使用 TensorFlow.js 命令行转换器将 Python 生成的 SavedModel 移植到在 Web 浏览器中在客户端执行所需的 model.json 格式。

具体而言:

  • 如何创建简单的 Python 机器学习模型并将其保存为 TensorFlow.js 转换器所需的格式。
  • 如何在从 Python 导出的 SavedModel 上安装和使用 TensorFlow.js 转换器。
  • 从转换中获取生成的文件并将其用于您的 JS Web 应用程序。
  • 了解出现问题时该怎么办(并非所有模型都会转换)以及您有哪些选择。

想象一下,如果您能够开展一些新发布的研究,并将该模型提供给全球数百万 JS 开发者,或者,您可以在自己的创作中自行使用它,如果该应用在网络浏览器中运行,世界上的任何人都可以体验它,因为不需要复杂的依赖项或环境设置。准备好开始入侵了吗?赶紧试试吧!

与我们分享您转化的内容!

您可以使用我们今天学到的知识,尝试将您喜爱的一些模型从 Python 转换出来。如果您成功做到了,并制作了展示该模型的实际演示网站,请在社交媒体上使用 #MadeWithTFJS # 标签为我们添加标签,这样您的项目就有机会在我们的 TensorFlow 博客上获得特别推介,甚至在未来的展示和讲述活动上也有机会展示。我们希望看到将更多精彩的研究成果移植到网络上,让更多人能够像这个优秀的示例一样,以新颖或有创造性的方式使用此类模型。

2. 什么是 TensorFlow.js?

1aee0ede85885520

TensorFlow.js 是一个开源机器学习库,可在任何 JavaScript 环境下运行。它基于以 Python 编写的原始 TensorFlow 库,旨在为 JavaScript 生态系统重新创建这种开发者体验和一组 API。

它的使用范围如何?

鉴于 JavaScript 的可移植性,您现在可以使用 1 种语言编写,并轻松地在以下所有平台上执行机器学习:

  • 网络浏览器中的客户端(使用原始 JavaScript)
  • 服务器端,甚至是 Raspberry Pi 等 IoT 设备,使用 Node.js
  • 使用 Electron 的桌面应用
  • 使用 React Native 的原生移动应用

TensorFlow.js 还支持在这些环境(例如,它可以在 CPU 或 WebGL 等实际基于硬件的环境)中执行多个后端。“后端”这里的环境并不意味着服务器端环境(例如,在 WebGL 中用于执行的后端可以是客户端),以便确保兼容性并保持快速运行。TensorFlow.js 目前支持:

  • 在设备的显卡 (GPU) 上执行 WebGL - 这是通过 GPU 加速执行较大模型(大小超过 3MB)的最快方式。
  • 在 CPU 上执行 Web Assembly (WASM) - 提高各种设备的 CPU 性能,包括老一代手机。这更适合较小的模型(小于 3MB),因为将内容上传到图形处理器的开销实际上比使用 WebGL 时在 CPU 上执行得更快。
  • CPU 执行 - 如果其他环境均不可用,则备用环境。这是三个速度中速度最慢的,但是您可以一直保持下去。

注意:如果您知道要在哪种设备上执行,则可以选择强制使用其中一个后端;如果您不指定,也可以直接让 TensorFlow.js 为您决定。

客户端超能力

在客户端计算机的网络浏览器中运行 TensorFlow.js 可带来诸多好处,值得考虑。

隐私权

您可以在客户端计算机上训练和对数据进行分类,而无需将数据发送到第三方网络服务器。有时,您可能需要遵守当地法律(例如 GDPR),或者在处理用户可能希望保留在其计算机上而不发送给第三方的任何数据时。

速度

由于您不必将数据发送到远程服务器,因此推断(数据分类)可以更快完成。更棒的是,您还可以直接访问设备的传感器,例如摄像头、麦克风、GPS、加速度计等(如果用户授予您访问权限)。

覆盖面和规模

世界上的任何人都可以点击您发送的链接,在浏览器中打开网页,然后利用您的成果。无需使用 CUDA 驱动程序进行复杂的服务器端 Linux 设置,只需使用机器学习系统即可。

费用

没有服务器意味着您只需为托管 HTML、CSS、JS 和模型文件的 CDN 付费。CDN 的成本比保持服务器(可能连接了显卡)全天候运行更便宜。

服务器端功能

利用 TensorFlow.js 的 Node.js 实现可启用以下功能。

全面支持 CUDA

在服务器端,对于显卡加速,您必须安装 NVIDIA CUDA 驱动程序,以使 TensorFlow 能够与显卡搭配使用(这与使用 WebGL 的浏览器不同,无需安装)。但是,有了全面的 CUDA 支持,您可以充分利用显卡较低级别的功能,从而缩短训练和推理时间。性能与 Python TensorFlow 实现相当,因为它们共享同一个 C++ 后端。

模型大小

对于研究中的尖端模型,您使用的模型可能非常大,也可能高达 GB。由于每个浏览器标签页的内存用量限制,这些模型目前无法在网络浏览器中运行。要运行这些较大的模型,您可以在自己的服务器上使用 Node.js,并满足高效运行此类模型所需的硬件规格。

IOT

Raspberry Pi 等热门单板计算机支持 Node.js,这也意味着您也可以在此类设备上执行 TensorFlow.js 模型。

速度

Node.js 是使用 JavaScript 编写的,这意味着它受益于即时编译。这意味着,在使用 Node.js 时,您通常可能会看到性能提升,因为它将在运行时进行优化,尤其是对于您可能正在进行的任何预处理。此案例研究展示了 Hugging Face 如何使用 Node.js 将自然语言处理模型的性能提升至原来的 2 倍。

现在,您已了解 TensorFlow.js 的基础知识、其运行位置以及一些优势,下面我们开始使用 TensorFlow.js 做一些有用的事吧!

3. 设置您的系统

在本教程中,我们将使用 Ubuntu。Ubuntu 是一种广为人知的 Linux 发行版,如果您选择在基于云的虚拟机上操作,那么 Ubuntu 可在 Google Cloud Compute Engine 上用作基础映像。

在撰写本文时,我们可以在创建新的 vanilla Compute Engine 实例时选择 Ubuntu 18.04.4 LTS 的映像,这就是我们将要使用的映像。您当然可以使用自己的计算机,如果您选择这样做,甚至可以使用其他操作系统,但安装说明和依赖关系可能会因系统而异。

安装 TensorFlow(Python 版本)

现在,您可能正尝试转换已经找到 / 或将要编写的一些基于 Python 的现有模型,因此,我们才能导出“SavedModel”文件,如果您的实例中有 “7d2”还不能下载。

通过 SSH 连接到您在上面创建的云端机器,然后在终端窗口中输入以下内容:

终端窗口

sudo apt update
sudo apt-get install python3

这样就可以确保我们在机器上安装了 Python 3。必须安装 Python 3.4 或更高版本才能使用 TensorFlow。

如需验证是否已安装正确的版本,请输入以下命令:

终端窗口

python3 --version

您应该会看到一些表示版本号的输出,例如 Python 3.6.9。如果您看到它正确输出了,且该值高于 3.4,则我们可以继续操作。

接下来,我们将安装适用于 Python 3 的 PIP(Python 的软件包管理器),然后对其进行更新。Type:

终端窗口

sudo apt install python3-pip
pip3 install --upgrade pip

同样,我们可以通过以下方式验证 pip3 安装:

终端窗口

pip3 --version

在写入时,我们发现在执行此命令后 pip 20.2.3 会输出到终端。

TensorFlow 需要 Python 软件包“setuptools”才能安装为 41.0.0 或更高版本。运行以下命令以确保将其更新到最新版本:

终端窗口

pip3 install -U setuptools

最后,我们现在可以安装 Python 版 TensorFlow:

终端窗口

pip3 install tensorflow

这可能需要一些时间才能完成,请等待其执行完成。

我们来检查 TensorFlow 是否已正确安装。在当前目录中创建一个名为 test.py 的 Python 文件:

终端窗口

nano test.py

nano 打开后,我们可以编写一些 Python 代码来输出已安装的 TensorFlow 版本:

test.py:

import tensorflow as tf
print(tf.__version__)

CTRL + O 将更改写入磁盘,然后按 CTRL + X 退出 nano 编辑器。

现在,我们可以运行这个 Python 文件来查看输出到屏幕上的 TensorFlow 版本:

终端窗口

python3 test.py

在编写之时,我们看到为安装的 TensorFlow Python 版本在控制台中输出了 2.3.1

4. 构建 Python 模型

此 Codelab 的下一步将介绍如何创建一个简单的 Python 模型,以说明如何将生成的经过训练的模型保存到“SavedModel”中。然后与我们的 TensorFlow.js 命令行转换器搭配使用。此原则与您尝试转换的任何 Python 模型都相似,但我们会让此代码保持简单,以便每个人都能理解。

修改一下在第一部分创建的 test.py 文件,并将代码更新为如下所示:

test.py:

import tensorflow as tf
print(tf.__version__)

# Import NumPy - package for working with arrays in Python.
import numpy as np

# Import useful keras functions - this is similar to the
# TensorFlow.js Layers API functionality.
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense

# Create a new dense layer with 1 unit, and input shape of [1].
layer0 = Dense(units=1, input_shape=[1])
model = Sequential([layer0])

# Compile the model using stochastic gradient descent as optimiser
# and the mean squared error loss function.
model.compile(optimizer='sgd', loss='mean_absolute_error')

# Provide some training data! Here we are using some fictional data 
# for house square footage and house price (which is simply 1000x the 
# square footage) which our model must learn for itself.
xs = np.array([800.0, 850.0, 900.0, 950.0, 980.0, 1000.0, 1050.0, 1075.0, 1100.0, 1150.0, 1200.0, 1250.0, 1300.0, 1400.0, 1500.0, 1600.0, 1700.0, 1800.0, 1900.0, 2000.0], dtype=float)

ys = np.array([800000.0, 850000.0, 900000.0, 950000.0, 980000.0, 1000000.0, 1050000.0, 1075000.0, 1100000.0, 1150000.0, 1200000.0,  1250000.0, 1300000.0, 1400000.0, 1500000.0, 1600000.0, 1700000.0, 1800000.0, 1900000.0, 2000000.0], dtype=float)

# Train the model for 500 epochs.
model.fit(xs, ys, epochs=500, verbose=0)

# Test the trained model on a test input value
print(model.predict([1200.0]))

# Save the model we just trained to the "SavedModel" format to the
# same directory our test.py file is located.
tf.saved_model.save(model, './')

此代码将训练一个非常简单的线性回归,以学习估算所提供的 x(输入)和 y(输出)之间的关系。然后,我们会将生成的经过训练的模型保存到磁盘。请查看内嵌注释,详细了解各行的用途。

如果我们在运行此程序后(通过调用 python3 test.py)检查目录,现在应该会看到在当前目录中创建的一些新文件和文件夹:

  • test.py
  • saved_model.pb
  • 资产
  • variables

现在,我们已生成了所需的文件,TensorFlow.js 转换器将使用这些模型转换模型以在浏览器中运行!

5. 将 SavedModel 转换为 TensorFlow.js 格式

安装 TensorFlow.js 转换器

如需安装转换器,请运行以下命令:

终端窗口

pip3 install tensorflowjs

很简单。

假设我们使用的是命令行转换器 (tensorflowjs_converter) 而不是上面显示的向导版本,我们可以调用以下命令来转换我们刚刚创建的已保存模型,并将参数显式传递给转换器:

终端窗口

tensorflowjs_converter \
    --input_format=keras_saved_model \
    ./ \
    ./predict_houses_tfjs

这是怎么回事?首先,我们调用刚刚安装的 tensorflowjs_converter 二进制文件,并指定我们尝试转换 keras 保存的模型。

在上面的示例代码中,您会发现我们导入了 Keras,并使用其更高级别的层 API 来创建模型。如果您尚未在 Python 代码中使用 keras,则可能需要使用其他输入格式:

  • keras - 加载 keras 格式(HDF5 文件类型)
  • tf_saved_model - 加载使用 TensorFlow Core API(而不是 keras)的模型。
  • tf_frozen_model - 加载包含冻结权重的模型。
  • tf_hub - 加载从 TensorFlow Hub 生成的模型。

您可以在此处详细了解这些其他格式

接下来的 2 个参数指定已保存的模型位于哪个文件夹。在上面的演示中,我们指定当前目录,最后指定要将转换输出到哪个目录,我们在上面指定了名为“predict_houses_tfjs”的文件夹当前目录中

运行以上命令会在当前目录中创建一个名为 predict_houses_tfjs 的新文件夹,其中包含 :

  • model.json
  • Group1-shard1of1.bin

这些文件是我们在网络浏览器中运行模型所需的文件。请保存这些文件,因为我们将在下一部分中使用它们。

6. 在浏览器中使用转换后的模型

托管转换的文件

首先,我们必须将生成的 model.json 文件和 *.bin 文件放置在网络服务器上,以便我们可以通过网页访问它们。在此演示中,我们将使用 Glitch.com,以便您轻松遵循。但是,如果您具有网络工程背景,可以选择在当前的 Ubuntu 服务器实例上启动一个简单的 http 服务器来执行此操作。一切由你决定。

将文件上传到 Glitch

  1. 登录 Glitch.com
  2. 使用此链接克隆我们的 TensorFlow.js 样板项目。此文件包含一个 html、css 和 js 框架文件,用于导入 TensorFlow.js 库供我们使用。
  3. 点击“素材资源”文件夹中找到
  4. 点击“上传素材资源”然后选择要上传到此文件夹中的 group1-shard1of1.bin。上传后,现在应如下所示:25a2251c7f165184
  5. 如果您点击刚刚上传的 group1-shard1of1.bin 文件,可以将网址复制到该文件的位置。现在复制此路径,如下所示:92ded8d46442c404
  6. 现在,在本地计算机上使用您惯用的文本编辑器修改 model.json,然后搜索(使用 CTRL+F)group1-shard1of1.bin 文件(该文件中会提到的某个地方)。

将此文件名替换为您从第 5 步中复制的网址,但删除从复制的路径中生成故障的前导 https://cdn.glitch.com/

修改后,其结果应如下所示(请注意,前置服务器路径被移除的方式只有这样,系统仅会保留生成的已上传文件名称):d5a338f2dc1f31d4.png 7.现在,点击素材资源,然后点击“上传素材资源”按钮,保存并上传这个经过修改的 model.json 文件,从而解决错误按钮(重要)。如果您不使用物理按钮,通过拖放操作,系统会将其作为可编辑文件上传,而不是上传到 CDN 上。当 TensorFlow.js 尝试下载给定模型的二进制文件时,CDN 不会位于同一文件夹,并且假定相对路径。如果操作正确,您应该会在 assets 文件夹中看到 2 个文件,如下所示:51a6dbd5d3097ffc.png

太棒了!现在,我们可以在浏览器中使用保存的文件以及一些实际代码了。

加载模型

现在我们已经托管了转换后的文件,接下来就可以编写一个简单的网页来加载这些文件并使用它们进行预测了。在 Glitch 项目文件夹中打开 script.js,然后将 const MODEL_URL 更改为指向为您在 Glitch 中上传的 model.json 文件生成的 Glitch.com 链接,然后将该文件的内容替换为以下内容:

script.js:

// Grab a reference to our status text element on the web page.
// Initially we print out the loaded version of TFJS.
const status = document.getElementById('status');
status.innerText = 'Loaded TensorFlow.js - version: ' + tf.version.tfjs;

// Specify location of our Model.json file we uploaded to the Glitch.com CDN.
const MODEL_URL = YOUR MODEL.JSON URL HERE! CHANGE THIS!';
// Specify a test value we wish to use in our prediction.
// Here we use 950, so we expect the result to be close to 950,000.
const TEST_VALUE = 950.0

// Create an asynchronous function.
async function run() {
    // Load the model from the CDN.
    const model = await tf.loadLayersModel(MODEL_URL);

    // Print out the architecture of the loaded model.
    // This is useful to see that it matches what we built in Python.
    console.log(model.summary());

    // Create a 1 dimensional tensor with our test value.
    const input = tf.tensor1d([TEST_VALUE]);

    // Actually make the prediction.
    const result = model.predict(input);

    // Grab the result of prediction using dataSync method
    // which ensures we do this synchronously.
    status.innerText = 'Input of ' + TEST_VALUE + 
        'sqft predicted as $' + result.dataSync()[0];
}

// Call our function to start the prediction!
run();

MODEL_URL 常量更改为指向 model.json 路径后,运行上述代码会生成如下所示的输出。

c5e8457213058ec3.png

如果我们检查网络浏览器的控制台(按 F12 可在浏览器中调出开发者工具),我们还可以看到已加载模型的模型说明,该模型会输出以下内容:

35e79d70dbd66f27

将其与此 Codelab 开头的 Python 代码进行比较,我们可以确认,这与我们使用 1 个密集输入和一个具有 1 个节点的密集层创建的网络相同。

恭喜!您刚刚在网络浏览器中运行了一个经过转换的 Python 训练模型!

7. 不会完成转化的模型

有时,转换将不支持编译为使用不太常见的运算的更复杂的模型。基于浏览器的 TensorFlow.js 版本完全重写了 TensorFlow,因此,我们目前不支持 TensorFlow C++ API 的所有低级别操作(有 1000 个),但随着时间的推移,随着我们发展和核心操作变得更加稳定,我们会添加更多操作。

在撰写本文时,TensorFlow Python 中有这样一个在导出为 savedmodel 时生成不受支持的操作的函数是 linalg.diag。如果我们尝试转换在 Python 中使用它的已保存模型(它确实支持其生成的操作),您将看到类似于如下所示的错误:

5df94fc652393e00

在这里,我们可以看到以红色突出显示,linalg.diag 调用经过编译以生成一个名为 MatrixDiagV3 的操作,在编写此 Codelab 时,TensorFlow.js 在网络浏览器中不支持该操作。

解决办法

您可以使用以下两种方法。

  1. 在 TensorFlow.js 中实现这个缺失的操作 - 我们是一个开源项目,欢迎为新操作等项目贡献代码。查看这份指南,了解如何为 TensorFlow.js 编写新操作。如果您确实做到了这一点,则可以使用命令行转换器上的 Skip_op_check 标志来忽略此错误,然后以任何方式继续进行转换(这会假定此操作在您创建的新 build 的 TensorFlow.js build 中提供,且支持缺少的操作)。
  2. 确定在您导出的 savedmodel 文件中,Python 代码的哪个部分产生了不受支持的操作。在一小部分代码中,这可能很容易找到,但在更复杂的模型中,可能需要进行大量调查,因为目前没有方法可以识别以 savedmodel 文件格式生成一次指定操作的高级 Python 函数调用。不过,您可以在找到后将其更改为使用其他受支持的方法。

8. 恭喜

恭喜,您已迈出在网络浏览器中通过 TensorFlow.js 使用 Python 模型的第一步!

回顾

在此 Codelab 中,我们学习了如何执行以下操作:

  1. 设置 Linux 环境以安装基于 Python 的 TensorFlow
  2. 导出 Python“SavedModel”
  3. 安装 TensorFlow.js 命令行转换器
  4. 使用 TensorFlow.js 命令行转换器创建所需的客户端文件
  5. 在实际 Web 应用中使用生成的文件
  6. 确定不会转换的模型,以及需要实现哪些模型才能在将来转换。

后续操作

请记得使用 #MadeWithTFJS 标签在您创作的任何内容中标记我们,以便有机会在社交媒体上获得特别推荐,甚至在未来的 TensorFlow 活动中进行展示。我们很想查看你转换的内容,并在浏览器中使用客户端!

更多要深入学习的 TensorFlow.js Codelab

可以结账的网站