本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
1. 常用低阶API的升级
这份文档适用于使用低阶 TensorFlow1.x API升级到Tensorflow 2.x API 的开发者。如果您正在使用高阶 API (tf.keras),可能无需或仅需对您的代码执行很少操作,便可以让代码完全兼容 TensorFlow 2.x。
在 TensorFlow 2.x 中,1.X 的代码不经修改也许还可运行(除了contrib):
import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
但是,这样做无法发挥 TensorFlow 2.x 的许多优化改进。这里作者从低阶API代码视角实践Tensorflow1.x升级到2.x低阶API。
升级一些常见的改写经验,先从挥手告别难于理解的占位符开始,包括tf.placeholder,tf.InteractiveSession(),tf.Session()等,如下代码tf.placeholder所示。
#定义输入变量 x = tf.placeholder(dtype=tf.float32,shape=[None,in_units],name='x')
其他的部分常用API及其变化如下表所示。
功能 | Tensorflow 1.X | Tensorflow 2.X |
---|---|---|
梯度优化 | tf.train.AdamOptimizer | tf.optimizers.Adam |
占位符 | tf.placeholder | 无 |
会话 | tf.Session() | 无 |
数据分布 | tf.truncated_normal | tf.random.truncated_normal |
数学计算log | tf.log | tf.math.log |
模型保存 | tf.train.Saver.save | tf.saved_model.save |
模型加载 | tf.train.Saver.restore | tf.saved_model.load |
其中,tensorflow 1.x版本中的placeholder,在tf2中已经被取消,在tf2中,可以用tf.keras.Inputs代替。示例:
# tf1中 input_ids = tf.placeholder(dtype=tf.int32, shape=[None]) #tf2中,改写为: input_ids = tf.keras.Input(dtype=tf.int32, shape=[None])
2. 关于计算图
在tensorflow 1.x中,由于是基于静态图机制(Graph Execution),需要先构造图,然后才真正运行,因此需要用显示调用Session后,才会真正触发计算,对调试代码非常不利,使用不方便。
在tensorflow 2.x中,默认是基于动态图机制(Eager Execution),就像常规函数一样,调用时就触发计算。对调试代码非常方便。
所以,tf1中session部分代码,可以全部去掉。示例:
# tf1中 sess = tf.InteractiveSession() sess.run(tf.global_variables_initializer())
3. 全连接神经网络升级实践
3.1. 使用公开数据集
使用scikit-learn 提供的简单手写字符识别数据集DIGITS,每行数据宽度为64。
import numpy as np import tensorflow as tf from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split digits = load_digits() # DIGITS 数据集是 scikit-learn 提供的简单手写字符识别数据集。 digits_y = np.eye(10)[digits.target] # 标签独热编码 # 独热编码是一种稀疏向量,其中:一个元素设为 1,所有其他元素均设为 0。 # 切分数据集,测试集占 20% X_train, X_test, y_train, y_test = train_test_split(digits.data, digits_y,test_size=0.2, random_state=1)
3.2. 定义全连接神经网络
class DNNModel(tf.Module): def __init__(self, layer=[64,128,256,10], keep_prob = 0.2, name=None): super(DNNModel, self).__init__(name=name) self.layer=layer self.keep_prob = keep_prob self.num = len(self.layer)-1 # 网络层数 self.w = [] self.b = [] h_in = self.layer[0] h_out = self.layer[1] for i in range(self.num): # tf.truncated_normal由tf.random.truncated_normal替换 w0 = tf.Variable(tf.random.truncated_normal([h_in,h_out],stddev=0.1),name='weights' +str(i+1) ) b0 = tf.Variable(tf.zeros([h_out],name='biases' + str(i+1))) self.w.append(w0) self.b.append(b0) if i < self.num -1: h_in = self.layer[i + 1] h_out = self.layer[i + 2] self.var = [] for i in range(len(self.w)): self.var.append(self.w[i]) self.var.append(self.b[i]) @tf.function(input_signature=[tf.TensorSpec([None,64])]) def __call__(self, x): x = tf.cast(x, tf.float32) # 转换输入数据类型 h1 = x for i in range(self.num): #定义前向传播过程 if i < self.num -1: #h0 = tf.nn.relu([email protected][i] + self.b[i], name='layer' +str(i+1)) h0 = tf.nn.relu(tf.matmul(h1, self.w[i]) + self.b[i], name='layer' +str(i+1)) # 或[email protected],以及tf.add #使用dropout if i == 0: h1 = h0 else: h1 = tf.nn.dropout(h0, rate = 1 - self.keep_prob) else: h1 = tf.matmul(h1, self.w[i]) + self.b[i] # 定义输出层 #self.y_conv = tf.nn.softmax(h1,name='y_conv') # 自行编写交叉熵损失,或tf.losses.categorical_crossentropy self.y_conv = h1 # 直接使用softmax_cross_entropy_with_logits return self.y_conv
注意:
python中一切皆对象,函数也是对象,同时也是可调用对象(callable),一个类实例要变成一个可调用对象,只需要实现一个特殊方法__call__()。但是在TensorFlow中,对于自定义模型的时候,经常用call()函数,区别在于__call__()用于class继承tf.Module,call()用于class继承tf.keras.Module。
3.3. 模型训练
layer=[64,128,128,10] EPOCHS = 100 # 迭代此时 LEARNING_RATE = 0.01 # 学习率 model = DNNModel(layer = layer, keep_prob = 0.2) # 实例化模型类 for epoch in range(EPOCHS): with tf.GradientTape() as tape: # 追踪梯度 preds = model(X_train) loss = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=y_train)) #loss = tf.reduce_sum(tf.losses.categorical_crossentropy(y_train, preds)) trainable_variables = model.var # 需优化参数列表 grads = tape.gradient(loss, trainable_variables) # 计算梯度,求导 optimizer = tf.optimizers.Adam(learning_rate=LEARNING_RATE) # Adam 优化器 optimizer.apply_gradients(zip(grads, trainable_variables)) # 更新梯度 # 计算准确度 preds = tf.argmax(model(X_test), axis=1) # 取值最大的索引,正好对应字符标签 labels = tf.argmax(y_test, axis=1) accuracy = tf.reduce_mean(tf.cast(tf.equal(preds, labels), tf.float32)) # 输出各项指标 if (epoch + 1) % 10 == 0: print(f'Epoch [{ epoch+1}/{ EPOCHS}], Train loss: { loss}, Test accuracy: { accuracy}')
3.4. 模型持久化保存
对于tensorflow2.x版本生成的saved_model模型,没有像1.x版本使用SavedModelBuilder API自定义签名(输入输出的数据类型+方法),2.x版本模型输入的数据类型可以通过@tf.function中的input_signature参数指定,方法目前来看是写死在源码中的,只有signature_constants.PREDICT_METHOD_NAME一种。很多时候模型的输入输出对我们来说是黑盒的,而在调用服务接口的时候我们需要知道模型的输入输出以及签名的key,我们可以使用saved_model_cli show –dir model/test/1 –all来查看我们需要的参数。
tf.saved_model.save(model,'DNNmodel_base')
3.5. 模型加载与使用
restored_model = tf.saved_model.load('DNNmodel_base') f = restored_model.signatures["serving_default"] X_test = tf.cast(X_test, tf.float32) preds = f(X_test) preds = tf.constant(preds['output_0']) preds = tf.argmax(preds, axis=1) labels = tf.argmax(y_test, axis=1) accuracy = tf.reduce_mean(tf.cast(tf.equal(preds, labels), tf.float32)) print(f'Test accuracy: { accuracy}')
4. 升级中遇到的问题
4.1. 关于tensorflow-cpu
针对Tensorflow 1.x的GPU安装版本,Tensorflow 2.x不再区分是否gpu,默认直接安装Tensorflow 。当系统检测到gpu并安装cuda后,则自动调用gpu。
如果,我们不需要或没有gpu时,gpu适配对这部分群体是浪费的(占用不必要的资源),于是有了Tensorflow-cpu,我们可以理解其为cpu only版本。
综上,也可以理解为:tensorflow == 1.x对应tensorflow-cpu == 2.x,tensorflow-gpu == 1.x 对应 tensorflow == 2.x。
4.2. 遇到问题
Tensorflow 2.0 使用AdamOptimizer模型报错。
原因:keras与tensorflow版本不匹配
ImportError: cannot import name ‘dtensor’ from ‘tensorflow.compat.v2.experimental’
环境 windows10 、tensorflow2.6版本(Keras已由2.10降至2.6)
5. 关于Tensorflow API简单说明
TensorFlow API一共可以分为三个层次,即低阶API、中阶API、高阶API:
第一层为Python实现的操作符,主要包括各种张量操作算子、计算图、自动微分;
第二层为Python实现的模型组件,对低级API进行了函数封装,主要包括各种模型层,损失函数,优化器,数据管道,特征列等等;
第三层为Python实现的模型成品,一般为按照OOP方式封装的高级API,主要为tf.keras.models提供的模型的类接口。
参考:
[1]. 谷歌开发者.官方教程 手把手教你如何将 TensorFlow 1 升级到 TensorFlow 2(上)
. 知乎. 2020.09
[2]. 不要清汤锅.tensorflow / tensorflow-gpu / tensorflow-cpu区别?
. CSDN博客. 2020.12
[3].凡心curry.TensorFlow 2 ——神经网络模型
. CSDN博客. 2021.04
[4]. Doit.TensorFlow2.0教程-使用低级api训练(非tf.keras)
. 知乎. 2019.07
[5]. yunfeather.tensorflow中Adam优化器运用
. CSDN博客. 2020.05
[6]. 丙吉.keras报错ImportError: cannot import name ‘dtensor’ from ‘tensorflow.compat.v2.experimental’
. 简书. 2022.09
[7]. 然后就去远行吧.TensorFlow2.0 —— 模型保存与加载
. CSDN博客. 2021.04
[8]. Tester_muller.Tensorflow 2.x 模型-部署与实践
. CSDN博客. 2022.08
[9]. 然后就去远行吧.TensorFlow 2.0简介. CSDN博客. 2020.08
[10]. 肖永威.Tensorflow BP神经网络多输出模型在生产管理中应用实践
. CSDN博客. 2020.09
Be First to Comment