目录:

  • 原文
  • Solver
  • Methods
    • SGD
    • AdaGrad
    • NAG
  • Scaffolding
  • Updating Parameters
  • Snapshotting and Resuming

原文


Solver

Solver通过协调Net的前向loss计算和反向梯度计算(forward inference and backward gradients),对参数进行更新,以减小loss。Caffe模型的学习被分为两个部分:由Solver进行优化、更新参数,由Net计算出loss和gradient。

Caffe提供了3种Solver方法:Stochastic Gradient Descent(SGD,随机梯度下降),Adaptive Gradient(ADAGRAD,自适应梯度下降)和Nesterov’s Accelerated Gradient(NESTEROV,Nesterov提出的加速梯度下降)。

Solve步骤:

  1. 设计优化对象、训练网络(用于学习)和测试网络(用于评估)
  2. 通过forward和backward迭代以优化和更新参数
  3. 周期性地评估测试网络
  4. 在优化过程中显示(snapshot)模型和solver的状态

每一次迭代中:

  1. 调用Net的forward pass计算出output 和loss
  2. 调用Net的backward pass计算出gradients
  3. 根据Solver方法,利用gradients更新参数
  4. 根据learning rate,history和method更新solver的状态

Caffe solvers有CPU / GPU两种模式。


Methods

Solver Methods用于最小化loss值。给定一个数据集D,优化的目标是D中所有数据的平均loss,即使平均loss取最小值。

其中 fW(X(i))是data中X(i)项的loss,r(W)是正则项,权重为λ。当数据量很大时(直接采用普通的梯度下降方法计算量很大),在每一次迭代中,我们采用数据集的一个子集(mini-batch)来近似代替,其数据量远小于整个数据集:

在forward pass中计算fW(即loss),在backward pass中计算∇fW(即gradient)。

SGD

  • 类型:SGD

随机梯度下降(Stochastic gradient)利用(负的)gradient ∇L(W)上一次权重的更新值Vt的线性组合来更新权重W学习速率(learning rate)α是(负的)gradient的权重。动量(momentum )μ是上一次更新值得权重。

有如下公式,根据上一次计算的更新值Vt和当前权重来计算本次的更新值Vt+1和权重 Wt+1:

学习的参数(α和μ)需要一定的调整才能达到最好的效果。如果你不是很清楚该怎样做的话,请看下面的“经验”,更多的细节请参考Leon Bottou的Stochastic Gradient Descent Tricks

设置学习速率( learning rate α)和动量(momentum μ)的经验:

一个比较好的建议是,将学习速率( learning rate α)初始化为α≈0.01,然后在训练(training)中当loss达到稳定时,将α除以一个常数(例如,10)。对于,动量(momentum μ)一般设置为μ=0.9,μ使weight的更新更为平缓,是学习过程更为稳定、快速。

这是Krizhevsky提出的技巧【文献1】,Caffe实现了SolverParameter让这个技巧易于实现。详见:./examples/imagenet/alexnet_solver.prototxt

要使用上述技巧,可以将下面的代码添加到自定义的solver prototxt文件中:

base_lr: 0.01     # 开始学习速率为:α = 0.01
lr_policy: "step" # 学习策略: 每stepsize次迭代之后,将α乘以gamma
gamma: 0.1        # 学习速率变化因子
stepsize: 100000  # 每100K次迭代,下降学习速率
max_iter: 350000  # 训练的最大迭代次数
momentum: 0.9     # momentum为:μ = 0.01

上面的例子中,我们将动量μ设为常数0.9。刚开始前100K次迭代时学习速率α设置为0.01,然后第100K~200K次迭代时将学习速率α乘以gamma (γ),即为α′=αγ=(0.01)*(0.1)=0.001,之后第200K~300K次迭代时学习速率为α′′=0.00001,最后第301K~350K次迭代时学习速率为α′′=0.000001.

上述例子中,当训练次数达到一定量后,计算量会扩大到1/(1-μ)倍,所以如果增加μ的话,最好是减少α值(反之相反)。举个例子, 设μ=0.9,则计算量会扩大1/(1-μ)=10倍。如果将μ扩大为0.99,那么计算量会扩大100倍,所以α应该除以10.

上述技巧也只是经验之谈,不保证绝对有用,甚至有副作用。如果训练过程中出现了发散现象(例如,loss或者output值非常大),试着减小开始学习速率(base_lr)再训练,重复这个过程,直到找到一个比较合适的学习速率。

