tensorflow—— 从 tensorflow 1到 tensorflow 2 的迁移

引用过一个段子,大意是,苹果发布了新的开发语言Swift,有非常多优秀的特征,于是很多时髦的程序员入坑学习。不料,经过一段头脑体操一般的勤学苦练,发现使用Swift做开发,不仅要学习Swift,还要学习Swift2、Swift3、Swift4…

今天的TensorFlow 2.0也有点这样的趋势。事实上大多具有革命性的公司都是这样,一方面带来令人兴奋的新特征,另一方面则是高企不落的学习成本。

第一个例子:房价预测

本示例中的源码来自于《从锅炉工到AI专家》系列2,使用了最简单的线性函数来做房价预测。原始TensorFlow 1.x/ Python 2.x代码如下:

 
#!/usr/bin/env python 
# -*- coding=UTF-8 -*-
 
#本代码在mac电脑,python2.7环境测试通过
#第一行是mac/Linux系统脚本程序的标志,表示从环境参量中寻找python程序解释器来执行本脚本
#省去了每次在命令行使用 python <脚本名> 这样的执行方式
#第二行表示本脚本文本文件存盘使用的代码是utf-8,并且字符串使用的编码也是utf-8,
#在本源码中,这一点其实没有什么区别,但如果需要中文输出的时候,这一行就必须要加了。
 
#引入TensorFlow库
import tensorflow as tf
#引入数值计算库
import numpy as np 
 
#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
# np.dot的意思就是向量x * 0.5
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
#以下使用TensorFlow构建数学模型,在这个过程中,
#直到调用.run之前,实际上都是构造模型,而没有真正的运行。
#这跟上面的numpy库每一次都是真正执行是截然不同的区别
# 请参考正文,我们假定房价的公式为:y=a*x+b
 
#tf.Variable是在TensorFlow中定义一个变量的意思
#我们这里简单起见,人为给a/b两个初始值,都是0.3,注意这也是相当于规范化之后的数值
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))
 
#这是定义主要的数学模型,模型来自于上面的公式
#注意这里必须使用tf的公式,这样的公式才是模型
#上面使用np的是直接计算,而不是定义模型
# TensorFlow的函数名基本就是完整英文,你应当能读懂
y_value = tf.multiply(x,a) + b
 
# 这里是代价函数,同我们文中所讲的唯一区别是用平方来取代求绝对值,
#目标都是为了得到一个正数值,功能完全相同,
#平方计算起来会更快更容易,这种方式也称为“方差“
loss = tf.reduce_mean(tf.square(y_value - y))
# TensorFlow内置的梯度下降算法,每步长0.5
optimizer = tf.train.GradientDescentOptimizer(0.5)
# 代价函数值最小化的时候,代表求得解
train = optimizer.minimize(loss)
 
# 初始化所有变量,也就是上面定义的a/b两个变量
init = tf.global_variables_initializer()
 
#启动图
sess = tf.Session()
#真正的执行初始化变量,还是老话,上面只是定义模型,并没有真正开始执行
sess.run(init)
 
#重复梯度下降200次,每隔5次打印一次结果
for step in xrange(0, 200):
    sess.run(train) 
    if step % 5 == 0:
        print step, sess.run(loss),sess.run(a), sess.run(b)
  • 使用tensorflow.compat.v1代码包来兼容原有1.x的代码

TensorFlow 2.0中提供了tensorflow.compat.v1代码包来兼容原有1.x的代码,可以做到几乎不加修改的运行。社区的contrib库因为涉及大量直接的TensorFlow引用代码或者自己写的Python扩展包,所以无法使用这种模式。TensorFlow 2.0中也已经移除了contrib库,这让人很有点小遗憾的。
使用这种方式升级原有代码,只需要把原有程序开始的TensorFlow引用:

import tensorflow as tf

替换为:

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
  • 命令行迁移工具
    TensorFlow 2.0中提供了命令行迁移工具,来自动的把1.x的代码转换为2.0的代码。工具使用方法如下(假设我们的程序文件名称为first-tf.py):
tf_upgrade_v2 --infile first-tf.py --outfile first-tf-v2.py

迁移工具还可以对整个文件夹的程序做升级,请参考工具自身的帮助文档。
使用迁移工具升级的代码,实质上也是使用了tensorflow.compat.v1兼容包来提供在TensorFlow 2.0环境中执行1.x的代码。这里贴出自动转换后的新代码供你对比参考:

 
#引入TensorFlow库
import tensorflow as tf
#import tensorflow.compat.v1 as tf
tf.compat.v1.disable_v2_behavior()
 
#引入数值计算库
import numpy as np
 
#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
# np.dot的意思就是向量x * 0.5
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
#以下使用TensorFlow构建数学模型,在这个过程中,
#直到调用.run之前,实际上都是构造模型,而没有真正的运行。
#这跟上面的numpy库每一次都是真正执行是截然不同的区别
# 请参考正文,我们假定房价的公式为:y=a*x+b
 
