Tensorflow C API 从训练到部署:使用 C API 进行预测和部署

前述博文 Tensorflow C++ 从训练到部署(2):简单图的保存、读取与 CMake 编译Tensorflow C++ 从训练到部署(3):使用 Keras 训练和部署 CNN 使用 Tensorflow/Keras 的 Python API 进行训练,并使用 C++ API 进行了预测。由于 C++ API 需要编译 Tensorflow 源码,还是比较麻烦的。而 Tensorflow 官方提供了 C API 编译好的库文件,相对部署上比较容易(直接复制库文件到自己的工程即可),本文将介绍使用 C API 进行预测的方法。对于 Python 训练部分,与前述文章相同不做赘述。

0、系统环境
Ubuntu 16.04
Tensorflow 1.12.0

1、安装依赖
1、GPU 支持安装(可选)
CUDA 9.0
cnDNN 7.x

2、Tensorflow 1.12.0
下载地址:
https://www.tensorflow.org/install/lang_c

其中 1.12.0 的下载地址如下(我这里提供了包含TX2 aarch64在内的几个版本):

TensorFlow C library CUDA cuDNN URL
Linux x86_64 CPU x x https://pan.baidu.com/s/1FDdXCgtJJlDJP8ziDs6dow
Linux x86_64 GPU 9.0 7.x https://pan.baidu.com/s/1qxDntkQ-rcgvp1xxrSKW0w
macOS CPU x x https://pan.baidu.com/s/1F6NdNtCxg11P_EpEdsqttA
Linux aarch64 GPU (TX2) 9.0 7.0.5 https://pan.baidu.com/s/1mI76203wY9Nd5US4sH5-pg

将库解压到 third_party/libtensorflow 目录。

如果上面的版本都不符合你的需求,你可以参照这篇文章编译你需要的版本。

2、TFUtils 工具类
为了简便起见,我们首先将常用的 C API 封装为

1)文件 utils/TFUtils.hpp:

2)文件 utils/TFUtils.cpp:

3、简单图的读取与预测
在前述文章 Tensorflow C++ 从训练到部署(2):简单图的保存、读取与 CMake 编译 中我们已经介绍了一个 c=a*b 的简单“网络”是如何计算的。

其中 Python 构建网络和预测部分就不重复了,详见该文所述。这里直接给出 C API 的代码:

文件名:simple/load_simple_net_c_api.cc

简单解释一下:

这一行是加载 pb 文件。

这一段是创建两个输入 tensor 以及输入的 ops。注意这里的 CreateTensor 在后面都需要调用 DeleteTensors 进行内存释放。输出的 tensors 还没创建先定义为 nullptr。

这一行是运行网络。

这两行是从输出的 output_tensors 读取数据到一个二维vector const std::vector>,我们这里输出只有 “c” 一个名字,而且只有一个索引 0,因此直接取出 data[0] 就是我们原本想要的输出。

编译运行这一文件,如果没有问题则会得到如下输出:

4、CNN的读取与预测
与刚才小节3相似,CNN网络也是一样的流程,还是以最基本的 fashion_mnist 为例,该网络的训练和保存流程请参考之前的文章。这里我们仅介绍 C API 进行预测的部分。由于我们这里需要读取一幅图并转化成 Tensor 输入网络,我们构造一个简单的函数 Mat2Tensor 实现这一转换:

1)Met2Tensor 部分文件:fashion_mnist/utils/mat2tensor_c_cpi.h

2)网络读取与预测,这部分与刚才的小节3基本一样,就不做解释了:

编译运行这一文件,如果没有问题,则会得到如下输出:

到此,我们就完成了使用 C API 运行 Tensorflow Model 的流程。

本文中的全部代码均已开源:
https://github.com/skylook/tensorflow_cpp

参考文献
[1] https://github.com/Neargye/hello_tf_c_api
[2] https://www.tensorflow.org/api_docs/python/tf/contrib/saved_model/save_keras_model
[3] https://www.tensorflow.org/install/lang_c

Posted in tensorflow | Leave a comment

[TX2] Tensorflow 1.12.0 在 Jetson TX2 上的编译

系统环境
Ubuntu 16.04
Jetpack 3.2.1 on TX2 [Link](with CUDA 9.0 cuDNN 7.0.5)

1、编译准备
1)配置环境

2)安装依赖
Java

