tensorflow_知识点
1. tensorflow动态图和静态图切换
动态图是Tensorflow1.3版本之后出现的,到1.11版本时,已经比较完善。在2.0之后版本为默认工作方式。
tensorflow2.X 关闭动态图的函数
tf.compat.v1.disable_v2_behavior
启用动态图的函数:
tf.compat.v1.enable_v2_behavior
2.tensor和numpy互转
静态图中,tensor和numpy不能互转。动态图 可以转化
data_tensor= tf.convert_to_tensor(data_numpy) # numpy转tensor 显式转换。大多数情况tensor接收到numpy会自动转化
data_numpy = data_tensor.numpy() # tensor转numpy
3.声明函数为静态图
在函数前面加上 "@tf.function" 。函数将以张量运算图运行。自东土中,如果在被修饰的函数有多个返回分支,则必须确保所有的分支都返回相同类型的张量,否则会报错
4.在静态图中使用动态图
tensorflow2.X提供 在静态图使用动态图操作方式的封装关键字"tf.py_function"
tf.compat.v1.disable_v2_behavior # 使用静态图方式 def my_py_func(X,Y): …… return z z=tf.py_function(my_py_func,[X,Y] ,tf.float32) #后续接静态图调用过程代码 …… #程序执行时,my_py_func内 的tensor都是 “EaderTensro”动态tensor类型,因此可以numpy等数据类型相互转换调用
5.静态图和动态图性能差异
2021-9月份,数据集3万张,8个类。分别在批次=20,128下测试
测试以下三种方式:tf.kreas静态图方式, 2.X全部动态图方式,2.X部分动态图方式(train_step 使用 @tf.function 修饰,其余动态图) 。取三次情况做平均。测试结果如下
20批次(显卡6G显存): 以静态图为基准, 全动态图耗时是 140% , 部分动态图 100%
128批次(显卡24显存): 以静态图为基准,全部动态图耗时100% , 部分动态图 115%
似乎动态图性能都能找到方式和静态图一样的执行效率
6.冻结网络层
tensorflow只需要更改模型的"trainable" 属性即可完成更改。更改完,需要调用 模型的"compile"函数,完成关联项更改
trainable 的优先级,高级覆盖低级
model.trainable = False model.layers[0].trainable = False model.layers[1].trainable = True model.compile(……) 此时,整个模型都不可训练 model.trainable = True model.layers[0].trainable = False model.layers[1].trainable = True model.compile(……) 此时, 模型的layers层中设置使能性能的,进行巡礼。 比如训练过程 层0将不会进行参数更新。 层1将进行参数。 如果要详细查看 可以设定动态图,然后调试过程中 查看“self.model.trainable_weights”的值
7.迁移学习中,只训练输出层
参考“冻结网络层”, 将其余层的训练使能设为“False”,输出层的训练使能启用。
8. Loaded cuDNN version 8204 后程序退出
模型能够加载, 但是执行如下语句
y = model(x, training=True)
程序不报异常,直接结束执行。
原因: cuda,cudnn 和tensorflow版本不匹配。tensorflow官网 安装页面 “GPU支持”有cuda11.2字样, 最下面又有cuda11.1 。 并且安装的适合没有像 pytorch ,直接在安装语句指定 cuda版本。 误以为安装最新版本都支持。因此安装cuda11.4+cudnn8.2 。
解决办法:按照tensorflow官网-》源代码构建 -》Windows
版本对应关系,安装后解决。
PS: 安装最新版本驱动,再安装cuda11.2 会报 已经安装更新版本,无法安装cuda11.2。此时需要手动卸掉 。 安装cuda后,再安装一次显卡驱动。
9. 集成学习(ensemble learning)合并网络时,报错“ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(type_spec=TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name='input_2'), name='input_2', ……". The following previous layers were accessed without issue: []”
#错误代码
for …… inputs.append(models[index_model].input ) outputs.append( sub_models[index_model].get_layer(merge_layer_name).output)
output_concat = tf.keras.layers.Concatenate()( outputs )
tf.keras.models.Model(inputs,output_concat )
将多个模型合并成一个,重命名层名后,合并。 执行到Model()时,函数报找不到梯度图。 后面查找,发现原来的代码是取原来网络 第一层网络的input 和需要合并层的网络输出,进行合并。
#正确的代码
#假定模型是俩层嵌套。 输入和 合并的网络层都在第二层嵌套中。
for …… inputs.append(models[index_model].layers[0].input ) outputs.append(models[index_model].get_layer( "目标层父亲层名").get_layer("目标层名".output) output_concat = tf.keras.layers.Concatenate()( outputs ) model = tf.keras.models.Model(inputs, output_concat ) #代码运行成功
原因是:模型input和 “layers”层之间数据流方式不一样。可能改名之后,layers之间的数据流向跟着变,而模型的input等没有跟着更改。
解决办法:找到最开始的最底层的input , 找到具体要合并的层,返回output 。
10. tensorflow2.X 读入 frozen graph 形式pb文件
tensorflow 的pb文件有俩种,一种是saved_model_dir ,文件形式是文件夹;一种是 frozen graph in text or binary format ,形式是单个文件夹。 对于前者读取,网上搜下,一句函数搞定,对于后者搜索非常多,总感觉少掉 Graph Def 转使用的模型。 后面终于在csdn的 vokxchh:Python3.7的Tensorflow2.0 图像分类的模型生成与读取 的代码找到加载方法。
#包裹冻结图 def wrap_frozen_graph(graph_def, inputs, outputs, print_graph=False): def _imports_graph_def(): tf.compat.v1.import_graph_def(graph_def, name="") wrapped_import = tf.compat.v1.wrap_function(_imports_graph_def, []) import_graph = wrapped_import.graph print("-" * 50) print("Frozen model layers: ") layers = [op.name for op in import_graph.get_operations()] if print_graph == True: for layer in layers: print(layer) print("-" * 50) return wrapped_import.prune( tf.nest.map_structure(import_graph.as_graph_element, inputs), tf.nest.map_structure(import_graph.as_graph_element, outputs))
#读取pb文件 with tf.io.gfile.GFile("./frozen_models/frozen_graph.pb", "rb") as f: graph_def = tf.compat.v1.GraphDef() #默认是二进制的按这样读取。如果是text,需要网上找函数 loaded = graph_def.ParseFromString(f.read()) #转化为可以使用的模型 frozen_func = wrap_frozen_graph(graph_def=graph_def, inputs=["Input:0"], #输入层的节点名称 outputs=["Identity:0"], #输出层的节点名称 print_graph=True) #True打印所有层名 #后续的使用就是 outputs = frozen_func(batch_data) #注意outputs是 list的EagerTensor
测试冻结的PB比 未作处理的“saved_model_dir”,运行速度快3.5倍。因此建议需要用tensorflow模型时,使用变量冻结常量操作,保存为 frozen graph 形式pb文件。
后面又找到类似上述代码更早的地址“Lei Mao”的github博客:
Save, Load and Inference From TensorFlow 2.x Frozen Graph
冻结部分可以参考他的。