參考連接:http://sebastianruder.com/optimizing-gradient-descent/html
若是熟悉英文的話,強烈推薦閱讀原文,畢竟翻譯過程當中由於我的理解有限,可能會有謬誤,還望讀者能不吝指出。另外,因爲原文太長,分了兩部分翻譯,本篇主要是梯度降低優化算法的總結,下篇將會是隨機梯度的並行和分佈式,以及優化策略的總結。git
梯度降低是優化中最流行的算法之一,也是目前用於優化神經網絡最經常使用到的方法。同時,每一個優秀的深度學習庫都包含了優化梯度降低的多種算法的實現(好比, lasagne 、 caffe 和 keras 的文檔)。然而,這些算法通常被封裝成優化器,如黑盒通常,所以很可貴到它們實際能力和缺點的解釋。github
本篇博客的目標是爲讀者提供不一樣梯度降低優化算法的直觀解釋,但願讀者能夠學以至用。咱們會先了解下梯度降低的不一樣變種。而後會對訓練過程的問題進行簡單總結。接着,咱們會介紹最經常使用的優化算法,展現它們解決這些問題的動機,以及它們對應更新規則變化的緣由。咱們也就會簡單回顧在並行和分佈式的狀況下,梯度降低優化的算法和架構。最後,咱們也會聊聊有助於優化梯度降低的其餘策略。算法
梯度降低是最小化以模型參數 θ∈Rdθ∈Rd 構建的目標函數 J(θ)J(θ) 的一種方法,它經過按目標函數 ∇θJ(θ)∇θJ(θ) 在參數梯度的相反方向更新參數。學習率 ηη 決定了咱們到達(局部)最小所需的步數的大小。換成通俗的話說,咱們會沿着目標函數所構建的表面坡度的方向往下走,直到咱們到達一個谷底。若是你還不熟悉梯度降低,你能夠參考這篇 優化神經網絡的入門介紹 。網絡
一共有三種不一樣版本的梯度降低,它們的不一樣之處字啊與咱們計算目標函數梯度時使用數據的多少。根據數據量的大小,咱們會在參數更新的準確度和更新花費的時間之間進行權衡。架構
最普通的梯度降低,即批量梯度降低,使用整個訓練數據根據參數 θθ 計算目標函數的梯度:dom
θ=θ−η⋅∇θJ(θ)θ=θ−η⋅∇θJ(θ)分佈式
由於咱們須要計算完整個數據集的梯度才能更新,批量梯度降低很是的耗時,並且面對沒法徹底放入內容的數據集,處理起來也很棘手。批量梯度更新也沒法讓咱們 在線 ,即在運行時加入新的樣本進行模型更新。ide
以代碼的形式,批量梯度降低的形式以下:函數
for i in range(nb_epochs): params_grad = evaluate_gradient(loss_function, data, params) params = params - learning_rate * params_grad
對於預先設定好的訓練迭代次數,咱們首先對於整個數據集根據參數矢量 params
計算損失函數的梯度矢量 weight_grad
。注意最新的深度學習庫提供了自動微分的方法,能夠根據參數高效計算梯度。若是你本身作梯度的微分,那麼最好作一下梯度檢查。(從 這篇文章 能夠獲取一些合理檢查梯度的技巧。)
SGD 的代碼片斷僅僅在訓練樣本時添加了一個循環,根據每一個樣本進行梯度估計。注意咱們會在每次更新訓練時會對訓練數據進行隨機洗牌處理,這會在後面進行解釋:
for i in range(nb_epochs): np.random.shuffle(data) for example in data: params_grad = evaluate_gradient(loss_function, example, params) params = params - learning_rate * params_grad
然而, 傳統的 mini-batch 梯度降低,並沒有法保證好的收斂,但卻有一些須要強調的挑戰:
接下來,咱們將會羅列一些深度學習社區普遍用於處理前面提到的挑戰的算法。咱們將不會討論那些沒法實際處理高維數據集的算法,即二階方法,如 牛頓法 。
2、關於solver.prototxt中相關參數的解釋:
epoch:1個epoch就是將全部的訓練圖像所有經過網絡訓練一次
例如:假若有1280000張圖片,batchsize=256,則1個epoch須要1280000/256=5000次iteration
它的max-iteration=450000,則共有450000/5000=90個epoch
而lr何時衰減與stepsize有關,減小多少與gamma有關,即:若stepsize=500, base_lr=0.01, gamma=0.1,則當迭代到第一個500次時,lr第一次衰減,衰減後的lr=lr*gamma=0.01*0.1=0.001,之後重複該過程,因此
stepsize是lr的衰減步長,gamma是lr的衰減係數。
在訓練過程當中,每到必定的迭代次數都會測試,迭代次數是由test-interval決定的,如test_interval=1000,則訓練集每迭代1000次測試一遍網絡,而
test_size, test_iter, 和test圖片的數量決定了怎樣test, test-size決定了test時每次迭代輸入圖片的數量,test_iter就是test全部的圖片的迭代次數,如:500張test圖片,test_iter=100,則test_size=5, 而solver文檔裏只須要根據test圖片總數量來設置test_iter,以及根據須要設置test_interval便可。
3、關於train.prototxt中相關係數解釋:
name: "LeNet" layer { name: "mnist" type: "Data" //這裏的type還有MemoryData(內存讀取)HDF5Date,HDF5output,ImageDta等 top: "data" //bottom表明輸入,top表明輸出 top: "label" include { phase: TRAIN //該層參數只在訓練階段有效 } transform_param { scale: 0.00390625 //數據變換使用的數據縮放因子,用於數據預處理如剪均值,尺寸變換,隨機剪,鏡像等 } data_param { //數據層參數 source: "./examples/mnist/mnist_train_lmdb" #lmdb路徑 batch_size: 64 //批量數目,一次讀取64張圖 backend: LMDB } } layer { //一個新的數據層,但只在測試階段纔有效 name: "mnist" type: "Data" top: "data" top: "label" include { phase: TEST //該層參數只在測試階段有效 } transform_param { scale: 0.00390625 } data_param { source: "./examples/mnist/mnist_test_lmdb" batch_size: 100 backend: LMDB } } layer { //定義接下來的卷積層 name: "conv1" type: "Convolution" bottom: "data" //輸入爲data top: "conv1" //輸出爲conv1 param { lr_mult: 1 //weights的學習率和全局相同 } param { lr_mult: 2 //biases的學習率是全局的2倍 } convolution_param { //卷積計算參數 num_output: 20 //輸出特徵圖數量爲20,即有20個filters kernel_size: 5 //卷積核的尺寸爲5*5,這裏的卷積核即爲filter stride: 1 //卷積核移動尺寸 weight_filler { //權值使用xavier填充器 type: "xavier" //一種初始化方法 } bias_filler { //bias使用常數填充器,默認爲0 type: "constant" } } } layer { //定義接下來的池化層(又稱下采樣層) name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX //使用最大值下采樣法 kernel_size: 2 //下采樣窗口尺寸爲2*2 stride: 2 //窗口移動尺寸爲2 } } layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 50 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool2" type: "Pooling" bottom: "conv2" top: "pool2" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { //全鏈接層 name: "ip1" type: "InnerProduct" bottom: "pool2" top: "ip1" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 500 //該層輸出元素個數爲500個 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { //非線性層,使用RELU激活函數 name: "relu1" type: "ReLU" bottom: "ip1" top: "ip1" } layer { name: "ip2" type: "InnerProduct" bottom: "ip1" top: "ip2" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 10 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { //分類準確率層,只在TEST階段有效,輸出爲accuracy,該層用於計算準確率 name: "accuracy" type: "Accuracy" bottom: "ip2" bottom: "label" top: "accuracy" include { phase: TEST } } layer { //損失層,採用softmax分類器計算loss值 name: "loss" type: "SoftmaxWithLoss" bottom: "ip2" bottom: "label" top: "loss" }
momentum:動量(又稱動量衰減係數)
weight_decay:正則化懲罰項的係數
總結:
(1)SGD
優勢:簡單方便;
缺點:一、選擇一個合適的學習率很難;二、對於稀疏數據,每一個都是同等的更新,但可能存在就是某些數據須要更多更新,某些只要fintune便可;三、容易陷入局部最小值;
(2)SGD with momentum
優勢:更新時能夠保留以前更新的方向,因此降低時具備慣性更快,且有必定概率逃出局部最小值;
(3)Nexterov 動量降低
優勢:不像傳統的momentum那樣根據慣性來降低,而是根據參數的近似將來位置來更新,更加準確智能;
(4)Adagrad降低
優勢:根據參數自適應地更新學習率,對於不斷頻繁更新的參數做較大更新,對於不多更新的參數做做較小更新,因此咱們不須要手動更新學習率,通常初始化爲0.01;
缺點:因爲分母上累積了梯度的平方,且每一個加上的值都是整數,隨着不斷訓練累積和會不斷增大,致使學習率不斷減少,學習能力愈來愈弱;
(5)Adadelta降低
優勢:它是對Adagrad的擴展,解決了Adagrad激進單調遞減學習率的缺點,它的梯度遞歸的由前面全部梯度的平方的均值來替代,同時還不須要設置初始學習率了;
(6)RMSprop降低:也是用來解決Adagrad學習率降低過快的問題;
(7)ADAM降低:比其餘降低策略更好,具體看上面;
比較:
Karpathy作了一個這幾個方法在MNIST上性能的比較,其結論是:
adagrad相比於sgd和momentum更加穩定,即不須要怎麼調參。而精調的sgd和momentum系列方法不管是收斂速度仍是precision都比adagrad要好一些。在精調參數下,通常Nesterov優於momentum優於sgd。而adagrad一方面不用怎麼調參,另外一方面其性能穩定優於其餘方法。