Bazel (Tensorflow 使用 Bazel 0.15 编译,因此这里下载 0.15.2 版本,详情参见这里)

2、编译 Tensorflow
1)下载源码
运行如下命令下载 tensorflow 1.12.0 版本源码:

2)修改源码
为了在 TX2 上编译通过,需要 apply this patch
具体说明如下:

2.1)打开文件:tensorflow-1.12.0/tensorflow/contrib/lite/kernels/internal/BUILD
查找:

修改成:

2.2)打开文件:tensorflow-1.12.0/third_party/aws.BUILD
查找:

修改成:

3)编译配置

其中会提示若干选项,请参考如下进行选择:

3)编译
由于 TX2 上面内存只有 8G,因此编译 C Lib 时需要限制内存使用不超过8G,如果直接按照官方的方式是会报错的,当然你也可以设置 swap 来解决。我这里直接设置为4G,你可以根据需要进行调整,但是最好不要超过8G:

这一过程大约需要5、6个小时,如果最后提示编译成功,则会在如下目录生成 libtensorflow.tar.gz 文件
bazel-bin/tensorflow/tools/lib_package/libtensorflow.tar.gz

至此就完成了 TX2 上 Tensorflow 版本的编译。

下面是包含 TX2 在内的几个常用 Tensorflow C Lib 地址,不想编译的直接下载我这里的网盘文件即可:

TensorFlow C library CUDA cuDNN URL
Linux x86_64 CPU x x https://pan.baidu.com/s/1FDdXCgtJJlDJP8ziDs6dow
Linux x86_64 GPU 9.0 7.x https://pan.baidu.com/s/1qxDntkQ-rcgvp1xxrSKW0w
macOS CPU x x https://pan.baidu.com/s/1F6NdNtCxg11P_EpEdsqttA
Linux aarch64 GPU (TX2) 9.0 7.0.5 https://pan.baidu.com/s/1mI76203wY9Nd5US4sH5-pg

参考文献
[1] https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/lib_package/README.md
[2] https://jkjung-avt.github.io/build-tensorflow-1.8.0/
[3] https://github.com/peterlee0127/tensorflow-nvJetson

Posted in tensorflow | Leave a comment

Deep Local Feature 文章 & 数据收集

在 SLAM 中 Local Feature 的提取和匹配是一个比较重要的内容,近些年有很多相关的使用 Deep Learning 学习局部描述子的工作,这里做一下相关文章和代码收集。后续如有精力会进行速度和性能比较。

文章收集

文章 会议 PDF 代码
GeoDesc: Learning Local Descriptors by Integrating Geometry Constraints ECCV 2018 PDF Code
DELF: DEep Local Features CVPR 2018 PDF Code
LF-Net: Learning Local Features from Images NIPS 2018 PDF Code
AffNet: Repeatability Is Not Enough: Learning Discriminative Affine Regions via Discriminability ECCV 2018 PDF Code
SuperPoint: Self-Supervised Interest Point Detection and Description CVPR 2018 PDF Code
DeepCD: Learning Deep Complementary Descriptors for Patch Representations ICCV 2017 PDF Code
HardNet: Working hard to know your neighbor’s margins: Local descriptor learning loss NIPS 2017 PDF Code
TFeat: shallow convolutional patch descriptor BMVC 2016 PDF Code
LIFT: Learned Invariant Feature Transform ECCV 2016 PDF Code

数据收集

数据集名称 下载地址
Phototour http://phototour.cs.washington.edu/patches/default.htm
HPatches https://github.com/hpatches/hpatches-dataset

Posted in CNN | Leave a comment

Tensorflow C++ 从训练到部署(3):使用 Keras 训练和部署 CNN

在上一篇文章中我们并没有去训练一个真正的网络和解决一个实际问题,我们所做的是构建了一个 c = a * b 的计算图,并用 python 进行了保存和 c++ 进行了读取,这一保存和读取中也仅包含图的结构并没有相关参数。本篇文章中我们进一步以 Tensorflow 官方的 Fashion MNIST 为例,完成一个简单的分类问题。本文前面 Keras 训练模型以及转化到 Tensorflow 格式部分与之前一篇博客(Keras 转换成 Tensorflow 模型格式并使用)基本一致。本文主要包含:
1)Python:Fashion MNIST 数据集
2)Python:使用 Keras 定义 CNN 模型、训练并保存
3)Python:转换 Keras 模型到 Tensorflow 格式并保存
4)Python:使用 Tensorflow Python API 加载模型并预测
5)C++:使用 Tensorflow C++ API 加载模型并预测