【文献1】:A. Krizhevsky, I. Sutskever, and G. Hinton. ImageNet Classification with Deep Convolutional Neural Networks. Advances in Neural Information Processing Systems, 2012.

AdaGrad

  • 类型:ADAGRAD

自适应梯度下降方法( Adaptive gradient)【文献1】跟随机梯度下降(Stochastic gradient)一样是基于梯度的优化方法。给定之前更新的信息:,按照下面的公式更新参数:

实际操作中,对于权重,自适应梯度(AdaGrad )只需要额外空间存储历史信息,而不是的存储空间来存储所有的历史纪录。

【文献1】: Duchi, E. Hazan, and Y. Singer. Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. The Journal of Machine Learning Research, 2011.

NAG

  • 类型:NESTEROV

Nesterov提出的加速梯度下降(Nesterov’s accelerated gradient)是Nesterov提出的凸优化的最佳方法【文献1】,其收敛速度可以达到,而不是。尽管在Caffe中并不是一定能够满足收敛于的条件(例如,由于非平滑non-smoothness和non-convexity非凸)实际中NAG对于某类特定结构的深度学习模型是一个非常有效的方法【文献2】。

权重weight更新参数与随机梯度下降(Stochastic gradient)非常相似:

与SGD的不同之处在于梯度∇L(W)项中取值不同:在NAG中,对于权重W梯度的计算要机上动量=>∇L(Wt+μVt);在SGD中,只是简单的计算当前权重的动量=>∇L(Wt)。

【文献1】:Y. Nesterov. A Method of Solving a Convex Programming Problem with Convergence Rate O(1/k√). Soviet Mathematics Doklady, 1983.
【文献2】:I. Sutskever, J. Martens, G. Dahl, and G. Hinton. On the Importance of Initialization and Momentum in Deep Learning. Proceedings of the 30th International Conference on Machine Learning, 2013.


Scaffolding

Solver::Presolve()方法:准备用于优化的方法及初始化模型。

> caffe train -solver examples/mnist/lenet_solver.prototxt
I0902 13:35:56.474978 16020 caffe.cpp:90] Starting Optimization
I0902 13:35:56.475190 16020 solver.cpp:32] Initializing solver from parameters:
test_iter: 100
test_interval: 500
base_lr: 0.01
display: 100
max_iter: 10000
lr_policy: "inv"
gamma: 0.0001
power: 0.75
momentum: 0.9
weight_decay: 0.0005
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
solver_mode: GPU
net: "examples/mnist/lenet_train_test.prototxt"

Net initialization(网络初始化)

I0902 13:35:56.655681 16020 solver.cpp:72] Creating training net from net file: examples/mnist/lenet_train_test.prototxt
[...]
I0902 13:35:56.656740 16020 net.cpp:56] Memory required for data: 0
I0902 13:35:56.656791 16020 net.cpp:67] Creating Layer mnist
I0902 13:35:56.656811 16020 net.cpp:356] mnist -> data
I0902 13:35:56.656846 16020 net.cpp:356] mnist -> label
I0902 13:35:56.656874 16020 net.cpp:96] Setting up mnist
I0902 13:35:56.694052 16020 data_layer.cpp:135] Opening lmdb examples/mnist/mnist_train_lmdb
I0902 13:35:56.701062 16020 data_layer.cpp:195] output data size: 64,1,28,28
I0902 13:35:56.701146 16020 data_layer.cpp:236] Initializing prefetch
I0902 13:35:56.701196 16020 data_layer.cpp:238] Prefetch initialized.
I0902 13:35:56.701212 16020 net.cpp:103] Top shape: 64 1 28 28 (50176)
I0902 13:35:56.701230 16020 net.cpp:103] Top shape: 64 1 1 1 (64)
[...]
I0902 13:35:56.703737 16020 net.cpp:67] Creating Layer ip1
I0902 13:35:56.703753 16020 net.cpp:394] ip1 <- pool2
I0902 13:35:56.703778 16020 net.cpp:356] ip1 -> ip1
I0902 13:35:56.703797 16020 net.cpp:96] Setting up ip1
I0902 13:35:56.728127 16020 net.cpp:103] Top shape: 64 500 1 1 (32000)
I0902 13:35:56.728142 16020 net.cpp:113] Memory required for data: 5039360
I0902 13:35:56.728175 16020 net.cpp:67] Creating Layer relu1
I0902 13:35:56.728194 16020 net.cpp:394] relu1 <- ip1
I0902 13:35:56.728219 16020 net.cpp:345] relu1 -> ip1 (in-place)
I0902 13:35:56.728240 16020 net.cpp:96] Setting up relu1
I0902 13:35:56.728256 16020 net.cpp:103] Top shape: 64 500 1 1 (32000)
I0902 13:35:56.728270 16020 net.cpp:113] Memory required for data: 5167360
I0902 13:35:56.728287 16020 net.cpp:67] Creating Layer ip2
I0902 13:35:56.728304 16020 net.cpp:394] ip2 <- ip1
I0902 13:35:56.728333 16020 net.cpp:356] ip2 -> ip2
I0902 13:35:56.728356 16020 net.cpp:96] Setting up ip2
I0902 13:35:56.728690 16020 net.cpp:103] Top shape: 64 10 1 1 (640)
I0902 13:35:56.728705 16020 net.cpp:113] Memory required for data: 5169920
I0902 13:35:56.728734 16020 net.cpp:67] Creating Layer loss
I0902 13:35:56.728747 16020 net.cpp:394] loss <- ip2
I0902 13:35:56.728767 16020 net.cpp:394] loss <- label
I0902 13:35:56.728786 16020 net.cpp:356] loss -> loss
I0902 13:35:56.728811 16020 net.cpp:96] Setting up loss
I0902 13:35:56.728837 16020 net.cpp:103] Top shape: 1 1 1 1 (1)
I0902 13:35:56.728849 16020 net.cpp:109]     with loss weight 1
I0902 13:35:56.728878 16020 net.cpp:113] Memory required for data: 5169924

