- 深度学习程序设计实战
- 方林 陈海波编著
- 1352字
- 2025-02-25 14:02:53
3.2 优化器和计算图
3.2.1 梯度和优化器
前面已经说过,TF的实质是一个自动求微分的工具。根据BP算法(见算法2-2),我们已经知道了在计算偏导数的过程中如何避免重复计算。TF中的优化器(tf.train.Optimizer)及其子孙类就是用来自动求微分的。Optimizer.minimize()函数是用来求张量的最小值的。请注意,与tf.assign()函数一样,上述minimize()函数返回的也是一个张量。所以执行这个函数并不能马上求解tensor的极小值,就像执行tf.assign()并不能马上给一个变量赋值一样。必须在一个会话的范围内,通过该会话的run()方法运行minimize()返回的张量,才能求得一个目标函数极小值的解。
tf.train.Optimizer有很多子类,最简单的就是基于GD法的梯度下降优化器:tr.train.GradientDescentOptimizer。它的原理是根据BP算法计算目标函数针对每个可训练变量的偏导数,然后利用GD法的式(2-2)计算每个可训练变量的误差,最后再把误差加到对应的变量上(见算法2-1)。除了梯度下降优化器外,TF还有很多其他优化器,例如MomentumOptimier、AdamOptimier等。它们都是为了克服梯度下降优化器的不足而提出的,我们在后面的章节中会加以说明。下面通过例子来说明优化器的使用方法。
3.2.2 求解平方根
根据前面的讨论,我们已经知道,用GD法求正数a的平方根等价于求解函数y=(x2-a)2的最小值。所以代码应该是这样的:


请注意:
1)初始化器Initializer用来为变量赋初值。常用的初始化器有tf.initializer包里的ones、zeros、random_normal、random_uniform等,分别表示给变量的每一个元素赋初值1、0、正态分布随机数和均匀分布随机数。注意,变量的真正初始化要到运行Session.run(tf.global_variables_initializer())时才执行。
2)在对模型进行训练前,应该执行Session.run(tf.global_variables_initializer()),给所有可训练张量赋初值。如果没有定义变量,这一句可不运行。变量只需赋初值一次,因此这一句应该在while循环前执行。
Session每运行一次ts.train_op张量,就会按照BP算法自动计算目标函数针对每个相关可训练变量[5]的偏导数(即梯度),然后按照Optimizer对象的规定计算每个变量的误差,最后根据误差自动调整每个变量的值。
3)Session.run()函数一次可运行一个张量或者多个张量。当运行多个张量时,请把它们组成一个列表(list)或者元组(tupple)。一般来说,张量之间的次序不重要。如果只求一个张量的值,run()的返回值就是这个张量的值;如果同时求多个张量的值,则返回一个依次包含每个张量的值的列表。tf.train.Optimizer张量的值是None。
上面程序运行的结果是:
sqrt(2)=1.4141785
sqrt(3)=1.7320222
sqrt(4)=1.9999753
sqrt(5)=2.2360463
sqrt(6)=2.4494696
sqrt(7)=2.6457334
sqrt(8)=2.8284097
sqrt(9)=2.9999843
sqrt(10)=3.1622627
3.2.3 计算图
前文已经说过,计算图的实质是依赖关系图。依赖关系图不仅定义了运算之间的依赖关系,还避免了重复运算。但是,在上一节计算平方根时,并没有涉及计算图tf.Graph。这是怎么回事呢?
第一,我们实际上已经使用了计算图。在TF里,如果用户不显示地使用一个计算图,系统就会建一个缺省计算图。用户可以通过tf.get_default_graph()函数,或者Session.graph属性获取这个计算图。
第二,由于没有显示地使用计算图,所以代码3-9存在一个缺陷,即如果我们在其他的.py文件中定义了一个新的模型,则它跟当前计算平方根的模型都存在于系统的缺省计算图上。这不但会导致变量名字冲突,当模型不再被使用时,还会为清除模型带来不便。一般地,我们应该让计算图与模型之间一一对应,最好不要在同一个计算图上定义两个独立的模型。
使用计算图的方法是先构建一个tf.Graph对象,然后调用as_default()方法,并在其下创建所有张量。下面是使用计算图求平方根的程序:

运行结果与上一节代码的结果相同。