tensorflow1迁移2尝试

最近跟着看了一篇博文《深度学习之卷积神经网络CNN及tensorflow代码实现示例》,学习着里面的代码,但是遇到了问题,那就是发现里面很多是tensorflow1的代码,而我用的是tensorflow2。以这个为例子,研究tensorflow1到2的转换。

简单方法-直接用tf1兼容

tf2直接全局转为tf1,这样代码很快就跑起来了。

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

但是,这样没有办法真正让我们掌握tf2,也无法了解其精髓。因此,考虑完全将代码转为tf2。

tf_upgrade_v2转换工具

听说有个tf_upgrade_v2的工具可以快速转换,目前正在研究中。
不过目前经常报错:
‘gbk’ codec can’t decode byte 0x89 in position 561: illegal multibyte sequence
而且根据博文《使用 tf_upgrade_v2 命令把 tensorflow1.x 的代码快速转换成 tensorflow2.0》的转化结果,这里转化的方法,很多函数也只是自动帮你加入了tf.compat.v1,并没有办法真正把你的代码变为tf2的,只能说暂时过渡。
因此,最好还是慢慢搞懂里面的函数,学习经验,彻底代替。

函数API手动替换

学习了《tensorflow 1.X迁移至tensorflow2 的代码写法》,觉得可以逐步替换函数,同时真正了解tf1与tf2的区别。
tf1基于图模式,tf2基于eager模式,tf2更便于我们编程和调试,尽管目前tf1的代码很多,学习tf1的代码时,应该学习其思想,将其以tf2重新实现。

语法的基本改变

首先,print函数这个会报错,因为旧版本python不用加括号,新版本应该加上括号。
诸如此类的代码:

print X_data.shape

改为:

print (X_data.shape)

采用兼容性语句

有许多函数数,由于学习时间短,我暂时没有好的解决方法,只能是加上tf.compat.v1.这样用了

tf.compat.v1.function()

像tf.reset_default_graph函数,h函数用于清除默认图形堆栈并重置全局默认图形

tf.reset_default_graph()

优化器的选择函数

train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)

值得注意的是,这里还得关闭eager模式

tf.compat.v1.disable_eager_execution()

当然,等后面完全迁移成功后,自然我们要转入这一模式的,但是前期一步步来,慢慢学习如何兼容。

更换为最新的函数

自然,有许多函数我们是可以找到最新的名称的,使用上新的名字或者功能。
tf.placeholder函数,生成占位符

tf_X = tf.placeholder(tf.float32,[None,8,8,1])

考虑采用keras的input函数代替。

tf_X = keras.Input(dtype=tf.float32,shape=[8,8,1])

tf.random_normal用于从“服从指定正态分布的序列”中随机取出指定个数的值

conv_filter_w1 = tf.Variable(tf.random_normal([3, 3, 1, 10]))

这个随机数生成,改起来较为容易

conv_filter_w1 = tf.Variable(tf.random.normal([3, 3, 1, 10]))

tf.nn.moments()函数用于计算均值和方差

 tf.nn.moments(conv_out2, [0, 1, 2], keep_dims=True)

它变动的只是入口参数:

batch_mean, batch_var = tf.nn.moments(conv_out2, [0, 1, 2], shift=None,keepdims=True,name=None)

数学函数,如像计算对数的tf.log、tf.arg_max(input,axis)根据axis取值的不同返回每行或者每列最大值的索引,主要是都归于math之下了。

tf.math.log()
tf.math.argmax(pred,1)

基本思想的改变

到目前为止,也只是简单的函数名改换,还没有涉及tf1和tf2的根本区别。
目前,暂时还无法对session这一块进行改造,因为对于eager模式和图模式的了解还有限,而这也是讲tf1升级为tf2中,感觉是最重要的地方。
tf2的eager模式,让我们很多函数的执行可以无需借助sess.run。

tf.Session() 创建一个新的TensorFlow会话

with tf.Session() as sess

tf.global_variables_initializer()函数

tf.global_variables_initializer()

原程序中的sess.run,如:

#with tf.Session() as sess:
with tf.compat.v1.Session() as sess:    
    #sess.run(tf.global_variables_initializer())
    sess.run(tf.compat.v1.global_variables_initializer())
    for epoch in range(1000): # 迭代1000个周期
        for batch_xs,batch_ys in generatebatch(X,Y,Y.shape[0],batch_size): # 每个周期进行MBGD算法
            sess.run(train_step,feed_dict={tf_X:batch_xs,tf_Y:batch_ys})
        if(epoch%100==0):
            res = sess.run(accuracy,feed_dict={tf_X:X,tf_Y:Y})
            print (epoch,res)
    res_ypred = y_pred.eval(feed_dict={tf_X:X,tf_Y:Y}).flatten() # 只能预测一批样本,不能预测一个样本
    print (res_ypred) 