0、系统环境
Ubuntu 16.04
Tensorflow 1.12.0 (安装详见官网,本文环境使用 pip 方式安装)

1、Fashion MNIST 数据集
1)数据简介
Fashion-MNIST [1] 是一个替代MNIST手写数字集的图像数据集。 它是由Zalando(一家德国的时尚科技公司)旗下的研究部门提供。其涵盖了来自10种类别的共7万个不同商品的正面图片。Fashion-MNIST的大小、格式和训练集/测试集划分与原始的MNIST完全一致。60000/10000的训练测试数据划分,28×28的灰度图片。你可以直接用它来测试你的机器学习和深度学习算法性能,且不需要改动任何的代码 [11]。

典型的 Fashion-MNITST 数据是这样的,其中每三行表示一个类别:
fashion-mnist-sprite

Fashion-MNIST 与 MNIST 同样有 10 个类别,不过并不是 0-9 的 10 个数字,它的类别如下:

screenshot-from-2018-09-25-11-50-54

我们使用过以前的 MNIST 数据集都知道,随便弄个很简单的网络,就可以轻轻松松刷出 99% 以上的分数了,即使传统方法也很容易达到高分。所以 MNIST 手写数字识别由于过于简单,作为一个基本的实验数据已经没有什么意义了。Tensorflow 和很多深度学习框架现在的入门数据也都推荐 Fashion MNIST。

2)数据读取
其实 Keras 为我们提供了简单的接口可以一键下载 Fashion-MNIST 数据并且读取:

不过由于天朝网络的原因,我并不推荐这种方式,建议直接下载到本地读取。我这里将数据直接存到 data/fashion 目录下。
百度网盘下载:
https://pan.baidu.com/s/19zZqU5tSwZyY780z8Y8_VA

读取数据代码如下(保存为:utils/mnist_reader.py):

2、使用 Keras 定义 CNN 模型、训练并保存
下面的代码中我们定义了一个非常简单的 CNN 网络,结构图如下:
model

我们使用这一网络进行训练并且保存为 Keras 标准的 h5 格式。这一部分代码比较基础,就不做过多解释了。

Keras 模型定义和训练代码如下(保存为:train.py):

如果你的运行没有问题则会看到类似如下输出:

同时在 models/ 文件夹下保存了 fashion_mnist.h5 文件,这一文件包含了模型的结构和参数。

3、转换 Keras 模型到 Tensorflow 格式并保存
这一环节我们使用 keras_to_tensorflow [2] 转换工具进行模型转换,其实这个工具原理很简单,首先用 Keras 读取 .h5 模型文件,然后用 tensorflow 的 convert_variables_to_constants 函数将所有变量转换成常量,最后再 write_graph 就是一个包含了网络以及参数值的 .pb 文件了。

具体代码参见(原始代码中可以传入输出 node 数量和名字并使用 identity 生成新的 tensor,我这里稍作修改,直接读取 Keras 的 outputs 的操作名,最后会输出原始 inputs 和 outputs 的名字供后面使用):

Tensorflow 模型转换代码(保存为:utils/keras_to_tensorflow.py)

我们执行如下命令转换 Keras 模型到 Tensorflow 的 pb 格式:

如果你的运行无误的话则会显示如下信息并生成 models/fashion_mnist.h5.pb 这个就是转换过来的 Tensorflow 格式:

这里面也告知了你模型输入和输出的 Tensor 名字,这两个信息很重要我们后面会用到。

4、使用 Tensorflow Python API 加载模型并预测
我们使用标准的 Tensorflow Low-Level API 加载和预测代码如下(保存为:load_predict.py)

这段代码中前面同样是读取 Fashion MNIST 数据集,与训练代码一样。部分代码说明如下:

读取 pb 模型文件:

获取当前的计算图:

获取输出的 Tensor:

可以看到除了之前我们给出的输出 Tensor 名称 output_class/Softmax 外,我们还需要加上一个索引 :0。关于这一问题的解释可以参见 [12]。我们这里简单来理解,”output_class/Softmax” 是指定了一个 Operation 的名字,对应最后 Softmax 层,大部分层的输出都是一个 Tensor,不过也有可能一个层产生多个输出 Tensor,因此我们这里需要指定是哪个输出。通常对于一个输出的时候就是用 :0 指定,对于 Input 也是同理。

