20,131 次浏览

Morvan博客-tensorflow2学习(一)

最近要阅读修改一篇论文的tensorflow代码,所以来学习tensorflow,博客主要内容来自Morvan的tensorflow的教程(reference1, 2),Morvan大佬用的tensorflow用的是很早版本了,本人安装的r2.0,所以将morvan大佬教程的代码修改成tensorflow2来熟悉api。考虑要写一些api的注解,所以就以博客形式放出来了。

tensorflow的基本思想就是通过构建含有基础变量tensor的graph,在session中运行。(reference4)

使用tensorflow进行线性拟合

拟合直线:\(\)\(y = 0.1 x + 0.3\)\(\),很简单机器学习任务,思路很简单就是初始化Weight,biases,使用损失函数MSE来判断拟合的效果,使用梯度下降进行参数的更新。其实就是一个最小二乘法。

import tensorflow.compat.v1 as tf
import numpy as np

tf.disable_v2_behavior()

# create data
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*0.1 + 0.3

# create tensorflow struct start
Weights = tf.Variable(tf.random_uniform((1,), -1.0, 1.0))
biases = tf.Variable(tf.zeros((1,)))

y = Weights*x_data + biases

loss = tf.reduce_mean(tf.square(y-y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

init = tf.initialize_all_variables()

# 创建session
sess = tf.Session()
sess.run(init)

for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(Weights), sess.run(biases), sess.run(loss))

此段代码并未对morvan的代码进行修改,这是因为使用tensorflow2.0的compat模块,使用v1版本,我们就可以运行tensorflow的v1的代码,但是这种改法没太多意义。

我们需要知道tensorflow2开始使用动态图进行计算,当然依旧保留了静态图,个人认为两者的区别,就像交流电与直流电,我们将家庭的电路加入就可以让可以让家庭的电路工作,而直流需要将所有的电路连通检查好才能保证电路的运行。

如下使用tensorflow2.0语法进行实现上述功能。

import tensorflow as tf
import numpy as np

# create data
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*0.1 + 0.3

# create tensorflow structure
Weights = tf.Variable(tf.random.uniform((1,), -1.0, 1.0))
biases = tf.Variable(tf.zeros((1,)))

loss = lambda: tf.keras.losses.MSE(y_data, Weights * x_data + biases)  # alias: tf.losses.mse
optimizer = tf.keras.optimizers.SGD(learning_rate=0.5)  # alias: tf.optimizers.SGD

for step in range(201):
    optimizer.minimize(loss, var_list=[Weights, biases])
    if step % 20 == 0:
        print("{} step, weights = {}, biases = {}, loss = {}".format(step, Weights.read_value(), biases.read_value(), loss()))  # read_value函数可用numpy替换
  1. tf里面的api别名是真的多(丹妮莉丝 坦格利安,旧瓦雷利亚的后裔,安达尔人先民的女王,维斯特洛的统治者暨全境守护者,大草原多斯拉克人卡丽熙,不焚者,弥林的女王,镣拷打破者,龙之母,阿斯塔波的解放者,罗伊拿人和先民的女王,龙石岛公主)。。。
  2. 上述代码是在eager execution模式下运行的,也就是动态图模式,可以很好的与numpy结合使用,不需要构建graph放入session之后进行运行。
  3. loss 函数需要设置了callable(可调用),所以在这里用了一个无参的lambda表达式,在进行参数优化时,将loss传入,以及传入需要更新的参数列表var_list,在eager execution中直接进行minimize操作即可,optimizer.minimize返回的是一个UnreadVariable对象。
  4. 这里使用的SGD(随机梯度下降)优化方法,着实没找到梯度下降的api
import tensorflow as tf
import numpy as np

# create data
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*0.1 + 0.3

# create tensorflow structure
Weights = tf.Variable(tf.random.uniform((1,), -1.0, 1.0))
biases = tf.Variable(tf.zeros((1,)))

@tf.function
def loss():
    return tf.keras.losses.MSE(y_data, Weights * x_data + biases)

optimizer = tf.keras.optimizers.SGD(learning_rate=0.5)  # alias: tf.optimizers.SGD

for step in range(201):
    optimizer.minimize(loss, var_list=[Weights, biases])
    if step % 20 == 0:
        print("{} step, weights = {}, biases = {}".format(step, Weights.read_value(), biases.read_value()))  # read_value函数可用numpy替换

这一段代码则将loss函数换成静态图操作,和上面eager的代码各自跑5次(调整step从201为1000)进行了小小的对比:

\(\)\(|eager(s):|3.11|3.27|3.07|3.26|3.15| \\
|graph(s):|2.46|2.50|2.58|2.45|2.49|\)\(\)

动态图的优势是灵活方便,静态图高效稳定,在上面的实验中也可以看出来。

  1. 对于tensorflow2可以使用tf.function来进行静态图的使用,需要注意的是,返回值需要是variable。
  2. 我们需要知道对于静态图与动态图之中variable的作用域与作用时间的差别,在动态图中, tf.variable时一个普通的python变量, 超出了其作用域范围就会被销毁. 而在静态图中, tf.variable则是计算图中一个持续存在的节点, 不受python的作用域的影响

系列:
Morvan博客-tensorflow2学习(一)
Morvan博客-tensorflow2学习(二)
Morvan博客-tensorflow2学习(三)
tensorflow2学习(四)

reference
1. https://www.bilibili.com/video/av16001891
2. https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/
3. https://tensorflow.google.cn/api_docs/python/
4. http://www.tensorfly.cn/tfdoc/get_started/introduction.html
5. https://zhuanlan.zhihu.com/p/67192636