# 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) ```