执行计算图并打印输出结果,其中 feed_dict={‘input_image_input:0’: test_images} 将 test_images 作为输入传入网络:

执行整个代码:

如果运行没有问题则可以看到如下结果:

与之前我们使用 Keras 的 predict 接口结果对比,是一样的,说明我们转换后的模型无误。

关于 Keras 转换成 Tensorflow 模型和预测的步骤就到这里。完整示例可以参见:
https://github.com/skylook/tensorflow_cpp

5、使用 Tensorflow C++ API 加载模型并预测
1)使用 C++ 转换 OpenCV 的 Mat 到 Tensor
Tensor 要求输入的是归一化的 float32 格式图片,实际我们使用如下代码来完成 OpenCV Mat 到 Tensor 的转换(保存为:utils/mat2tensor.h)

这段代码比较简单,就是声明一个 {1, img.size().height, img.size().width, img.channels()} 的单个 Tensor,将地址直接赋给 fake_mat,然后使用 OpenCV 把图片转成 float32 格式,声明的 Tensor 自然也就转成了 float32 格式。最后是根据输入 normal 因子进行归一化。这一归一化方法和之前训练时一致。

2)使用 C++ 调用 pb 模型并预测
与前面的文章类似,我们参考 Python 调用 pb 模型及预测接口使用 C++ API 调用之前转换的模型并预测代码如下(保存为:load_predict.cpp):

如果编译运行没有问题的话,会输出如下结果:

输入和调用模型与之前的博客基本一致,这里解释下输出部分:

这里 flat_inner_dims 的 API 官方说明如下:
screenshot-from-2018-10-15-18-57-02

表示将按照指定类型 T 和指定维度 NDIMS 的 Eigen::TensorMap 输出,需要说明的是这一 T 和 NDMS 维度必须与模型中实际输出类型一致,否则运行时会报错。TensorMap 相当于 Tensor 的一个引用,其内存地址并不像 Tensor 一样是自己创建与释放的,因此没有 resize 等操作,其他使用方法与 Tensor 类似。关于 Eigen::Tensor 使用说明参见 [6] 和 [7]。

其中 tensorflow::TTypes::Tensor 与 Eigen::TensorMap, Eigen::Aligned> 其实是等价的,因此上面那一行也可以替换成:

到这里我们就完整介绍了一个 CNN 网络从 Keras 训练、转成 Tensorflow 格式到 C++ 部署的基本流程。

本文完整代码参见 Github:
https://github.com/skylook/tensorflow_cpp

参考文献
[1] https://www.tensorflow.org/tutorials/keras/basic_classification
[2] https://medium.com/tensorflow/hello-deep-learning-fashion-mnist-with-keras-50fcff8cd74a
[3] https://github.com/zalandoresearch/fashion-mnist
[4] https://zhuanlan.zhihu.com/p/30985013
[5] https://github.com/ADozois/proc_deep_detector
[6] http://eigen.tuxfamily.org/index.php?title=Tensor_support
[7] https://github.com/PX4/eigen/blob/master/unsupported/Eigen/CXX11/src/Tensor/README.md
[8] https://www.tensorflow.org/api_docs/cc/class/tensorflow/tensor

Tensorflow C++ 从训练到部署系列文章目录

Tensorflow C++ 从训练到部署(3):使用 Keras 训练和部署 CNN
Tensorflow C++ 从训练到部署(2):简单图的保存、读取与 CMake 编译
Tensorflow C++ 从训练到部署(1):环境搭建

Posted in tensorflow | Leave a comment

Keras 转换成 Tensorflow 模型格式并使用

Tensorflow 官方已经集成了 Keras 作为自己推荐的 High-Level API,Keras 的确使用非常方便,而且代码美观简洁,不像 Tensorflow 那样有很多形式化的代码。对于我们进行快速原型和实验是非常有帮助的。然而在一些场合我们可能需要混合使用 Keras 和 Tensorflow 定义模型或者保存模型的操作,这时就需要一些转换了。

系统环境
Ubuntu 16.04
Tensorflow 1.10.1 (内置:Keras 2.1.6-tf)