#tf.Variable是在TensorFlow中定义一个变量的意思
#我们这里简单起见,人为给a/b两个初始值,都是0.3,注意这也是相当于规范化之后的数值
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))
 
#这是定义主要的数学模型,模型来自于上面的公式
#注意这里必须使用tf的公式,这样的公式才是模型
#上面使用np的是直接计算,而不是定义模型
# TensorFlow的函数名基本就是完整英文,你应当能读懂
y_value = tf.multiply(x,a) + b
 
# 这里是代价函数,同我们文中所讲的唯一区别是用平方来取代求绝对值,
#目标都是为了得到一个正数值,功能完全相同,
#平方计算起来会更快更容易,这种方式也称为“方差“
loss = tf.reduce_mean(input_tensor=tf.square(y_value - y))
# TensorFlow内置的梯度下降算法,每步长0.5
optimizer = tf.compat.v1.train.GradientDescentOptimizer(0.5)
# 代价函数值最小化的时候,代表求得解
train = optimizer.minimize(loss)
 
# 初始化所有变量,也就是上面定义的a/b两个变量
init = tf.compat.v1.global_variables_initializer()
 
#启动图
sess = tf.compat.v1.Session()
#真正的执行初始化变量,还是老话,上面只是定义模型,并没有真正开始执行
sess.run(init)
 
#重复梯度下降200次,每隔5次打印一次结果
for step in range(0, 200):
    sess.run(train) 
    if step % 5 == 0:
        print(step, sess.run(loss),sess.run(a), sess.run(b))

输出:

0 0.022933874 0.5829507 0.80580086
5 1.3571795e-05 0.51297766 0.6923471
10 7.2995394e-06 0.5096736 0.69456106
15 3.962296e-06 0.50712687 0.69599235
20 2.150776e-06 0.50525075 0.69704735
25 1.1674589e-06 0.5038685 0.6978246
30 6.3373983e-07 0.50285023 0.6983972
35 3.4402746e-07 0.5021 0.6988191
40 1.867464e-07 0.5015472 0.69912994
45 1.0136825e-07 0.50113994 0.699359
50 5.5029687e-08 0.5008399 0.69952774
55 2.9866097e-08 0.50061876 0.6996521
60 1.6214793e-08 0.5004559 0.6997436
65 8.802925e-09 0.50033593 0.6998111
70 4.777937e-09 0.5002475 0.6998608
75 2.59221e-09 0.5001823 0.69989747
80 1.4069683e-09 0.5001343 0.69992447
85 7.63773e-10 0.50009894 0.6999444
90 4.147581e-10 0.5000729 0.699959
95 2.2541087e-10 0.50005376 0.69996977
100 1.2259554e-10 0.50003964 0.6999777
105 6.6514086e-11 0.5000292 0.6999836
110 3.60998e-11 0.5000215 0.6999879
115 1.9568595e-11 0.50001585 0.6999911
120 1.0619736e-11 0.5000117 0.69999343
125 5.7348614e-12 0.5000086 0.69999516
130 3.1895554e-12 0.5000064 0.6999964
135 1.7265123e-12 0.5000047 0.69999737
140 9.464429e-13 0.50000346 0.699998
145 4.9482196e-13 0.5000025 0.69999856
150 2.7046808e-13 0.50000185 0.699999
155 1.4150459e-13 0.5000013 0.6999992
160 7.5957015e-14 0.50000095 0.69999945
165 4.0927263e-14 0.5000007 0.69999963
170 2.3874235e-14 0.50000054 0.6999997
175 2.3874235e-14 0.50000054 0.6999997
180 2.3874235e-14 0.50000054 0.6999997
185 2.3874235e-14 0.50000054 0.6999997
190 2.3874235e-14 0.50000054 0.6999997

所以从本质上,这种方式跟第一种方法,采用tensorflow.compat.v1包作为tensorflow替代包的方式是完全相同的。

当然还是学习TensorFlow 2.0的相关特征,重构原有代码为新版本代码才是正路。毕竟tensorflow2提供更多功能和降低使用门槛,都能使用更少的代码量来完成相同的功能。

首先了解一下TensorFlow 2.0同1.x之间的重要区别:

在API层面的类、方法有了较大的变化,这个需要在使用中慢慢熟悉
取消了Session机制,每一条命令直接执行,而不需要等到Session.run
因为取消了Session机制,原有的数学模型定义,改为使用Python函数编写。原来的feed_dict和tf.placeholder,成为了函数的输入部分;原来的fetches,则成为了函数的返回值。
使用keras的模型体系对原有的TensorFlow API进行高度的抽象,使用更容易
使用tf.keras.Model.fit来替代原有的训练循环。

使用TensorFlow 2.0原生代码的程序代码如下:

 
#!/usr/bin/env python3
#上面一行改为使用python3解释本代码
 
#引入python新版本的语言特征
from __future__ import absolute_import, division, print_function
 
#引入TensorFlow库,版本2.0
import tensorflow as tf
 
