TensorFlow
TensorFlow
目录
吴恩达深度学习视频中的一些杂记
TensorFlow很强大。你只需说明如何计算损失函数,它就能求导。而且用一两行代码就能运用梯度优化器,Adam优化器或者其他优化器。
(注意区别TensorFlow和Transformer,有点像,但一个是python包一个是模型)
举个例子:
,这就是损失函数,你通过化简该函数为,得知最小值是5。但我们来看一下怎样用TensorFlow将其最小化。
最小化损失函数
在Jupyter notebook中运行以下Python代码
# 导入TensorFlow
import numpy as np
import tensorflow as tf
# 接下来,让我们定义参数w
# 【注意】在TensorFlow中,你要用tf.Variable()来定义我们想要优化的参数。一旦w被称为TensorFlow变量
w = tf.Variable(0,dtype = tf.float32)
# 定义损失函数:J=w^2-10w+25
cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25)
# 定义学习率为0.01,目标是最小化损失
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
# 最后下面的几行是惯用表达式:
init = tf.global_variables_initializer()
session = tf.Session() # 这样就开启了一个TensorFlow session。
session.run(init) # 来初始化全局变量。
# 然后让TensorFlow评估一个变量,我们要用到:
# session.run将w初始化为0,并定义损失函数,我们定义train为学习算法,它用梯度下降法优化器使损失函数最小化,但实际上我们还没有运行学习算法,所以#上面的这一行将w初始化为0,并定义损失函数,我们定义train为学习算法,它用梯度下降法优化器使损失函数最小化,但实际上我们还没有运行学习算法,所以session.run(w)评估了w,让我::
session.run(w)
# ——————————————————————————————————————————————————————————————————————————
# 评估w等于0,因为我们什么都还没运行
print(session.run(w)) # 0.0
# 运行一步梯度下降法
session.run(train)
print(session.run(w)) # 0.1
# 迭代运行梯度下降1000次
for i in range(1000):
session.run(train)
print(session.run(w)) # 4.99999,与最优解5很接近了
添加训练数据
那么如何把训练数据加入TensorFlow程序呢?
coefficient = np.array([[1.],[-10.],[25.]]) # 这就是我们要接入x的数据
w = tf.Variable(0,dtype = tf.float32)
x = tf.placeholder(tf.float32, [3,1]) # X为[3,1]数组。这个placeholder函数告诉TensorFlow,你稍后会为x提供数值。
# cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25)
# cost = w**2-10*w+25
cost = x[0][0]*w**2 + x[1][0]*w + x[2][0] # x为二次函数的参数
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)
print(session.run(w)) # 0.0
session.run(train, feed_dict={x:coefficients}) # feed_dict设置我们要接入x的数据
print(session.run(w)) # 0.1
for i in range(1000):
session.run(train, feed_dict={x:coefficients})
print(session.run(w)) # 4.99999
现在如果你想改变这个二次函数的系数,也是一样的
# 假设你把
coefficient = np.array([[1.],[-10.],[25.]])
# 改成
coefficient = np.array([[1.],[-20.],[100.]])
现在这个函数就变成了,如果我重新运行,希望我得到的使最小化的值为10
在梯度下降1000次迭代之后,我们得到9.99998,接近最优解10
更精简的写法
import numpy as np
import tensorflow as tf
w = tf.Variable(0,dtype = tf.float32)
x = np.array([[1.],[-10.],[25.]], dtype=np.float32)
optimizer = tf.keras.optimizers.Adam(0.1)
def training(x, w, optimizer):
"""
x:训练数据
w:TensorFlow变量
optimizer:最优化算法
"""
def cost_fn():
return x[0][0]*w**2 + x[1][0]*w + x[2][0]
for i in range(1000):
optimizer.minimize(cost_fn, [w])
return w
w = training(x,w, optimizer)
一些补充
补充:运算符号问题
使用这些add
和multiply
之类的函数。TensorFlow知道如何对add
和mutiply
,还有其它函数求导,这就是为什么你只需基本实现前向传播,它能弄明白如何做反向传播和梯度计算,因为它已经内置在add
,multiply
和平方函数中。
要是觉得这种写法不好看的话,TensorFlow其实还重载了一般的加减运算等等,因此你也可以把写成更好看的形式
# cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25) # 旧写法
cost = w**2-10*w+25 # 新写法,被运算符重载支持
补充:placeholder的好处
TensorFlow中的placeholder是一个你之后会赋值的变量。
当你运行训练迭代,用feed_dict
来让x=coefficients
,把训练数据加入损失方程
如果你在做mini-batch梯度下降,你需要在每次迭代时插入不同的mini-batch
补充:with写法
还有最后一点我想提一下,
@Note:
# 下面这三行,在TensorFlow里是符合表达习惯的
session = tf.Session()
session.run(init)
print(session.run(w))
# 有些程序员会用另一种写法,作用基本上是一样的
with tf.Session() as session:
session.run(init)
print(session.run(w))
# 作用一样,但Python中的with命令更方便清理,以防在执行这个内循环时出现错误或例外
补充:换最佳化算法
在编程框架中你可以用一行代码做很多事情,
例如,你不想用梯度下降法,而是想用Adam优化器,你只要改变这行代码:train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
,
就能很快换掉它,换成更好的优化算法。所有现代深度学习编程框架都支持这样的功能,让你很容易就能编写复杂的神经网络。
TensorFlow的一些原理(计算图)
TensorFlow程序的核心是计算损失函数,然后TensorFlow自动计算出导数,以及如何最小化损失
cost =x[0][0]*w**2 +x[1][0]*w + x[2][0]
上面这个代码所做的就是让TensorFlow建立计算图,得到损失函数
(我看不懂了,而且这里视频好像有一部分被删了,没有看到他说TensorFlow的计算图怎么样)
前向函数和反向函数的处理
TensorFlow的优点在于,通过用这个计算损失,计算图基本实现前向传播。
TensorFlow已经内置了所有必要的反向函数,回忆一下训练深度神经网络时的一组前向函数和一组反向函数,而像TensorFlow之类的编程框架已经内置了必要的反向函数,这也是为什么通过内置函数来计算前向函数,它也能自动用反向函数来实现反向传播,即便函数非常复杂,再帮你计算导数,这就是为什么你不需要明确实现反向传播,这是编程框架能帮你变得高效的原因之一。
TensorFlow的计算图
如果你看TensorFlow的使用说明,我只是指出TensorFlow的说明用了一套和我不太一样的符号来画计算图,它用了,,然后它不是写出值,想这里的,TensorFlow使用说明倾向于只写运算符,所以这里就是平方运算,而这两者一起指向乘法运算,以此类推,然后在最后的节点,我猜应该是一个将加上去得到最终值的加法运算。
我认为计算图用第一种方式会更容易理解,但是如果你去看TensorFlow的使用说明,如果你看到说明里的计算图,你会看到另一种表示方式,节点都用运算来标记而不是值,但这两种呈现方式表达的是同样的计算图。