1、Fashion MNIST 数据集
1)数据简介
Fashion-MNIST [1] 是一个替代MNIST手写数字集的图像数据集。 它是由Zalando(一家德国的时尚科技公司)旗下的研究部门提供。其涵盖了来自10种类别的共7万个不同商品的正面图片。Fashion-MNIST的大小、格式和训练集/测试集划分与原始的MNIST完全一致。60000/10000的训练测试数据划分,28×28的灰度图片。你可以直接用它来测试你的机器学习和深度学习算法性能,且不需要改动任何的代码 [11]。

典型的 Fashion-MNITST 数据是这样的,其中每三行表示一个类别:
fashion-mnist-sprite

Fashion-MNIST 与 MNIST 同样有 10 个类别,不过并不是 0-9 的 10 个数字,它的类别如下:

screenshot-from-2018-09-25-11-50-54

我们使用过以前的 MNIST 数据集都知道,随便弄个很简单的网络,就可以轻轻松松刷出 99% 以上的分数了,即使传统方法也很容易达到高分。所以 MNIST 手写数字识别由于过于简单,作为一个基本的实验数据已经没有什么意义了。Tensorflow 和很多深度学习框架现在的入门数据也都推荐 Fashion MNIST。

2)数据读取
其实 Keras 为我们提供了简单的接口可以一键下载 Fashion-MNIST 数据并且读取:

不过由于天朝网络的原因,我并不推荐这种方式,建议直接下载到本地读取。我这里将数据直接存到 data/fashion 目录下。
百度网盘下载:
https://pan.baidu.com/s/19zZqU5tSwZyY780z8Y8_VA

读取数据代码如下(保存为:utils/mnist_reader.py):

2、使用 Keras 定义 CNN 模型并保存
下面的代码中我们定义了一个非常简单的 CNN 网络,结构图如下:
model

我们使用这一网络进行训练并且保存为 Keras 标准的 h5 格式。这一部分代码比较基础,就不做过多解释了。

Keras 模型定义和训练代码如下(保存为:train.py):

如果你的运行没有问题则会看到类似如下输出:

同时在 models/ 文件夹下保存了 fashion_mnist.h5 文件,这一文件包含了模型的结构和参数。

3、转换 Keras 模型到 Tensorflow 格式并保存
这一环节我们使用 keras_to_tensorflow [2] 转换工具进行模型转换,其实这个工具原理很简单,首先用 Keras 读取 .h5 模型文件,然后用 tensorflow 的 convert_variables_to_constants 函数将所有变量转换成常量,最后再 write_graph 就是一个包含了网络以及参数值的 .pb 文件了。

具体代码参见(原始代码中可以传入输出 node 数量和名字并使用 identity 生成新的 tensor,我这里稍作修改,直接读取 Keras 的 outputs 的操作名,最后会输出原始 inputs 和 outputs 的名字供后面使用):

Tensorflow 模型转换代码(保存为:utils/keras_to_tensorflow.py)

我们执行如下命令转换 Keras 模型到 Tensorflow 的 pb 格式:

如果你的运行无误的话则会显示如下信息并生成 models/fashion_mnist.h5.pb 这个就是转换过来的 Tensorflow 格式:

这里面也告知了你模型输入和输出的 Tensor 名字,这两个信息很重要我们后面会用到。

4、使用 Tensorflow 加载模型并预测
我们使用标准的 Tensorflow Low-Level API 加载和预测代码如下(保存为:load_predict.py)

这段代码中前面同样是读取 Fashion MNIST 数据集,与训练代码一样。部分代码说明如下:

读取 pb 模型文件:

获取当前的计算图:

获取输出的 Tensor:

可以看到除了之前我们给出的输出 Tensor 名称 output_class/Softmax 外,我们还需要加上一个索引 :0。关于这一问题的解释可以参见 [12]。我们这里简单来理解,”output_class/Softmax” 是指定了一个 Operation 的名字,对应最后 Softmax 层,大部分层的输出都是一个 Tensor,不过也有可能一个层产生多个输出 Tensor,因此我们这里需要指定是哪个输出。通常对于一个输出的时候就是用 :0 指定,对于 Input 也是同理。

执行计算图并打印输出结果,其中 feed_dict={‘input_image_input:0’: test_images} 将 test_images 作为输入传入网络:

执行整个代码:

如果运行没有问题则可以看到如下结果:

与之前我们使用 Keras 的 predict 接口结果对比,是一样的,说明我们转换后的模型无误。