#引入数值计算库
import numpy as np
 
#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
# 请参考正文,我们假定房价的公式为:y=a*x+b
#定义tensorflow变量,a是权重,b是偏移
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))
 
#以上代码基本同tensorflow1.x版本一致
#以下有了区别
#使用python语言定义数学模型,模型来自于上面的公式
#上面使用np的是直接计算得到训练样本,而不是定义模型
#模型中并非必须使用tensorflow的计算函数来代替python的乘法运算
@tf.function
def model(x):
        return a*x+b
 
#定义代价函数,也是python函数
def loss(predicted_y, desired_y):
    return tf.reduce_sum(tf.square(predicted_y - desired_y))
 
# TensorFlow内置Adam算法,每步长0.1
optimizer = tf.optimizers.Adam(0.1)
# 还可以选用TensorFlow内置SGD(随机最速下降)算法,每步长0.001
#不同算法要使用适当的步长,步长过大会导致模型无法收敛
#optimizer = tf.optimizers.SGD(0.001)
 
#重复梯度下降200次,每隔5次打印一次结果
for step in range(0, 200):
        with tf.GradientTape() as t:
                outputs = model(x)  #进行一次计算
                current_loss = loss(outputs, y) #得到当前损失值
                grads = t.gradient(current_loss, [a, b])    #调整模型中的权重、偏移值
                optimizer.apply_gradients(zip(grads,[a, b]))    #调整之后的值代回到模型
        if step % 5 == 0:   #每5次迭代显示一次结果
                print( "Step:%d loss:%%%2.5f weight:%2.7f bias:%2.7f " % 
                        (step,current_loss.numpy(), a.numpy(), b.numpy()))

输出:

Step:0 loss:%24.96212 weight:0.4000000 bias:0.4000000 
Step:5 loss:%2.52661 weight:0.7618728 bias:0.7769755 
Step:10 loss:%3.09851 weight:0.6724465 bias:0.7311985 
Step:15 loss:%0.76833 weight:0.4870611 bias:0.5883760 
Step:20 loss:%1.25122 weight:0.4825920 bias:0.6234047 
Step:25 loss:%0.17589 weight:0.5593261 bias:0.7323259 
Step:30 loss:%0.47866 weight:0.5368637 bias:0.7342420 
Step:35 loss:%0.07048 weight:0.4649821 bias:0.6781172 
Step:40 loss:%0.15869 weight:0.4680379 bias:0.6885849 
Step:45 loss:%0.05100 weight:0.5052948 bias:0.7266813 
Step:50 loss:%0.03731 weight:0.4950116 bias:0.7130399 
Step:55 loss:%0.03594 weight:0.4784144 bias:0.6908888 
Step:60 loss:%0.00249 weight:0.4967375 bias:0.7031578 
Step:65 loss:%0.01727 weight:0.5068015 bias:0.7081487 
Step:70 loss:%0.00109 weight:0.4971068 bias:0.6951037 
Step:75 loss:%0.00376 weight:0.5000064 bias:0.6963828 
Step:80 loss:%0.00299 weight:0.5062823 bias:0.7025081 
Step:90 loss:%0.00116 weight:0.4994940 bias:0.6978173
Step:95 loss:%0.00049 weight:0.5020515 bias:0.7015482
Step:100 loss:%0.00001 weight:0.4994163 bias:0.6997705
Step:105 loss:%0.00025 weight:0.4987615 bias:0.6995357
Step:110 loss:%0.00012 weight:0.5002910 bias:0.7010981
Step:115 loss:%0.00000 weight:0.4993444 bias:0.6999485
Step:120 loss:%0.00004 weight:0.4995600 bias:0.6998640
Step:125 loss:%0.00003 weight:0.5003581 bias:0.7003891
Step:130 loss:%0.00000 weight:0.4998741 bias:0.6997344
Step:135 loss:%0.00000 weight:0.5001204 bias:0.6999192
Step:140 loss:%0.00001 weight:0.5002499 bias:0.7000750
Step:145 loss:%0.00000 weight:0.4999313 bias:0.6998295
Step:150 loss:%0.00000 weight:0.5000790 bias:0.7000531
Step:155 loss:%0.00000 weight:0.4999929 bias:0.7000217
Step:160 loss:%0.00000 weight:0.4999173 bias:0.6999694
Step:165 loss:%0.00000 weight:0.5000172 bias:0.7000650
Step:170 loss:%0.00000 weight:0.4999548 bias:0.6999837
Step:175 loss:%0.00000 weight:0.4999981 bias:0.7000053
Step:180 loss:%0.00000 weight:0.5000175 bias:0.7000092
Step:185 loss:%0.00000 weight:0.4999933 bias:0.6999787
Step:190 loss:%0.00000 weight:0.5000210 bias:0.7000080
Step:195 loss:%0.00000 weight:0.4999985 bias:0.6999913

——————
参考:tensorflow兼容处理 tensorflow.compat.v1 tf.contrib

你可能感兴趣的:(基础概念,tensorflow)