# Tensorflow
## Tensorflow配置动态显存
对于Tensorflow 1.x版本
```python
import tensorflow as tf
config = tf.ConfigProto(allow_soft_placement=True)
config.gpu_options.allow_growth = True
with tf.Session(config=config) as sess:
# sess.run(your_task)
sess = tf.Session(config=config)
```
对于Tensorflow 2.x版本
```python
import tensorflow as tf
tf.config.set_soft_device_placement(True)
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices) > 0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
```
## Tensorflow加载模型
```python
checkpoint_file = './checkpoint/tf.'
with tf.Session() as sess:
saver = tf.train.import_meta_graph(checkpint_file + '.meta')
saver.restore(sess, checkpoint_file)
# 获取计算图和权重
graph = tf.get_default_graph()
# 可以通过获取节点列表来得到当前所有变量名
tensor_name_list = [tensor.name for tensor in graph.as_graph_def().node]
print(tensor_name_list)
x = graph.get_tensor_by_name('Placeholder:0')
y = graph.get_tensor_by_name('Placeholder_1:0')
```
## 准备数据集
在Tensorflow中,准备图片数据的常用方案有两种,第一种是使用tf.keras中的ImageDataGenerator工具构建图片数据生成器。第二种是使用Tensorflow原生方法构建,用tf.data.Dataset搭配tf.image中的一些图片处理方法构建数据管道。
- tf.keras.preprocessing.image.ImageDataGenerator
- tf.data.Dataset, tf.image
## checkpoint转pb冻结图
ckpt:依赖Tensorflow,只能在其框架下使用
pb:谷歌推荐,变量固定为常量,减小模型大小
```python
# 将CKPT 转换成 PB格式的文件的过程
确定输入输出节点名称
通过传入CKPT模型的路径得到模型的图和变量数据
通过 import_meta_graph 导入模型中的图
通过 saver.restore 从模型中恢复图中各个变量的数据
通过 graph_util.convert_variables_to_constants将模型冻结为pb模式
def freeze_graph(input_checkpoint,output_graph):
'''
:param input_checkpoint:
:param output_graph: PB模型保存路径
:return:
'''
# checkpoint = tf.train.get_checkpoint_state(model_folder) #检查目录下ckpt文件状态是否可用
# input_checkpoint = checkpoint.model_checkpoint_path #得ckpt文件路径
# 指定输出的节点名称,该节点名称必须是原模型中存在的节点
output_node_names = "InceptionV3/Logits/SpatialSqueeze"
saver = tf.train.import_meta_graph(input_checkpoint + '.meta', clear_devices=True)
graph = tf.get_default_graph() # 获得默认的图
input_graph_def = graph.as_graph_def() # 返回一个序列化的图代表当前的图
with tf.Session() as sess:
saver.restore(sess, input_checkpoint) #恢复图并得到数据
output_graph_def = graph_util.convert_variables_to_constants( # 模型持久化,将变量值固定
sess=sess,
input_graph_def=input_graph_def,# 等于:sess.graph_def
output_node_names=output_node_names.split(","))# 如果有多个输出节点,以逗号隔开
with tf.gfile.GFile(output_graph, "wb") as f: #保存模型
f.write(output_graph_def.SerializeToString()) #序列化输出
print("%d ops in the final graph." % len(output_graph_def.node)) #得到当前图有几个操作节点
# for op in graph.get_operations():
# print(op.name, op.values())
def freeze_graph_test(pb_path, image_path):
'''
:param pb_path:pb文件的路径
:param image_path:测试图片的路径
:return:
'''
with tf.Graph().as_default():
output_graph_def = tf.GraphDef()
with open(pb_path, "rb") as f:
output_graph_def.ParseFromString(f.read())
tf.import_graph_def(output_graph_def, name="")
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# 定义输入的张量名称,对应网络结构的输入张量
# input:0作为输入图像,keep_prob:0作为dropout的参数,测试时值为1,is_training:0训练参数
input_image_tensor = sess.graph.get_tensor_by_name("input:0")
input_keep_prob_tensor = sess.graph.get_tensor_by_name("keep_prob:0")
input_is_training_tensor = sess.graph.get_tensor_by_name("is_training:0")
# 定义输出的张量名称
output_tensor_name = sess.graph.get_tensor_by_name("InceptionV3/Logits/SpatialSqueeze:0")
# 读取测试图片
im=read_image(image_path,resize_height,resize_width,normalization=True)
im=im[np.newaxis,:]
# 测试读出来的模型是否正确,注意这里传入的是输出和输入节点的tensor的名字,不是操作节点的名字
# out=sess.run("InceptionV3/Logits/SpatialSqueeze:0", feed_dict={'input:0': im,'keep_prob:0':1.0,'is_training:0':False})
out=sess.run(output_tensor_name, feed_dict={input_image_tensor: im,
input_keep_prob_tensor:1.0,
input_is_training_tensor:False})
print("out:{}".format(out))
score = tf.nn.softmax(out, name='pre')
class_id = tf.argmax(score, 1)
print "pre class_id:{}".format(sess.run(class_id))
if __name__ == '__main__':
# 输入ckpt模型路径
input_checkpoint='checkpoint/model.tf'
# 输出pb模型的路径
out_pb_path="checkpoint/frozen_model.pb"
# 调用freeze_graph将ckpt转为pb
freeze_graph(input_checkpoint, out_pb_path)
# 测试pb模型
image_path = 'img/animal.jpg'
freeze_graph_test(pb_path=out_pb_path, image_path=image_path)
```
## 训练时保存模型为SavedModel模型
```python
# 模型输入输出以及模型定义
x = tf.placeholder(dtype = tf.float32, shape = [None,224,224,3], name = 'input_image')
model =VGG16().build_vgg16(x,N_CLASSES) # 用tf.layers实现的vgg网络
# model输出为softmax概率
'''
模型训练...
'''
# 简单形式
tf.saved_model.simple_save(sess,
"./saved_models/model_"+str(step),
inputs={"MyInput": x},
outputs={"MyOutput": model})
#复杂形式(推荐)
builder = tf.saved_model.builder.SavedModelBuilder("./saved_models/model_"+str(step))
signature = tf.saved_model.predict_signature_def(inputs={'myInput': x},
outputs={'myOutput': model})
builder.add_meta_graph_and_variables(sess=sess,
tags=[tf.saved_model.tag_constants.SERVING],
signature_def_map={'serving_default': signature})
builder.save()
```
```python
#加载saved_model模型
import tensorflow as tf # 以下所有代码默认导入
PATH = './models'
with tf.Session() as sess:
tf.saved_model.loader.load(sess, ["serve"], PATH)
in_x = sess.graph.get_tensor_by_name('input:0') #加载输入变量
y = sess.graph.get_tensor_by_name('output:0') #加载输出变量
scores = sess.run(y, feed_dict={in_x: 3.})
print(scores)
```
## checkpoint转SavedModel模型
```python
import tensorflow as tf
def convert_ckpt_to_savedmodel(checkpoint_file, savedmodel_file):
'''
:param: checkpoint_file: 模型保存时的路径+模型名前缀
:param: savedmodel_file: 转换后的模型的路径
'''
graph = tf.Graph()
with graph.as_default():
config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False)
sess = tf.Session(config=config)
with sess.as_default():
# 载入保存好的meta graph,恢复图中变量,通过SavedModelBuilder保存可部署的模型
saver = tf.train.import_meta_graph(checkpoint_file+'.meta')
saver.restore(sess, checkpoint_file)
print(graph.get_name_scope())
tf.summary.FileWriter(logs_dir, sess.graph)
# 去除多余枝节
converted_graph_def = tf.graph_util.convert_variables_to_constants(sess, graph.as_graph_def(), ['output'])
g = tf.graph_util.extract_sub_graph(converted_graph_def, ['output'])
g = tf.graph_util.remove_training_nodes(g, protected_nodes=["input_x", "output"])
builder = tf.saved_model.builder.SavedModelBuilder(savedmodel_file)
"""
build_tensor_info
建立一个基于提供的参数构造的TensorInfo protocol buffer,
输入:tensorflow graph中的tensor;
输出:基于提供的参数(tensor)构建的包含TensorInfo的protocol buffer
get_operation_by_name
通过name获取checkpoint中保存的变量,能够进行这一步的前提是在模型保存的时候给对应的变量赋予name
"""
print(graph.get_operation_by_name("input_x").outputs[0].shape)
input_image = tf.saved_model.utils.build_tensor_info(
graph.get_operation_by_name("input_x").outputs[0])
print(graph.get_operation_by_name("output").outputs[0].shape)
output = tf.saved_model.utils.build_tensor_info(
graph.get_operation_by_name("output").outputs[0])
"""
signature_constants
SavedModel保存和恢复操作的签名常量。
在序列标注的任务中,这里的method_name是"tensorflow/serving/predict"
"""
# 定义模型的输入输出,建立调用接口与tensor签名之间的映射
labeling_signature = (
tf.saved_model.signature_def_utils.build_signature_def(
inputs={
"input_image": input_image,
},
outputs={
"output": output
},
method_name="tensorflow/serving/predict"
))
"""
add_meta_graph_and_variables
建立一个Saver来保存session中的变量,输出对应的原图的定义,这个函数假设保存的变量已经被初始化;
对于一个SavedModelBuilder,这个API必须被调用一次来保存meta graph;
对于后面添加的图结构,可以使用函数 add_meta_graph()来进行添加
"""
# 建立模型名称与模型签名之间的映射
builder.add_meta_graph_and_variables(
sess, [tf.saved_model.tag_constants.SERVING],
# 保存模型的方法名,与客户端的request.model_spec.signature_name对应
signature_def_map={
tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
labeling_signature
})
builder.save()
print("Build Done.")
def convert_ckpt_to_savedmodel(checkpoint_file, savedmodel_file):
graph = tf.Graph()
config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
with tf.compat.v1.Session(graph=graph, config=config) as sess:
# 重载模型
loader = tf.compat.v1.train.import_meta_graph(checkpoint_file + '.meta')
loader.restore(sess, checkpoint_file)
# checkpoint转SavedModel
builder = tf.compat.v1.saved_model.builder.SavedModelBuilder(savedmodel_file)
builder.add_meta_graph_and_variables(sess, [tf.saved_model.TRAINING, tf.saved_model.SERVING], strip_default_attrs=True)
builder.save()
print("Build Done.")
if __name__ == '__main__':
checkpoint_file = './checkpoint/'
savedmodel_file = './saved_madel/'
convert_ckpt_to_savedmodel(checkpoint_file, savedmodel_file)
```
```bash
# 查看saved_model模型的节点
saved_model_cli show --dir ./saved_model --all
```
## keras模型转换SavedModel
```python
#若keras的模型为model.json(结构)和weights.h5(权重)
# tensorflow == 1.13.1
import tensorflow as tf
def load_keras_model(model_path, weights_path):
fr = open(model_path, "r")
model_json = fr.read()
fr.close()
model = tf.keras.models.model_from_json(model_json, custom_objects={"tf":tf})
model.load_weights(weights_path)
return model
model_export_dir = "./model/1"
model = load_keras_model("model.json", "weights.h5")
name_to_inputs = {i.name.split(":")[0]:i for i in model.inputs}
name_to_outputs = {i.name:i for i in model.outputs}
print(name_to_inputs)
print(name_to_outputs)
tf.saved_model.simple_save(tf.keras.backend.get_session(),
model_export_dir,
inputs=name_to_inputs,
outputs=name_to_outputs)
```