Loss(损失)

I0902 13:35:56.728893 16020 net.cpp:170] loss needs backward computation.
I0902 13:35:56.728909 16020 net.cpp:170] ip2 needs backward computation.
I0902 13:35:56.728924 16020 net.cpp:170] relu1 needs backward computation.
I0902 13:35:56.728938 16020 net.cpp:170] ip1 needs backward computation.
I0902 13:35:56.728953 16020 net.cpp:170] pool2 needs backward computation.
I0902 13:35:56.728970 16020 net.cpp:170] conv2 needs backward computation.
I0902 13:35:56.728984 16020 net.cpp:170] pool1 needs backward computation.
I0902 13:35:56.728998 16020 net.cpp:170] conv1 needs backward computation.
I0902 13:35:56.729014 16020 net.cpp:172] mnist does not need backward computation.
I0902 13:35:56.729027 16020 net.cpp:208] This network produces output loss
I0902 13:35:56.729053 16020 net.cpp:467] Collecting Learning Rate and Weight Decay.
I0902 13:35:56.729071 16020 net.cpp:219] Network initialization done.
I0902 13:35:56.729085 16020 net.cpp:220] Memory required for data: 5169924
I0902 13:35:56.729277 16020 solver.cpp:156] Creating test net (#0) specified by net file: examples/mnist/lenet_train_test.prototxt

Completion(完成)

I0902 13:35:56.806970 16020 solver.cpp:46] Solver scaffolding done.
I0902 13:35:56.806984 16020 solver.cpp:165] Solving LeNet

Updating Parameters

权重更新是在Solver::ComputeUpdateValue()中完成的。ComputeUpdateValue方法利用权重衰减项(weight decay)计算出权重梯度(weight gradients)(现阶段还只有误差梯度),进而计算出每个权重最后的梯度。然后经过与学习速率α相乘后,该值被存储于每一个参数(Blob的diff域)中。最后,调用每个参数的Blob::Update()方法进行最后的参数更新(Blob的data值减去diff值)。


Snapshotting and Resuming

Solver使用Solver::Snapshot()方法保存权重的值,使用Solver::SnapshotSolverState()保存状态。保存的权重表示当前学习到的模型,并且允许从该状态继续进行学习。训练可以通过Solver::Restore()方法和Solver::RestoreSolverState()方法继续进行。

权重保存文件没有拓展名,状态保存文件的拓展名是.solverstate extension,每种文件都有一个_iter_N后缀,表明保存时的迭代次数。

在Solver定义文件(*_solver.prototxt)中,保存方法是如下定义:

