一.資料層及參數
要運作caffe,需要先建立一個模型(model),如比較常用的Lenet,Alex等, 而一個模型由多個屋(layer)構成,每一屋又由許多參數組成。所有的參數都定義在caffe.proto這個檔案中。要熟練使用caffe,最重要的就是學會配置檔案(prototxt)的編寫。
層有很多種類型,比如Data,Convolution,Pooling等,層之間的資料流動是以Blobs的方式進行。
今天我們就先介紹一下資料層.
資料層是每個模型的最底層,是模型的入口,不僅提供資料的輸入,也提供資料從Blobs轉換成别的格式進行儲存輸出。通常資料的預處理(如減去均值, 放大縮小, 裁剪和鏡像等),也在這一層設定參數實作。
資料來源可以來自高效的資料庫(如LevelDB和LMDB),也可以直接來自于記憶體。如果不是很注重效率的話,資料也可來自磁盤的hdf5檔案和圖檔格式檔案。
所有的資料層的都具有的公用參數:先看示例
layer {
name: "cifar"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mean_file: "examples/cifar10/mean.binaryproto"
}
data_param {
source: "examples/cifar10/cifar10_train_lmdb"
batch_size: 100
backend: LMDB
}
}
name: 表示該層的名稱,可随意取
type: 層類型,如果是Data,表示資料來源于LevelDB或LMDB。根據資料的來源不同,資料層的類型也不同(後面會詳細闡述)。一般在練習的時候,我們都是采用的LevelDB或LMDB資料,是以層類型設定為Data。
top或bottom: 每一層用bottom來輸入資料,用top來輸出資料。如果隻有top沒有bottom,則此層隻有輸出,沒有輸入。反之亦然。如果有多個 top或多個bottom,表示有多個blobs資料的輸入和輸出。
data 與 label: 在資料層中,至少有一個命名為data的top。如果有第二個top,一般命名為label。 這種(data,label)配對是分類模型所必需的。
include: 一般訓練的時候和測試的時候,模型的層是不一樣的。該層(layer)是屬于訓練階段的層,還是屬于測試階段的層,需要用include來指定。如果沒有include參數,則表示該層既在訓練模型中,又在測試模型中。
Transformations: 資料的預處理,可以将資料變換到定義的範圍内。如設定scale為0.00390625,實際上就是1/255, 即将輸入資料由0-255歸一化到0-1之間
其它的資料預處理也在這個地方設定:
transform_param {
scale: 0.00390625
mean_file_size: "examples/cifar10/mean.binaryproto"
# 用一個配置檔案來進行均值操作
mirror: 1 # 1表示開啟鏡像,0表示關閉,也可用ture和false來表示
# 剪裁一個 227*227的圖塊,在訓練階段随機剪裁,在測試階段從中間裁剪
crop_size: 227
}
在caffe中,如果定義了crop_size,那麼在train時會對大于crop_size的圖檔進行随機裁剪,而在test時隻是截取中間部分(詳見/caffe/src/caffe/data_transformer.cpp):
1、資料來自于資料庫(如LevelDB和LMDB)
層類型(layer type):Data
必須設定的參數:
source: 包含資料庫的目錄名稱,如examples/mnist/mnist_train_lmdb
batch_size: 每次處理的資料個數,如64
可選的參數:
rand_skip: 在開始的時候,路過某個資料的輸入。通常對異步的SGD很有用。
backend: 選擇是采用LevelDB還是LMDB, 預設是LevelDB.
示例:
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/mnist/mnist_train_lmdb"
batch_size: 64
backend: LMDB
}
}
2、資料來自于記憶體
層類型:MemoryData
必須設定的參數:
batch_size:每一次處理的資料個數,比如2
channels:通道數
height:高度
width: 寬度
示例:
layer {
top: "data"
top: "label"
name: "memory_data"
type: "MemoryData"
memory_data_param{
batch_size: 2
height: 100
width: 100
channels: 1
}
transform_param {
scale: 0.0078125
mean_file: "mean.proto"
mirror: false
}
}
3、資料來自于HDF5
層類型:HDF5Data
必須設定的參數:
source: 讀取的檔案名稱
batch_size: 每一次處理的資料個數
示例:
layer {
name: "data"
type: "HDF5Data"
top: "data"
top: "label"
hdf5_data_param {
source: "examples/hdf5_classification/data/train.txt"
batch_size: 10
}
}
4、資料來自于圖檔
層類型:ImageData
必須設定的參數:
source: 一個文本檔案的名字,每一行給定一個圖檔檔案的名稱和标簽(label)
batch_size: 每一次處理的資料個數,即圖檔數
可選參數:
rand_skip: 在開始的時候,路過某個資料的輸入。通常對異步的SGD很有用。
shuffle: 随機打亂順序,預設值為false
new_height,new_width: 如果設定,則将圖檔進行resize
示例:
layer {
name: "data"
type: "ImageData"
top: "data"
top: "label"
transform_param {
mirror: false
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
image_data_param {
source: "examples/_temp/file_list.txt"
batch_size: 50
new_height: 256
new_width: 256
}
}
5、資料來源于Windows
層類型:WindowData
必須設定的參數:
source: 一個文本檔案的名字
batch_size: 每一次處理的資料個數,即圖檔數
示例:
layer {
name: "data"
type: "WindowData"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mirror: true
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
window_data_param {
source: "examples/finetune_pascal_detection/window_file_2007_trainval.txt"
batch_size: 128
fg_threshold: 0.5
bg_threshold: 0.5
fg_fraction: 0.25
context_pad: 16
crop_mode: "warp"
}
}
二.視覺層(Vision Layers)及參數
本文隻講解視覺層(Vision Layers)的參數,視覺層包括Convolution, Pooling, Local Response Normalization (LRN), im2col等層。
1、Convolution層:
就是卷積層,是卷積神經網絡(CNN)的核心層。
層類型:Convolution
lr_mult: 學習率的系數,最終的學習率是這個數乘以solver.prototxt配置檔案中的base_lr。如果有兩個lr_mult, 則第一個表示權值的學習率,第二個表示偏置項的學習率。一般偏置項的學習率是權值學習率的兩倍。
在後面的convolution_param中,我們可以設定卷積層的特有參數。
必須設定的參數:
num_output: 卷積核(filter)的個數
kernel_size: 卷積核的大小。如果卷積核的長和寬不等,需要用kernel_h和kernel_w分别設定
其它參數:
stride: 卷積核的步長,預設為1。也可以用stride_h和stride_w來設定。
pad: 擴充邊緣,預設為0,不擴充。 擴充的時候是左右、上下對稱的,比如卷積核的大小為5*5,那麼pad設定為2,則四個邊緣都擴充2個像素,即寬度和高度都擴充了4個像素,這樣卷積運算之後的特征圖就不會變小。也可以通過pad_h和pad_w來分别設定。
weight_filler: 權值初始化。 預設為“constant",值全為0,很多時候我們用"xavier"算法來進行初始化,也可以設定為”gaussian"
bias_filler: 偏置項的初始化。一般設定為"constant",值全為0。
bias_term: 是否開啟偏置項,預設為true, 開啟
group: 分組,預設為1組。如果大于1,我們限制卷積的連接配接操作在一個子集内。如果我們根據圖像的通道來分組,那麼第i個輸出分組隻能與第i個輸入分組進行連接配接。
輸入:n*c0*w0*h0
輸出:n*c1*w1*h1
其中,c1就是參數中的num_output,生成的特征圖個數
w1=(w0+2*pad-kernel_size)/stride+1;
h1=(h0+2*pad-kernel_size)/stride+1;
如果設定stride為1,前後兩次卷積部分存在重疊。如果設定pad=(kernel_size-1)/2,則運算後,寬度和高度不變。
示例:
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
2、Pooling層
也叫池化層,為了減少運算量和資料次元而設定的一種層。
層類型:Pooling
必須設定的參數:
kernel_size: 池化的核大小,如何确定大小?。也可以用kernel_h和kernel_w分别設定。
其它參數:
pool: 池化方法,預設為MAX。目前可用的方法有MAX, AVE, 或STOCHASTIC
pad: 和卷積層的pad的一樣,進行邊緣擴充。預設為0
stride: 池化的步長,預設為1。一般我們設定為2,即不重疊(步長=視窗大小)。也可以用stride_h和stride_w來設定。
示例:
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
pooling層的運算方法基本是和卷積層是一樣的。
輸入:n*c*w0*h0
輸出:n*c*w1*h1
和卷積層的差別就是其中的c保持不變
w1=(w0+2*pad-kernel_size)/stride+1;
h1=(h0+2*pad-kernel_size)/stride+1;
如果設定stride為2,前後兩次卷積部分重疊。
3、Local Response Normalization (LRN)層
此層是對一個輸入的局部區域進行歸一化,達到“側抑制”的效果。可去搜尋AlexNet或GoogLenet,裡面就用到了這個功能
層類型:LRN
參數:全部為可選,沒有必須
local_size: 預設為5。如果是跨通道LRN,則表示求和的通道數;如果是在通道内LRN,則表示求和的正方形區域長度。
alpha: 預設為1,歸一化公式中的參數。
beta: 預設為5,歸一化公式中的參數。
norm_region: 預設為ACROSS_CHANNELS。有兩個選擇,ACROSS_CHANNELS表示在相鄰的通道間求和歸一化。WITHIN_CHANNEL表示在一個通道内部特定的區域内進行求和歸一化。與前面的local_size參數對應。
歸一化公式:對于每一個輸入, 去除以,得到歸一化後的輸出
示例:
layers {
name: "norm1"
type: LRN
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
4、im2col層
如果對matlab比較熟悉的話,就應該知道im2col是什麼意思。它先将一個大矩陣,重疊地劃分為多個子矩陣,對每個子矩陣序列化成向量,最後得到另外一個矩陣。
看一看圖就知道了:
在caffe中,卷積運算就是先對資料進行im2col操作,再進行内積運算(inner product)。這樣做,比原始的卷積操作速度更快。
看看兩種卷積操作的異同:
三.激活層(Activiation Layers)及參數
在激活層中,對輸入資料進行激活操作(實際上就是一種函數變換),是逐元素進行運算的。從bottom得到一個blob資料輸入,運算後,從top輸入一個blob資料。在運算過程中,沒有改變資料的大小,即輸入和輸出的資料大小是相等的。
輸入:n*c*h*w
輸出:n*c*h*w
常用的激活函數有sigmoid, tanh,relu等,下面分别介紹。
1、Sigmoid
對每個輸入資料,利用sigmoid函數執行操作。這種層設定比較簡單,沒有額外的參數。
層類型:Sigmoid
示例:
layer {
name: "encode1neuron"
bottom: "encode1"
top: "encode1neuron"
type: "Sigmoid"
}
2、ReLU / Rectified-Linear and Leaky-ReLU
ReLU是目前使用最多的激活函數,主要因為其收斂更快,并且能保持同樣效果。
标準的ReLU函數為max(x, 0),當x>0時,輸出x; 當x<=0時,輸出0
f(x)=max(x,0)
層類型:ReLU
可選參數:
negative_slope:預設為0. 對标準的ReLU函數進行變化,如果設定了這個值,那麼資料為負數時,就不再設定為0,而是用原始資料乘以negative_slope
layer {
name: "relu1"
type: "ReLU"
bottom: "pool1"
top: "pool1"
}
RELU層支援in-place計算,這意味着bottom的輸出和輸入相同以避免記憶體的消耗。
3、TanH / Hyperbolic Tangent
利用雙曲正切函數對資料進行變換。
層類型:TanH
layer {
name: "layer"
bottom: "in"
top: "out"
type: "TanH"
}
4、Absolute Value
求每個輸入資料的絕對值。
f(x)=Abs(x)
層類型:AbsVal
layer {
name: "layer"
bottom: "in"
top: "out"
type: "AbsVal"
}
5、Power
對每個輸入資料進行幂運算
f(x)= (shift + scale * x) ^ power
層類型:Power
可選參數:
power: 預設為1
scale: 預設為1
shift: 預設為0
layer {
name: "layer"
bottom: "in"
top: "out"
type: "Power"
power_param {
power: 2
scale: 1
shift: 0
}
}
6、BNLL
binomial normal log likelihood的簡稱
f(x)=log(1 + exp(x))
層類型:BNLL
layer {
name: "layer"
bottom: "in"
top: "out"
type: “BNLL”
}
四.其它常用層及參數
本文講解一些其它的常用層,包括:softmax_loss層,Inner Product層,accuracy層,reshape層和dropout層及其它們的參數配置。
1、softmax-loss
softmax-loss層和softmax層計算大緻是相同的。softmax是一個分類器,計算的是類别的機率(Likelihood),是Logistic Regression 的一種推廣。Logistic Regression 隻能用于二分類,而softmax可以用于多分類。
softmax與softmax-loss的差別:
softmax計算公式:
而softmax-loss計算公式:
關于兩者的差別更加具體的介紹,可參考:softmax vs. softmax-loss
使用者可能最終目的就是得到各個類别的機率似然值,這個時候就隻需要一個 Softmax層,而不一定要進行softmax-Loss 操作;或者是使用者有通過其他什麼方式已經得到了某種機率似然值,然後要做最大似然估計,此時則隻需要後面的 softmax-Loss 而不需要前面的 Softmax 操作。是以提供兩個不同的 Layer 結構比隻提供一個合在一起的 Softmax-Loss Layer 要靈活許多。
不管是softmax layer還是softmax-loss layer,都是沒有參數的,隻是層類型不同而也
softmax-loss layer:輸出loss值
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip1"
bottom: "label"
top: "loss"
}
softmax layer: 輸出似然值
layers {
bottom: "cls3_fc"
top: "prob"
name: "prob"
type: “Softmax"
}
2、Inner Product
全連接配接層,把輸入當作成一個向量,輸出也是一個簡單向量(把輸入資料blobs的width和height全變為1)。
輸入: n*c0*h*w
輸出: n*c1*1*1
全連接配接層實際上也是一種卷積層,隻是它的卷積核大小和原資料大小一緻。是以它的參數基本和卷積層的參數一樣。
層類型:InnerProduct
lr_mult: 學習率的系數,最終的學習率是這個數乘以solver.prototxt配置檔案中的base_lr。如果有兩個lr_mult, 則第一個表示權值的學習率,第二個表示偏置項的學習率。一般偏置項的學習率是權值學習率的兩倍。
必須設定的參數:
num_output: 過濾器(filfter)的個數
其它參數:
weight_filler: 權值初始化。 預設為“constant",值全為0,很多時候我們用"xavier"算法來進行初始化,也可以設定為”gaussian"
bias_filler: 偏置項的初始化。一般設定為"constant",值全為0。
bias_term: 是否開啟偏置項,預設為true, 開啟
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
3、accuracy
輸出分類(預測)精确度,隻有test階段才有,是以需要加入include參數。
層類型:Accuracy
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
4、reshape
在不改變資料的情況下,改變輸入的次元。
層類型:Reshape
先來看例子
layer {
name: "reshape"
type: "Reshape"
bottom: "input"
top: "output"
reshape_param {
shape {
dim: 0 # copy the dimension from below
dim: 2
dim: 3
dim: -1 # infer it from the other dimensions
}
}
}
有一個可選的參數組shape, 用于指定blob資料的各維的值(blob是一個四維的資料:n*c*w*h)。
dim:0 表示次元不變,即輸入和輸出是相同的次元。
dim:2 或 dim:3 将原來的次元變成2或3
dim:-1 表示由系統自動計算次元。資料的總量不變,系統會根據blob資料的其它三維來自動計算目前維的次元值 。
假設原資料為:64*3*28*28, 表示64張3通道的28*28的彩色圖檔
經過reshape變換:
reshape_param {
shape {
dim: 0
dim: 0
dim: 14
dim: -1
}
}
輸出資料為:64*3*14*56
5、Dropout
Dropout是一個防止過拟合的trick。可以随機讓網絡某些隐含層節點的權重不工作。
先看例子:
layer {
name: "drop7"
type: "Dropout"
bottom: "fc7-conv"
top: "fc7-conv"
dropout_param {
dropout_ratio: 0.5
}
}layer {
name: "drop7"
type: "Dropout"
bottom: "fc7-conv"
top: "fc7-conv"
dropout_param {
dropout_ratio: 0.5
}
}
隻需要設定一個dropout_ratio就可以了
五.Blob,Layer and Net以及對應配置檔案的編寫
深度網絡(net)是一個組合模型,它由許多互相連接配接的層(layers)組合而成。Caffe就是組建深度網絡的這樣一種工具,它按照一定的政策,一層一層的搭建出自己的模型。它将所有的資訊資料定義為blobs,進而進行便利的操作和通訊。Blob是caffe架構中一種标準的數組,一種統一的記憶體接口,它較長的描述了資訊是如何存儲的,以及如何在層之間通訊的。
1、blob
Blobs封裝了運作時的資料資訊,提供了CPU和GPU的同步。從數學上來說, Blob就是一個N維數組。它是caffe中的資料操作基本機關,就像matlab中以矩陣為基本操作對象一樣。隻是矩陣是二維的,而Blob是N維的。N可以是2,3,4等等。對于圖檔資料來說,Blob可以表示為(N*C*H*W)這樣一個4D數組。其中N表示圖檔的數量,C表示圖檔的通道數,H和W分别表示圖檔的高度和寬度。當然,除了圖檔資料,Blob也可以用于非圖檔資料。比如傳統的多層感覺機,就是比較簡單的全連接配接網絡,用2D的Blob,調用innerProduct層來計算就可以了。
在模型中設定的參數,也是用Blob來表示和運算。它的次元會根據參數的類型不同而不同。比如:在一個卷積層中,輸入一張3通道圖檔,有96個卷積核,每個核大小為11*11,是以這個Blob是96*3*11*11. 而在一個全連接配接層中,假設輸入1024通道圖檔,輸出1000個資料,則Blob為1000*1024
2、layer
層是網絡模型的組成要素和計算的基本機關。層的類型比較多,如Data,Convolution,Pooling,ReLU,Softmax-loss,Accuracy等,一個層的定義大至如下圖:
從bottom進行資料的輸入 ,計算後,通過top進行輸出。圖中的黃色多邊形表示輸入輸出的資料,藍色矩形表示層。
每一種類型的層都定義了三種關鍵的計算:setup,forward and backword
setup: 層的建立和初始化,以及在整個模型中的連接配接初始化。
forward: 從bottom得到輸入資料,進行計算,并将計算結果送到top,進行輸出。
backward: 從層的輸出端top得到資料的梯度,計算目前層的梯度,并将計算結果送到bottom,向前傳遞。
3、Net
就像搭積木一樣,一個net由多個layer組合而成。
現給出 一個簡單的2層神經網絡的模型定義( 加上loss 層就變成三層了),先給出這個網絡的拓撲。
第一層:name為mnist, type為Data,沒有輸入(bottom),隻有兩個輸出(top),一個為data,一個為label
第二層:name為ip,type為InnerProduct, 輸入資料data, 輸出資料ip
第三層:name為loss, type為SoftmaxWithLoss,有兩個輸入,一個為ip,一個為label,有一個輸出loss,沒有畫出來。
對應的配置檔案prototxt就可以這樣寫:
name: "LogReg"
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
data_param {
source: "input_leveldb"
batch_size: 64
}
}
layer {
name: "ip"
type: "InnerProduct"
bottom: "data"
top: "ip"
inner_product_param {
num_output: 2
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip"
bottom: "label"
top: "loss"
}
第一行将這個模型取名為LogReg, 然後是三個layer的定義,參數都比較簡單,隻列出必須的參數。
六.Solver及其配置
solver算是caffe的核心的核心,它協調着整個模型的運作。caffe程式運作必帶的一個參數就是solver配置檔案。運作代碼一般為
# caffe train --solver=*_slover.prototxt
在Deep Learning中,往往loss function是非凸的,沒有解析解,我們需要通過優化方法來求解。solver的主要作用就是交替調用前向(forward)算法和後向(backward)算法來更新參數,進而最小化loss,實際上就是一種疊代的優化算法。
到目前的版本,caffe提供了六種優化算法來求解最優參數,在solver配置檔案中,通過設定type類型來選擇。
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")
具體的每種方法的介紹,請看本系列的下一篇文章, 本文着重介紹solver配置檔案的編寫。
Solver的流程:
1.設計好需要優化的對象,以及用于學習的訓練網絡和用于評估的測試網絡。(通過調用另外一個配置檔案prototxt來進行)
2.通過forward和backward疊代的進行優化來跟新參數。
3.定期的評價測試網絡。(可設定多少次訓練後,進行一次測試)
4.在優化過程中顯示模型和solver的狀态
在每一次的疊代過程中,solver做了這幾步工作:
1、調用forward算法來計算最終的輸出值,以及對應的loss
2、調用backward算法來計算每層的梯度
3、根據選用的slover方法,利用梯度進行參數更新
4、記錄并儲存每次疊代的學習率、快照,以及對應的狀态。
接下來,我們先來看一個執行個體:
net: "examples/mnist/lenet_train_test.prototxt"
test_iter: 100
test_interval: 500
base_lr: 0.01
momentum: 0.9
type: SGD
weight_decay: 0.0005
lr_policy: "inv"
gamma: 0.0001
power: 0.75
display: 100
max_iter: 20000
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
solver_mode: CPU
接下來,我們對每一行進行詳細解譯:
net: "examples/mnist/lenet_train_test.prototxt"
設定深度網絡模型。每一個模型就是一個net,需要在一個專門的配置檔案中對net進行配置,每個net由許多的layer所組成。每一個layer的具體配置方式可參考本系列文文章中的(2)-(5)。注意的是:檔案的路徑要從caffe的根目錄開始,其它的所有配置都是這樣。
也可用train_net和test_net來對訓練模型和測試模型分别設定。例如:
train_net: "examples/hdf5_classification/logreg_auto_train.prototxt"
test_net: "examples/hdf5_classification/logreg_auto_test.prototxt"
接下來第二行:
test_iter: 100
這個要與test layer中的batch_size結合起來了解。mnist資料中測試樣本總數為10000,一次性執行全部資料效率很低,是以我們将測試資料分成幾個批次來執行,每個批次的數量就是batch_size。假設我們設定batch_size為100,則需要疊代100次才能将10000個資料全部執行完。是以test_iter設定為100。執行完一次全部資料,稱之為一個epoch
test_interval: 500
測試間隔。也就是每訓練500次,才進行一次測試。
base_lr: 0.01
lr_policy: "inv"
gamma: 0.0001
power: 0.75
這四行可以放在一起了解,用于學習率的設定。隻要是梯度下降法來求解優化,都會有一個學習率,也叫步長。base_lr用于設定基礎學習率,在疊代的過程中,可以對基礎學習率進行調整。怎麼樣進行調整,就是調整的政策,由lr_policy來設定。
lr_policy可以設定為下面這些值,相應的學習率的計算為:
- fixed:保持base_lr不變.
- step: 如果設定為step,則還需要設定一個stepsize, 傳回
base_lr * gamma ^ (floor(iter / stepsize)),其中iter表示目前的疊代次數
- exp: 傳回base_lr * gamma ^ iter, iter為目前疊代次數
- inv:如果設定為inv,還需要設定一個power, 傳回base_lr * (1 + gamma * iter) ^ (- power)
- multistep: 如果設定為multistep,則還需要設定一個stepvalue。這個參數和step很相似,step是均勻等間隔變化,而multistep則是根據 stepvalue值變化
- poly:學習率進行多項式誤差, 傳回 base_lr (1 - iter/max_iter) ^ (power)
- sigmoid:學習率進行sigmod衰減,傳回 base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
multistep示例:
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# The learning rate policy
lr_policy: "multistep"
gamma: 0.9
stepvalue: 5000
stepvalue: 7000
stepvalue: 8000
stepvalue: 9000
stepvalue: 9500
接下來的參數:
momentum :0.9
上一次梯度更新的權重,具體可參看下一篇文章。
type: SGD
優化算法選擇。這一行可以省掉,因為預設值就是SGD。總共有六種方法可選擇,在本文的開頭已介紹。
weight_decay: 0.0005
權重衰減項,防止過拟合的一個參數
display: 100
每訓練100次,在螢幕上顯示一次。如果設定為0,則不顯示。
max_iter: 20000
最大疊代次數。這個數設定太小,會導緻沒有收斂,精确度很低。設定太大,會導緻震蕩,浪費時間。
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
快照。将訓練出來的model和solver狀态進行儲存,snapshot用于設定訓練多少次後進行儲存,預設為0,不儲存。snapshot_prefix設定儲存路徑。
還可以設定snapshot_diff,是否儲存梯度值,預設為false,不儲存。
也可以設定snapshot_format,儲存的類型。有兩種選擇:HDF5 和BINARYPROTO ,預設為BINARYPROTO
solver_mode: CPU
設定運作模式。預設為GPU,如果你沒有GPU,則需要改成CPU,否則會出錯。
注意:以上的所有參數都是可選參數,都有預設值。根據solver方法(type)的不同,還有一些其它的參數,在此不一一列舉。
七.Solver優化方法
上文提到,到目前為止,caffe總共提供了六種優化方法:
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")
Solver就是用來使loss最小化的優化方法。對于一個資料集D,需要優化的目标函數是整個資料集中所有資料loss的平均值。
其中,fW(x(i))計算的是資料x(i)上的loss, 先将每個單獨的樣本x的loss求出來,然後求和,最後求均值。 r(W)是正則項(weight_decay),為了減弱過拟合現象。
如果采用這種Loss 函數,疊代一次需要計算整個資料集,在資料集非常大的這情況下,這種方法的效率很低,這個也是我們熟知的梯度下降采用的方法。
在實際中,通過将整個資料集分成幾批(batches), 每一批就是一個mini-batch,其數量(batch_size)為N<<|D|,此時的loss 函數為:
有了loss函數後,就可以疊代的求解loss和梯度來優化這個問題。在神經網絡中,用forward pass來求解loss,用backward pass來求解梯度。
在caffe中,預設采用的Stochastic Gradient Descent(SGD)進行優化求解。後面幾種方法也是基于梯度的優化方法(like SGD),是以本文隻介紹一下SGD。其它的方法,有興趣的同學,可以去看文獻原文。
1、Stochastic gradient descent(SGD)
随機梯度下降(Stochastic gradient descent)是在梯度下降法(gradient descent)的基礎上發展起來的,梯度下降法也叫最速下降法,具體原理在網易公開課《機器學習》中,吳恩達教授已經講解得非常詳細。SGD在通過負梯度和上一次的權重更新值Vt的線性組合來更新W,疊代公式如下:
其中, 是負梯度的學習率(base_lr),是上一次梯度值的權重(momentum),用來權重之前梯度方向對現在梯度下降方向的影響。這兩個參數需要通過tuning來得到最好的結果,一般是根據經驗設定的。如果你不知道如何設定這些參數,可以參考相關的論文。
在深度學習中使用SGD,比較好的初始化參數的政策是把學習率設為0.01左右(base_lr: 0.01),在訓練的過程中,如果loss開始出現穩定水準時,對學習率乘以一個常數因子(gamma),這樣的過程重複多次。
對于momentum,一般取值在0.5--0.99之間。通常設為0.9,momentum可以讓使用SGD的深度學習方法更加穩定以及快速。
關于更多的momentum,請參看Hinton的《A Practical Guide to Training Restricted Boltzmann Machines》。
執行個體:
base_lr: 0.01
lr_policy: "step"
gamma: 0.1
stepsize: 1000
max_iter: 3500
momentum: 0.9
lr_policy設定為step,則學習率的變化規則為 base_lr * gamma ^ (floor(iter / stepsize))
即前1000次疊代,學習率為0.01; 第1001-2000次疊代,學習率為0.001; 第2001-3000次疊代,學習率為0.00001,第3001-3500次疊代,學習率為10-5
上面的設定隻能作為一種指導,它們不能保證在任何情況下都能得到最佳的結果,有時候這種方法甚至不work。如果學習的時候出現diverge(比如,你一開始就發現非常大或者NaN或者inf的loss值或者輸出),此時你需要降低base_lr的值(比如,0.001),然後重新訓練,這樣的過程重複幾次直到你找到可以work的base_lr。
2、AdaDelta
AdaDelta是一種”魯棒的學習率方法“,是基于梯度的優化方法(like SGD)。
具體的介紹文獻:
M. Zeiler ADADELTA: AN ADAPTIVE LEARNING RATE METHOD. arXiv preprint, 2012.
示例:
net: "examples/mnist/lenet_train_test.prototxt"
test_iter: 100
test_interval: 500
base_lr: 1.0
lr_policy: "fixed"
momentum: 0.95
weight_decay: 0.0005
display: 100
max_iter: 10000
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet_adadelta"
solver_mode: GPU
type: "AdaDelta"
delta: 1e-6
從最後兩行可看出,設定solver type為Adadelta時,需要設定delta的值。
3、AdaGrad
自适應梯度(adaptive gradient)是基于梯度的優化方法(like SGD)
具體的介紹文獻:
Duchi, E. Hazan, and Y. Singer. Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. The Journal of Machine Learning Research, 2011.
示例:
net: "examples/mnist/mnist_autoencoder.prototxt"
test_state: { stage: 'test-on-train' }
test_iter: 500
test_state: { stage: 'test-on-test' }
test_iter: 100
test_interval: 500
test_compute_loss: true
base_lr: 0.01
lr_policy: "fixed"
display: 100
max_iter: 65000
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "examples/mnist/mnist_autoencoder_adagrad_train"
# solver mode: CPU or GPU
solver_mode: GPU
type: "AdaGrad"
4、Adam
是一種基于梯度的優化方法(like SGD)。
具體的介紹文獻:
D. Kingma, J. Ba. Adam: A Method for Stochastic Optimization. International Conference for Learning Representations, 2015.
5、NAG
Nesterov 的加速梯度法(Nesterov’s accelerated gradient)作為凸優化中最理想的方法,其收斂速度非常快。
具體的介紹文獻:
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.
示例:
net: "examples/mnist/mnist_autoencoder.prototxt"
test_state: { stage: 'test-on-train' }
test_iter: 500
test_state: { stage: 'test-on-test' }
test_iter: 100
test_interval: 500
test_compute_loss: true
base_lr: 0.01
lr_policy: "step"
gamma: 0.1
stepsize: 10000
display: 100
max_iter: 65000
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "examples/mnist/mnist_autoencoder_nesterov_train"
momentum: 0.95
# solver mode: CPU or GPU
solver_mode: GPU
type: "Nesterov"
6、RMSprop
RMSprop是Tieleman在一次 Coursera課程演講中提出來的,也是一種基于梯度的優化方法(like SGD)
具體的介紹文獻:
T. Tieleman, and G. Hinton. RMSProp: Divide the gradient by a running average of its recent magnitude. COURSERA: Neural Networks for Machine Learning.Technical report, 2012.
示例:
net: "examples/mnist/lenet_train_test.prototxt"
test_iter: 100
test_interval: 500
base_lr: 1.0
lr_policy: "fixed"
momentum: 0.95
weight_decay: 0.0005
display: 100
max_iter: 10000
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet_adadelta"
solver_mode: GPU
type: "RMSProp"
rms_decay: 0.98
最後兩行,需要設定rms_decay值。
八.指令行解析
caffe的運作提供三種接口:c++接口(指令行)、Python接口和matlab接口。本文先對指令行進行解析,後續會依次介紹其它兩個接口。
caffe的c++主程式(caffe.cpp)放在根目錄下的tools檔案夾内, 當然還有一些其它的功能檔案,如:convert_imageset.cpp, train_net.cpp, test_net.cpp等也放在這個檔案夾内。經過編譯後,這些檔案都被編譯成了可執行檔案,放在了 ./build/tools/ 檔案夾内。是以我們要執行caffe程式,都需要加 ./build/tools/ 字首。
如:
# sudo sh ./build/tools/caffe train --solver=examples/mnist/train_lenet.sh
caffe程式的指令行執行格式如下:
caffe <command> <args>
其中的<command>有這樣四種:
train
test
device_query
time
對應的功能為:
train----訓練或finetune模型(model),
test-----測試模型
device_query---顯示gpu資訊
time-----顯示程式執行時間
其中的<args>參數有:
-solver
-gpu
-snapshot
-weights
-iteration
-model
-sighup_effect
-sigint_effect
注意前面有個-符号。對應的功能為:
-solver:必選參數。一個protocol buffer類型的檔案,即模型的配置檔案。如:
# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt
-gpu: 可選參數。該參數用來指定用哪一塊gpu運作,根據gpu的id進行選擇,如果設定為'-gpu all'則使用所有的gpu運作。如使用第二塊gpu運作:
# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 2
-snapshot:可選參數。該參數用來從快照(snapshot)中恢複訓練。可以在solver配置檔案設定快照,儲存solverstate。如:
# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -snapshot examples/mnist/lenet_iter_5000.solverstate
-weights:可選參數。用預先訓練好的權重來fine-tuning模型,需要一個caffemodel,不能和-snapshot同時使用。如:
# ./build/tools/caffe train -solver examples/finetuning_on_flickr_style/solver.prototxt -weights models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
-iterations: 可選參數,疊代次數,預設為50。 如果在配置檔案檔案中沒有設定疊代次數,則預設疊代50次。
-model:可選參數,定義在protocol buffer檔案中的模型。也可以在solver配置檔案中指定。
-sighup_effect:可選參數。用來設定當程式發生挂起事件時,執行的操作,可以設定為snapshot, stop或none, 預設為snapshot
-sigint_effect: 可選參數。用來設定當程式發生鍵盤中止事件時(ctrl+c), 執行的操作,可以設定為snapshot, stop或none, 預設為stop
剛才舉例了一些train參數的例子,現在我們來看看其它三個<command>:
test參數用在測試階段,用于最終結果的輸出,要模型配置檔案中我們可以設定需要輸入accuracy還是loss. 假設我們要在驗證集中驗證已經訓練好的模型,就可以這樣寫
# ./build/tools/caffe test -model examples/mnist/lenet_train_test.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel -gpu 0 -iterations 100
這個例子比較長,不僅用到了test參數,還用到了-model, -weights, -gpu和-iteration四個參數。意思是利用訓練好了的權重(-weight),輸入到測試模型中(-model),用編号為0的gpu(-gpu)測試100次(-iteration)。
time參數用來在螢幕上顯示程式運作時間。如:
# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -iterations 10
這個例子用來在螢幕上顯示lenet模型疊代10次所使用的時間。包括每次疊代的forward和backward所用的時間,也包括每層forward和backward所用的平均時間。
# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -gpu 0
這個例子用來在螢幕上顯示lenet模型用gpu疊代50次所使用的時間。
# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel -gpu 0 -iterations 10
利用給定的權重,利用第一塊gpu,疊代10次lenet模型所用的時間。
device_query參數用來診斷gpu資訊。
# ./build/tools/caffe device_query -gpu 0
最後,我們來看兩個關于gpu的例子
# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 0,1
# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu all
這兩個例子表示: 用兩塊或多塊GPU來平行運算,這樣速度會快很多。但是如果你隻有一塊或沒有gpu, 就不要加-gpu參數了,加了反而慢。
最後,在linux下,本身就有一個time指令,是以可以結合進來使用,是以我們運作mnist例子的最終指令是(一塊gpu):
$ sudo time ./build/toos/caffe train -solver examples/mnist/lenet_solver.prototxt
轉載于:https://www.cnblogs.com/invisible2/p/10371195.html