
3.3 评估和优化模型
在完成模型的基础设计后,为了让模型能够满足实际的生产需要,需要对模型的各种参数进行调整和优化。
3.3.1 评估指标的介绍与使用
模型的评估主要有如下几个指标:准确率、识别的时间和loss下降变化等。
观察这些指标最常用的工具就是TensorFlow提供的可视化工具TensorBoard,TensorBoard提供了对准确率、损失值、权重、偏差值以及各个设备上所消耗内存和时间等的变化情况的观察。在第2章,我们已对相关内容重点进行了介绍。
另一个常用的工具就是Timeline,可以使用它分析在整个模型的计算过程中,每个操作所消耗的时间,由此可以有针对性地优化耗时的操作。
使用Timeline对象获取每个节点的执行时间,主要包括如下步骤。
①在sess.run()中指定可选的参数options和run_metadata。
②在Timeline中使用run_metadata.step_stats()创建一个对象。
③将该对象数据保存为文件。
下面实现矩阵的乘法,使用timeline()方法进行记录并展示,具体实现如下:

运行上述代码,会在代码所在目录中生成一个timeline.json文件。
在谷歌浏览器的地址栏中输入chrome://tracing,将生成的timeline.json文件导入该页面中,显示结果如图3.7所示。

图3.7 模型耗时
图3.7所示界面的顶部就是时间轴,以ms(毫秒)为单位。
从左到右依次为模型一次完整的计算过程中,每个操作在设备上消耗的时间。具体而言,包括该操作的开始时间、结束时间,以及运算操作的输入、名称、类型等。
3.3.2 模型调优的主要方法
对模型评估的准确率、识别的时间、loss下降变化等指标的调优主要包括两类操作:一类是调整模型算法,另一类是调整参数和重构代码。对于调整模型算法,我们将在后续章节中详细介绍,本节着重讲解调整参数和重构代码。
调整参数和重构代码时需要注意的情形,主要包括以下方面。
1.调整学习率
学习率是机器学习中最常设定的参数,表示每次学习调整的变化。学习率设置得越大,训练时间就越短,速度就越快;而学习率设置得越小,训练的准确度就越高。在训练模型的调优过程中,对于学习率的设置需要不断地进行尝试。
在目前最流行的神经网络模型中,训练过程的优化方法基本包括梯度下降法、Momentum法、AdaGrad法、RMSprop和Adam等方法。在这些训练方法中,梯度下降法和Momentum法是需要预先设定学习率的,而其他几种方法是自适应学习率的。
梯度下降法最常见的三种分别为BGD、SGD和MBGD。
□ BGD(Batch Gradient Descent,批梯度下降)。BGD利用现有参数对整个数据集的输入计算相应的输出y值,然后和实际y值进行比较,进而统计误差、计算评价误差,以及作为更新参数的依据。该方法保证了使用所有的训练数据进行计算,能够收敛,不需要逐渐减少学习率;但是计算起来非常慢,遇到大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。
□ SGD(Stochastic Gradient Descent,随机梯度下降)。与BGD一次用所有数据计算梯度相比,SGD每次更新时对每个样本都会进行梯度更新。SGD运行速度比较快,并且可以新增样本,但因为更新比较频繁,可能造成损失值有严重的震荡现象。
□ MBGD(Mini-Batch Gradient Descent,小批量梯度下降法)。MBGD每次利用一小批样本进行计算,这样可以降低参数更新时的方差,收敛更稳定。不过MBGD不能保证很好的收敛性。如果学习率选择的太小,收敛速度会很慢;如果太大,损失值就会在极小值处不停地震荡甚至偏离。而且,对于非凸函数,容易收敛到局部的极小值处,甚至被困在鞍点处。
Momentum法则加入速度变量v,更新时在一定程度上保留之前的更新方向,利用当前批次微调本次的更新参数。这样可以使梯度方向不变的维度上的更新速度变快,使梯度方向有所改变的维度上的更新速度变慢,从而加快收敛并减小震荡。
AdaGrad法对低频的参数做较大的更新,对高频的参数做较小的更新。这样在处理稀疏的数据时就能够有较好的表现,但是由于计算时分母会不断积累,因此学习率就会收缩并最终变得非常小。
RMSprop是Geoff Hinton提出的一种自适应学习率方法,用于解决AdaGrad学习率急剧下降的问题,在实践中对于循环神经网络的效果较好。
Adam是另一种计算每个参数的自适应学习率方法,能够根据梯度的一阶矩和二阶矩进行动态调整。
TensorFlow也提供了这些优化方法,主要包括如下几种。
class tf.train.GradientDescentOptimizer
class tf.train.AdagradOptimizer
class tf.train.MomentumOptimizer
class tf.train.AdamOptimizer
class tf.train.FtrlOptimizer
class tf.train.RMSPropOptimizer
2.优化IO
大家经常接触到的数据读写操作主要有数据预处理、队列以及内存读写等操作。优化IO主要针对这三大数据操作。
第一,在数据预处理阶段,如果数据量比较大,建议在使用TensorFlow官方提供的数据格式TFRecords进行转换后再使用,一般不直接使用feed_dict方式。因为使用feed_dict方式会将所有的输入数据首先全部读取到内存中,然后再执行计算,这样会使数据IO操作和计算操作形成串行。而使用TFRecords格式的数据,由TensorFlow进行调度,TensorFlow会尝试将各种计算操作和数据读取操作在一定程度上形成并行,从而带来性能上的提升。
第二,在处理数据时,最常使用的就是队列。在实际使用中特别需要注意的是min_after_dequeue值的设置。如果该值太大,会使队列试图在内存中保留大量记录,使内存容易达到饱和,从而触发硬盘的交换功能,降低队列的速度。
第三,注意内存的使用,应使整个模型的内存消耗不超出机器内存。如果超出机器内存,必然触发交换功能,从而降低读写速度。
3.优化计算
对于计算的优化,需要根据实际情况进行处理。主要通过对TensorBoard的可视化以及timeline.json文件进行观察,找到耗时多的操作,通过优化执行顺序、并行操作等方式进行具体优化。