# 保存间隔(单位:迭代次数)
snapshot: 5000
# 保存文件的前缀,注意:是相对于caffe根目录,而不是具体Solver定义文件目录
snapshot_prefix: "/path/to/model"
# 是否保存Blob的diff域(存储梯度值),有助于debug,但是耗费更多存储空间
snapshot_diff: false
# 训练完成后是否保存最后的状态,默认是True
snapshot_after_train: true

Caffe学习:Solver相关推荐

  1. Caffe学习系列(7):solver及其配置

    solver算是caffe的核心的核心,它协调着整个模型的运作.caffe程序运行必带的一个参数就是solver配置文件.运行代码一般为 # caffe train --solver=*_slover ...

  2. Caffe学习系列(8):solver优化方法

    Caffe学习系列(8):solver优化方法 上文提到,到目前为止,caffe总共提供了六种优化方法: Stochastic Gradient Descent (type: "SGD&qu ...

  3. 利用Caffe训练模型(solver、deploy、train_val) + python如何使用已训练模型

    版权声明:博主原创文章,微信公众号:素质云笔记,转载请注明来源"素质云博客",谢谢合作!! https://blog.csdn.net/sinat_26917383/article ...

  4. Caffe学习系列(23):如何将别人训练好的model用到自己的数据上

    caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...

  5. Caffe学习系列(19): 绘制loss和accuracy曲线

    转载自: Caffe学习系列(19): 绘制loss和accuracy曲线 - denny402 - 博客园 http://www.cnblogs.com/denny402/p/5110204.htm ...

  6. Caffe学习系列(12):训练和测试自己的图片

    学习caffe的目的,不是简单的做几个练习,最终还是要用到自己的实际项目或科研中.因此,本文介绍一下,从自己的原始图片到lmdb数据,再到训练和测试模型的整个流程. 一.准备数据 有条件的同学,可以去 ...

  7. Caffe学习系列(3):视觉层(Vision Layers)及参数

    所有的层都具有的参数,如name, type, bottom, top和transform_param请参看我的前一篇文章:Caffe学习系列(2):数据层及参数 本文只讲解视觉层(Vision La ...

  8. caffe学习(五):cifar-10数据集训练及测试(Ubuntu)

    简介 网站链接:CIFAR-10 CIFAR-10数据集包括由10个类别的事物,每个事物各有6000张彩色图像,每张图片的大小是32*32. 整个数据集被分成了5个训练集和1个测试集,各有10000张 ...

  9. Caffe学习笔记3——制作并训练自己的数据集

    Caffe学习笔记3 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和h ...

  10. Caffe 学习笔记1

    Caffe 学习笔记1 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和 ...

最新文章

  1. vscode使用教程python-用VSCode写python的正确姿势
  2. set和multiset
  3. angular 图片引入_推荐一个 angular 图像加载插件
  4. hdu 5585 判断一个数能否被3整除
  5. 使用cloudera manager安装Oozie服务【详细步骤】
  6. 实验室最拼命的博士生,为什么却面临延毕?
  7. 首屏动画及验证网络状态跳转
  8. 东北林业大学c语言期末考试题,东北林业大学 2008年C语言考试试卷及答案.doc
  9. Python判断文件是否存在、访问
  10. (转) Csrss进程剖析
  11. 关于LTE下行导频信号
  12. 代码不规范,亲人两行泪——DTO
  13. oracle 怎么做日期计算,oracle日期计算
  14. git密匙的创建与git的基本操作
  15. 《那些年啊,那些事——一个程序员的奋斗史》——24
  16. 刷屏黑洞照片背后,有17名中国科学家
  17. 背景信息在网上轻松群发短信程序
  18. 注册表与盘符(转victor888文章 )
  19. “燕云十六将”之Jason郝钰(12)
  20. 如何从计算机截屏到U盘,win7电脑如何实现截图

热门文章

  1. C++--第14课 - 专题二经典问题解析
  2. 凸优化第四章凸优化问题 4.6 广义不等式约束
  3. kotlin使用spring data jpa(三)
  4. http性能测试点滴
  5. 前端开源项目周报0103
  6. SQL SERVER 2008 索引、数据存储基本理论【原创】
  7. 标准I/O缓冲:全缓冲、行缓冲、无缓冲
  8. Yii框架官方指南系列53——专题:使用命令行生成代码(已废弃)
  9. IntelliCAD 2009 Pro Plus v6.4.23.2 1CD
  10. 关于通用配置管理模块的思考-续(用XmlDocument 还是DataSet)