关于 Keras 转换成 Tensorflow 模型和预测的步骤就到这里。完整示例可以参见:
https://github.com/skylook/tensorflow_cpp

常见问题
1、错误: This could mean that the variable was uninitialized.

这通常是由于训练模型后直接进行保存的缘故。解决方法是重新声明一个 model 类型加载 keras 模型与参数。

2、错误:OSError: Unable to open file (unable to lock file, errno = 37, error message = ‘
No locks available’)
如果你使用 Keras 保存模型到 h5 时遇到如下问题:

这一问题通常是由于在 NFS 文件系统中的问题,建议在命令行配置系统变量或者假如 ~/.bashrc 文件:

3、错误:Tensor names must be of the form “:
如果你的代码遇到如下错误:

解决方法是在你调用 Tensor 时加入索引,例如 :0。详情请见 [12]。

参考文献
[1] https://blog.keras.io/keras-as-a-simplified-interface-to-tensorflow-tutorial.html
[2] https://github.com/amir-abdi/keras_to_tensorflow
[3] https://towardsdatascience.com/freezing-a-keras-model-c2e26cb84a38
[4] https://medium.com/@brianalois/simple-keras-trained-model-export-for-tensorflow-serving-23fa5dfeeecc
[5] https://blog.metaflow.fr/tensorflow-how-to-freeze-a-model-and-serve-it-with-a-python-api-d4f3596b3adc
[6] https://github.com/BerkeleyGW/hdf5_bug
[7] https://github.com/h5py/h5py/issues/1082#issuecomment-414291188
[8] https://github.com/amir-abdi/keras_to_tensorflow
[9] https://www.tensorflow.org/tutorials/keras/save_and_restore_models
[10] https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/graph_transforms/README.md#quantize_weights
[11] https://github.com/zalandoresearch/fashion-mnist/blob/master/README.zh-CN.md
[12] https://stackoverflow.com/questions/37849322/how-to-understand-the-term-tensor-in-tensorflow/37870634#37870634

Posted in tensorflow | Leave a comment

Tensorflow C++ 从训练到部署(2):简单图的保存、读取与 CMake 编译

经过了 上一篇文章,我们已经成功编译了 tensorflow c++ 的系统库文件并且安装到系统目录下了。这里我们将使用这个编译好的库进行基本的 C++ 模型加载执行等操作。
注意,在本篇文章会使用 Tensorflow 的 Python API,因为比较简单,这里不做介绍,安装详见官网教程:
https://www.tensorflow.org/install/

0、系统环境
Ubuntu 16.04
Tensorflow 1.10.1 (安装详见官网,建议使用 pip 方式安装)

1、一个简单网络的保存
只有 c = a * b 的网络:

在这段代码中,我们构建了一个非常简单的“网络”:
\(c = a * b\)
并且给 a 和 b 赋予了初值。这一网络虽然简单,但是更复杂的网络也是类似的道理,我们需要保存的无非是计算图的结构,和图中的参数。这里边我们 tf.train.write_graph 保存的仅仅是图的结构。注意其中每个 placeholder 的 name 非常重要,这是我们后面输入和获取这些值的基础。

在这一例子中,有两点注意:
a)tf.train.write_graph 函数就是指定了保存图的路径,as_text=False 表明用二进制格式保存(默认是文本格式保存)。
b)res = sess.run(c, feed_dict={‘a:0’: 2.0, ‘b:0’: 3.0}) 中,我们定义的 placeholder 的名字是 a 和 b,但是对于 tensorflow 来说 shape=None 的相当于一个 1×1 的向量,所以我们还是要指定一个下标表示 a 和 b 是这个向量的第一个元素,这里 tensorflow 用 a:0 和 b:0 表示。如果 a 和 b 本来就是一个多维向量,那么可以直接取出整个向量。

我们将这段代码保存为 simple/simple_net.py 文件并执行:

正常情况下会在 model 文件夹下保存一个 simple.pb 的文件,并且输出一个测试运行的结果:
res = 6.0

PS:你也可以指定为文本格式保存,通常文本格式我们保存为 .pbtxt 后缀,例如:

保存出来就是这样的,看起来很简单,不过通常我们还是用二进制格式比较高效:

2、使用 Python 读取这个网络
首先我们来看下用 Python 如何读取这个网络并进行计算: