Solver 通过协调 Net 的前向推断计算和反向梯度计算(forward inference and backward gradients),来对参数进行更新,从而达到减小 loss 的目的。Caffe 模型的学习被分为两个部分:由 Solver 进行优化、更新参数,由 Net 计算出 loss 和 gradient。
Solver介绍
solver的作用是:每一次迭代之后,怎样去更新权值,使得所有迭代结束后,总体损失是全局最优解。solver是一个统筹整个Net在不断运行的方式。
负责对模型优化,让损失函数(loss function)达到全局最小。
solver的主要作用就是交替调用前向(forward)算法和后向(backward)算法来更新参数,实际上就是一种迭代的优化算法。
在每一次的迭代过程中,solver做了这几步工作:
1. 调用forward算法来计算最终的输出值,以及对应的loss
2. 调用backward算法来计算每层的梯度
3. 根据选用的slover方法,利用梯度进行参数更新
4. 记录并保存每次迭代的学习率、快照,以及对应的状态
Solver求解最优化问题
从caffe社区翻译的官方教程中截的图
Caffe 支持的 solvers 包括:
- Stochastic Gradient Descent (type: “SGD”),随机梯度下降
- AdaDelta (type: “AdaDelta”)
- Adaptive Gradient (type: “AdaGrad”),自适应梯度
- Adam (type: “Adam”)
- Nesterov’s Accelerated Gradient (type: “Nesterov”) and
- RMSprop (type: “RMSProp”)
其中最常用的是SGD算法。
Solver参数配置
Solver的可配置参数都在caffe.proto中SolverParameter类中定义。
# The train/test net protocol buffer definition
net: "examples/mnist/lenet_train_test.prototxt"//选取Net的定义文件
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
test_iter: 100 //测试迭代次数,如果batch_size=100,则测试迭代100次,测试集有10000张图片可以被覆盖。
# Carry out testing every 500 training iterations.
test_interval: 500 //测试间隔,意思是每训练迭代500次,进行一次测试迭代。
# The base learning rate, momentum and the weight decay of the network.
base_lr: 0.01 //学习率
momentum: 0.9 //动量
weight_decay: 0.0005 //权重的衰减
# The learning rate policy //学习策略:有固定学习率和每步递减学习率
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# Display every 100 iterations //每迭代100次显示一次
display: 100
# The maximum number of iterations //最大迭代次数,也就是总共迭代次数
max_iter: 10000
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
# solver mode: CPU or GPU //使用GPU和CPU
solver_mode: CPU
net: “examples/mnist/lenet_train_test.prototxt”
设置深度网络模型。每一个模型就是一个net,需要在一个专门的配置文件中对net进行配置,每个net由许多的layer所组成。注意的是:文件的路径要从caffe的根目录开始,其它的所有配置都是这样。也可用train_net和test_net来对训练模型和测试模型分别设定:
train_net:"examples/mnist/lenet_train_test.prototxt"
test_net: "examples/mnist/lenet_test_test.prototxt"
test_iter: 100
mnist数据中测试样本总数为10000,一次性执行全部数据效率很低,因此我们将测试数据分成几个批次来执行,每个批次的数量就是batch_size。假设我们设置batch_size为100,则需要迭代100次才能将10000个数据全部执行完。因此test_iter设置为100。执行完一次全部数据,称之为一个epoch。
test_interval: 500
在训练集中每迭代500次,在测试集进行一次测试。
type: SGD
采用梯度下降算法求解。
SGD算法介绍
随机梯度下降(Stochastic gradient descent, type:”SGD”)利用负梯度 ∇L(W)和上一次权重的更新值Vt 的线性组合来更新权重 W。学习率(learning rate)α 是负梯度的权重。动量(momentum)μ 是上一次更新值的权重。
有如下公式,根据上一次计算的更新值V t 和当前权重W t 来计算本次的更新值V t+1 和权重W t+1 :
学习的超参数(α 和 μ)需要一定的调整才能达到最好的效果。
SGD参数配置
一个比较好的建议是,将学习速率( learning rate α)初始化为α ≈ 0.01 = 10 2 ,然后在训练(training)中当 loss 达到稳定时,将 α 除以一个常数(例如 10),将这个过程重复多次。对于动量(momentum μ)一般设置为μ = 0.9,μ 使 weight 的更新更为平缓,使学习过程更为稳定、快速。
base_lr: 0.01 # 开始学习速率为:α = 0.01=1e-2
lr_policy: "step" # 学习策略: 每 stepsize 次迭代之后,将 α 乘以 gamma
gamma: 0.1 # 学习速率变化因子
stepsize: 100000 # 每 100K 次迭代,降低学习速率
max_iter: 350000 # 训练的最大迭代次数 350K
momentum: 0.9