实际上,tf2中,sess.run根本无需使用,具体参考博客tensorflow 1.X迁移至tensorflow2 代码写法,另外参考TensorFlow 2 ——神经网络模型,对于使用的adam优化器等部分进行了改进。
完整代码如下,每个部分都运行在jupyter notebook:
加载数据:

import tensorflow as tf
from sklearn.datasets import load_digits
import numpy as np
digits = load_digits()
X_data = digits.data.astype(np.float32)
Y_data = digits.target.astype(np.float32).reshape(-1,1)
print (X_data.shape)
print (Y_data.shape)

数据形状调整:

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
from sklearn.preprocessing import OneHotEncoder

X = X_data.reshape(-1,8,8,1)
#X=X_data
Y = OneHotEncoder().fit_transform(Y_data).todense() #one-hot编码

print(X.shape)
print(Y.shape)

模型构建:

class Model(object):
    def __init__(self):
        # 随机初始化张量参数
        self.conv_filter_w1 = tf.Variable(tf.random.normal([3, 3, 1, 10]))
        self.conv_filter_b1 =  tf.Variable(tf.random.normal([10]))
        self.conv_filter_w2 = tf.Variable(tf.random.normal([3, 3, 10, 5]))
        self.conv_filter_b2 =  tf.Variable(tf.random.normal([5]))
        self.shift = tf.Variable(tf.zeros([5]))
        self.scale = tf.Variable(tf.ones([5]))
        self.fc_w1 = tf.Variable(tf.random.normal([2*2*5,50]))
        self.fc_b1 = tf.Variable(tf.random.normal([50]))
        self.out_w1 = tf.Variable(tf.random.normal([50,10]))
        self.out_b1 = tf.Variable(tf.random.normal([10]))

    def __call__(self, x):
        tf_X = tf.cast(x, tf.float32)  # 转换输入数据类型
        # 卷积层+激活层
        
        relu_feature_maps1 = tf.nn.relu(tf.nn.conv2d(tf_X, self.conv_filter_w1,strides=[1, 1, 1, 1], padding='SAME') + self.conv_filter_b1)
        # 池化层
        max_pool1 = tf.nn.max_pool(relu_feature_maps1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
        # 卷积层
        conv_out2 = tf.nn.conv2d(relu_feature_maps1, self.conv_filter_w2,strides=[1, 2, 2, 1], padding='SAME') + self.conv_filter_b2
        # BN归一化层+激活层 
        batch_mean, batch_var = tf.nn.moments(conv_out2, [0, 1, 2], shift=None,keepdims=True,name=None)
        epsilon = 1e-3
        BN_out = tf.nn.batch_normalization(conv_out2, batch_mean, batch_var, self.shift, self.scale, epsilon)       
        relu_BN_maps2 = tf.nn.relu(BN_out)
        # 池化层
        max_pool2 = tf.nn.max_pool(relu_BN_maps2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
        # 将特征图进行展开
        max_pool2_flat = tf.reshape(max_pool2, [-1, 2*2*5])
        # 全连接层
        fc_out1 = tf.nn.relu(tf.matmul(max_pool2_flat, self.fc_w1) + self.fc_b1)
        # 输出层
        pred = tf.nn.softmax(tf.matmul(fc_out1,self.out_w1)+self.out_b1)

        return pred

loss函数

def loss_fn(model, x, y):
    preds = model(x)
    return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=y))

accuracy计算:

def accuracy_fn(logits, labels):
    preds = tf.argmax(logits, axis=1)  # 取值最大的索引,正好对应字符标签
    labels = tf.argmax(labels, axis=1)
    return tf.reduce_mean(tf.cast(tf.equal(preds, labels), tf.float32))

整体调用:

EPOCHS = 1000  # 迭代此时
LEARNING_RATE = 0.02  # 学习率
model = Model()  # 实例化模型类
for epoch in range(EPOCHS):
    with tf.GradientTape() as tape:  # 追踪梯度
        loss = loss_fn(model, X, Y)

    trainable_variables = [model.conv_filter_w1, model.conv_filter_b1, model.conv_filter_w2, model.conv_filter_b2,model.scale,model.shift,model.fc_w1,model.fc_b1,model.out_w1,model.out_b1]  # 需优化参数列表
    grads = tape.gradient(loss, trainable_variables)  # 计算梯度

    optimizer = tf.optimizers.Adam(learning_rate=LEARNING_RATE)  # Adam 优化器
    optimizer.apply_gradients(zip(grads, trainable_variables))  # 更新梯度
    accuracy = accuracy_fn(model(X), Y)  # 计算准确度

    # 输出各项指标
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{EPOCHS}], Train loss: {loss}, Test accuracy: {accuracy}')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值