1.视频网站:mooc慕课https://mooc.study.163.com/university/deeplearning_ai#/c
2.详细笔记网站(中文):http://www.ai-start.com/dl2017/
3.github课件+作业+答案:https://github.com/stormstone/deeplearning.ai
3.11 TensorFlow
本节将介绍DL框架TensorFlow程序的基本结构。
TensorFlow安装参见链接
例1.TensorFlow实现最小化固定系数损失函数
假设你有一个损失函数
J
J
J需要最小化。
在这里我们将使用一个高度简化的损失函数,
J
(
w
)
=
w
2
−
10
w
+
25
J(w)=w^2-10w+25
J(w)=w2−10w+25。
其实它是
(
w
−
5
)
2
(w-5)^2
(w−5)2的展开,最小值就是5。
我们来看一下TensorFlow如何实现最小化这个函数,一个非常类似的程序结构可以用来训练NN。
用TensorFlow可以自动找到使损失函数最小的 w w w和 b b b的值。让我们先从上边这个简单的例子入手。
代码和相关说明如下
import numpy as np
import tensorflow as tf #导入TensorFlow
import os
#os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
#接下来,让我们定义参数w,在TensorFlow中,你要用tf.Variable()来定义参数
w = tf.Variable(0,dtype = tf.float32)
#然后我们定义损失函数J
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评估一个变量
print(session.run(w))
运行之后,结果为0.0。因为我们还没有开始下降。
如果运行tensorflow看到以下警告信息
Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
意思是:你的CPU支持AVX扩展,但是你安装的TensorFlow版本无法编译使用。
你可以通过以下代码忽略警告。详细参见 https://blog.csdn.net/feng98ren/article/details/84874326
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
现在我们下降一步,然后看运行参数 w w w
#然后让TensorFlow评估一个变量
session.run(train) #运行一步梯度下降法
print(session.run(w))
运行结果
0.099999994
现在我们尝试迭代1000次,然后看运行参数 w w w
for i in range(1000):
session.run(train) #运行1000次梯度下降法
print(session.run(w))
运行结果
4.9999886
记不记得我们说过要使 ( w − 5 ) 2 (w-5)^2 (w−5)2最小化, w w w的最优值是5,所以现在1000次迭代的结果已经很接近了。
希望这个例子能让你对TensorFlow程序的大致结构有了了解
TensorFlow知道如何对add和mutiply,还有其它函数求导,这就是为什么你只需基本实现前向传播,它能弄明白如何做反向传播和梯度计算,因为它已经内置在add,multiply和平方函数中。
cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25)
要是觉得这种写法不好看的话,TensorFlow其实还重载了一般的加减运算等等,因此你也可以把损失函数cost写成更好看的形式。
cost = w**2- 10*w+25
重新运行,也可以得到了同样的结果。
上面例子将关于 w w w的一个固定函数最小化了。如果你想要最小化的函数是训练集函数又如何呢?不管你有什么训练数据,当你训练NN时,训练数据会改变,那么如何把训练数据加入TensorFlow程序呢?
例2.TensorFlow实现最小化动态系数损失函数
我会定义训练数据 x x x。事实上训练数据会有特征 x x x和标签 y y y,但这个例子中只有 x x x。
x = tf.placeholder(tf.float32,[3,1])
训练数据 x x x是[3,1]数组。
然后把损失函数cost的二次方程式 w 2 − 10 w + 25 w^2-10w+25 w2−10w+25中,三项的固定系数1,-10和25替换如下
cost = x[0][0]*w**2 - x[1][0]*w + x[2][0]
现在
x
x
x变成了控制这个二次函数的系数(coefficient)。
而变量
x
x
x定义中的placeholder函数告诉TensorFlow,你稍后会为
x
x
x提供数值。
现在定义一个系数数组
coefficient = np.array([[1.],[-10.],[25.]])
这就是我们要送入 x x x的数据。
最后我们需要用如下方式把这个系数数组送入变量 x x x。
feed_dict = {x:coefficients}
最终完整代码如下
import numpy as np
import tensorflow as tf #导入TensorFlow
import os
#os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
#接下来,让我们定义参数w,在TensorFlow中,你要用tf.Variable()来定义参数
w = tf.Variable(0,dtype = tf.float32)
#定义训练数据x
x = tf.placeholder(tf.float32,[3,1])
#定义系数数组
coefficients = np.array([[1.],[-10.],[25.]])
#然后我们定义损失函数J
#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]
#用梯度下降法优化器使用损失函数最小化
#使用0.01的学习率,目标是最小化损失
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
#下面几行是管用表达式
init = tf.global_variables_initializer()
session = tf.Session() #开启了一个TensorFlow session
session.run(init) #初始化全局变量
#然后让TensorFlow评估一个变量
for i in range(1000):
session.run(train,feed_dict = {x:coefficients}) #运行1000次梯度下降法
print(session.run(w))
最终运行结果和上面固定系数的例子一样
4.9999886
你可以尝试把第二个系数从-10变化为-20,第三个系数从25变为100,这样损失函数就变成了
(
w
−
10
)
2
(w-10)^2
(w−10)2 ,要使它最小化,那
w
=
10
w=10
w=10。
我们可以用上面的代码尝试迭代1000次,结果
9.999977
TensorFlow中的placeholder可以定义动态赋值的变量,这种方式便于把训练数据加入损失函数。
当你运行训练迭代,用feed_dict来让变量x=coefficients。
如果你在做mini-batch梯度下降,在每次迭代时,你需要插入不同的mini-batch,那么每次迭代,你就用feed_dict来喂入训练集的不同子集,把不同的mini-batch喂入损失函数需要数据的地方。
希望通过上面的2个例子能让你了解了TensorFlow能做什么。让它如此强大的是,你只需说明如何计算损失函数,它就能求导(GradientDescentOptimize),而且用一两行代码就能运用梯度优化器,Adam优化器或者其他优化器。
TensorFlow程序的核心是计算损失函数,然后TensorFlow自动计算出导数,以及如何最小化损失。
损失函数代码所做的就是让TensorFlow建立计算图。
cost =x[0][0]*w**2 +x[1][0]*w + x[2][0]
计算图所做的就是取
x
[
0
]
[
0
]
x[0][0]
x[0][0],取
w
w
w并将它平方,然后
x
[
0
]
[
0
]
x[0][0]
x[0][0]和
w
2
w^2
w2相乘,你就得到了
x
[
0
]
[
0
]
∗
w
2
x[0][0]*w^2
x[0][0]∗w2,以此类推,最终整个建立起来计算cost,得到了损失函数。
TensorFlow的优点在于,通过用这个计算损失,计算图基本实现前向传播,TensorFlow已经内置了所有必要的反向传播过程的反向函数。这也是为什么通过内置函数来计算前向函数,它也能自动用反向函数来实现反向传播。你不需要明确实现反向传播,这是编程框架能帮你变得高效的原因之一。
如下图,如果你去看TensorFlow使用说明里的计算图,你会看到另一种表示方式,节点都用运算来标记而不是值,但这方式呈现的表达式是和上图一样的。
在编程框架中如果你不想用梯度下降法,而是想用Adam优化器,你只要改变替换代码GradientDescentOptimize,就能换成更好的优化算法。所有现代深度学习编程框架都支持这样的功能,让你很容易就能编写复杂的NN。