<commit_before>---
layout: post
title: "Tensorflow C++ 使用指南"
modified:
categories:
excerpt:
tags: [tensorflow,deep learning]
comments: true
author: xiexiaobo
image:
feature: sample-image-3.jpg
date: 2016-12-21T23:36:36+08:00
---
### 背景介绍
[Tensorflow](https://www.tensorflow.org)是谷歌开源的一款深度学习框架，支持分布式训练和多GPU训练。虽然其开源时间比Theano和Torch等深度学习框架更晚，但是因为有Google的强大支持和其在开源社区强大的影响力，Tensorflow迅速流行，目前已有大量使用Tensorflow实现的论文代码和经典模型。从个人的使用经验来说，使用Torch进行快速原型实验以及调试相对来说方法一些，因此相对来说更适合做纯研究的人使用。而Tensorflow在研究和应用两个方面相对来说平衡一些，不仅因为Tensorflow支持分布式的训练和多GPU，而且还提供了生产级别的高性能服务框架[Tensorflow Serving](https://tensorflow.github.io/serving/)，方便模型快速部署到生产环境。

如果你还不熟悉Tensorflow的基本使用，可以先学习下Tensorflow官网的[教程](https://www.tensorflow.org/versions/r0.11/tutorials/index.html)或者参考Github上的一些[教程](https://github.com/AlbertXiebnu/TF-Tutorials)。这篇文章主要是想介绍如何
把训练好的模型应用在生产环境中，我将会以一个实际的例子来说明整个过程以及中间的一些坑，希望可以给大家提供一个简单的参考。

> 为了方便大家学习和参考，文章中所有的代码都放在我的github项目中 [tf_han](https://github.com/AlbertXiebnu/tf_han)

在实际的使用过程中，最常见的一个生产流程是用Tensorflow的python脚本来进行算法实验和模型的训练，当模型的效果调整到最优后，我们希望可以把调优后的模型部署到实际的生产环境中。完成这个过程，一般来说有两种方式，第一种可以采用上文提到了Tensorflow Serving的方式，把模型的预测以服务的方式提供，客户端提供rpc调用的方式来获取预测结果。另一种方式是以动态链接库的方式提供，把模型的预测封装成.so文件，客户端可以直接把预测进行代码层面的集成。其中第一种方式提供了对模型生命周期的管理，模型切换以及机群和GPU的支持等，可以做到方便地从模型生成（训练）到模型部署（提供服务）这一流程。我觉得这种部署方式效率非常高，可以优先考虑。不过，因为在工作中，需要和现有的代码做集成，我主要尝试了第二种方法，下面将着重介绍。


### 创建模型
事实上，Tensorflow提供了两种打包动态链接库的方式。一种方式是只打包Tensorflow核心代码，生成tensorflow.so文件，然后客户端代码通过调用Tensorflow提供的[c api](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h)来使用。另一种方式就是直接调用Tensorflow的c++代码，然后和模型预测代码一起封装并打包成动态链接库，提供给外部接口来调用。第一种方法计划在下一篇文章中解释，这里主要讲下第二种方法。大体分为三个步骤：
1. 创建模型。用Tensorflow Python接口创建Graph，并训练和保存Graph和模型参数。
2. 生成动态链接库。利用Tensorflow c++ api来完成模型的加载，并对外提供预测接口。
3. 使用动态链接库。直接引用接口文件，在链接时链接第2步生成的动态链接库。

首先，第一步我们先定义模型。假设我们的应用场景是做文本分类，首先我们先定义一个层次LSTM的文本分类模型。模型的输入是文章的词序列，输出是文章的类别，即label。我们先看下模型的输入是如何定义的。
```python
x = tf.placeholder("int32",[None,FLAGS.max_sen,FLAGS.max_len],name="input")
y = tf.placeholder("float32",[None,n_classes],name="target")
keep_prob = tf.placeholder(tf.float32,name="keep_prob")
```
上面的代码中 *x* 表示模型的输入，为文章的词序列，每个词用词典的下标表示。*y* 表示文章的label，取值为0或1。*keep_prob* 为dropout层的参数。注意到我们为模型的每个输入结点进行了命名，这个命名在用 *c++ api* 加载模型是将会用到。模型的具体定义可以参考 [*model.py*](https://github.com/AlbertXiebnu/tf_han/blob/master/model.py)，太长了就不贴出来了。注意到，和模型输入一样，模型最后的输出结点同样进行了命名，命名为*output*。
```python
W = tf.get_variable("fullconnect_weights",shape=[2 * self.docsize,n_classes])<commit_msg>fix:tensorflow<commit_after>---
layout: post
title: "Tensorflow C++ 使用指南"
modified:
categories:
excerpt:
tags: []
comments: true
author: xiexiaobo
image:
feature: sample-image-2.jpg
date: 2016-12-21T13:36:36+08:00
---

### 背景介绍

[Tensorflow](https://www.tensorflow.org)是谷歌开源的一款深度学习框架，支持分布式训练和多GPU训练。虽然其开源时间比Theano和Torch等深度学习框架更晚，但是因为有Google的强大支持和其在开源社区强大的影响力，Tensorflow迅速流行，目前已有大量使用Tensorflow实现的论文代码和经典模型。从个人的使用经验来说，使用Torch进行快速原型实验以及调试相对来说方法一些，因此相对来说更适合做纯研究的人使用。而Tensorflow在研究和应用两个方面相对来说平衡一些，不仅因为Tensorflow支持分布式的训练和多GPU，而且还提供了生产级别的高性能服务框架[Tensorflow Serving](https://tensorflow.github.io/serving/)，方便模型快速部署到生产环境。

如果你还不熟悉Tensorflow的基本使用，可以先学习下Tensorflow官网的[教程](https://www.tensorflow.org/versions/r0.11/tutorials/index.html)或者参考Github上的一些[教程](https://github.com/AlbertXiebnu/TF-Tutorials)。这篇文章主要是想介绍如何
把训练好的模型应用在生产环境中，我将会以一个实际的例子来说明整个过程以及中间的一些坑，希望可以给大家提供一个简单的参考。

> 为了方便大家学习和参考，文章中所有的代码都放在我的github项目中 [tf_han](https://github.com/AlbertXiebnu/tf_han)

在实际的使用过程中，最常见的一个生产流程是用Tensorflow的python脚本来进行算法实验和模型的训练，当模型的效果调整到最优后，我们希望可以把调优后的模型部署到实际的生产环境中。完成这个过程，一般来说有两种方式，第一种可以采用上文提到了Tensorflow Serving的方式，把模型的预测以服务的方式提供，客户端提供rpc调用的方式来获取预测结果。另一种方式是以动态链接库的方式提供，把模型的预测封装成.so文件，客户端可以直接把预测进行代码层面的集成。其中第一种方式提供了对模型生命周期的管理，模型切换以及机群和GPU的支持等，可以做到方便地从模型生成（训练）到模型部署（提供服务）这一流程。我觉得这种部署方式效率非常高，可以优先考虑。不过，因为在工作中，需要和现有的代码做集成，我主要尝试了第二种方法，下面将着重介绍。


### 创建模型
事实上，Tensorflow提供了两种打包动态链接库的方式。一种方式是只打包Tensorflow核心代码，生成tensorflow.so文件，然后客户端代码通过调用Tensorflow提供的[c api](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h)来使用。另一种方式就是直接调用Tensorflow的c++代码，然后和模型预测代码一起封装并打包成动态链接库，提供给外部接口来调用。第一种方法计划在下一篇文章中解释，这里主要讲下第二种方法。大体分为三个步骤：
1. 创建模型。用Tensorflow Python接口创建Graph，并训练和保存Graph和模型参数。
2. 生成动态链接库。利用Tensorflow c++ api来完成模型的加载，并对外提供预测接口。
3. 使用动态链接库。直接引用接口文件，在链接时链接第2步生成的动态链接库。

首先，第一步我们先定义模型。假设我们的应用场景是做文本分类，首先我们先定义一个层次LSTM的文本分类模型。模型的输入是文章的词序列，输出是文章的类别，即label。我们先看下模型的输入是如何定义的。
```python
x = tf.placeholder("int32",[None,FLAGS.max_sen,FLAGS.max_len],name="input")
y = tf.placeholder("float32",[None,n_classes],name="target")
keep_prob = tf.placeholder(tf.float32,name="keep_prob")
```
上面的代码中 *x* 表示模型的输入，为文章的词序列，每个词用词典的下标表示。*y* 表示文章的label，取值为0或1。*keep_prob* 为dropout层的参数。注意到我们为模型的每个输入结点进行了命名，这个命名在用 *c++ api* 加载模型是将会用到。模型的具体定义可以参考 [*model.py*](https://github.com/AlbertXiebnu/tf_han/blob/master/model.py)，太长了就不贴出来了。注意到，和模型输入一样，模型最后的输出结点同样进行了命名，命名为*output*。
```python
W = tf.get_variable("fullconnect_weights",shape=[2 * self.docsize,n_classes])
{'fraction_non_alphanumeric': 0.12410108896650915, 'fraction_numerical': 0.014382576535853708, 'mean_word_length': 14.602564102564102, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 14, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '947519', 'n_tokens_mistral': 3324, 'n_tokens_neox': 3725, 'n_words': 125}