1. Caffe最優(yōu)求解過(guò)程
1.1 Solver介紹
Caffe的重中之重(核心)——Solver
負(fù)責(zé)對(duì)模型優(yōu)化揍异,讓損失函數(shù)(loss function)達(dá)到全局最小壤短。
solver的主要作用就是交替調(diào)用前向(forward)算法和后向(backward)算法來(lái)更新參數(shù)脚曾,實(shí)際上就是一種迭代的優(yōu)化算法。
在每一次的迭代過(guò)程中前痘,solver做了這幾步工作:
1窗悯、調(diào)用forward算法來(lái)計(jì)算最終的輸出值娜亿,以及對(duì)應(yīng)的loss
2、調(diào)用backward算法來(lái)計(jì)算每層的梯度
3廓块、根據(jù)選用的slover方法厢绝,利用梯度進(jìn)行參數(shù)更新
4、記錄并保存每次迭代的學(xué)習(xí)率带猴、快照昔汉,以及對(duì)應(yīng)的狀態(tài)。
1.2 Solver參數(shù)配置
message SolverParameter {
……
}
net: "examples/mnist/lenet_train_test.prototxt"
設(shè)置深度網(wǎng)絡(luò)模型拴清。每一個(gè)模型就是一個(gè)net靶病,需要在一個(gè)專門的配置文件中對(duì)net進(jìn)行配置,每個(gè)net由許多的layer所組成口予。注意的是:文件的路徑要從caffe的根目錄開(kāi)始娄周,其它的所有配置都是這樣。也可用train_net和test_net來(lái)對(duì)訓(xùn)練模型和測(cè)試模型分別設(shè)定:
train_net:"examples/mnist/lenet_train_test.prototxt"
test_net:"examples/mnist/lenet_test_test.prototxt"
test_iter: 100
mnist數(shù)據(jù)中測(cè)試樣本總數(shù)為10000沪停,一次性執(zhí)行全部數(shù)據(jù)效率很低煤辨,因此我們將測(cè)試數(shù)據(jù)分成幾個(gè)批次來(lái)執(zhí)行裳涛,每個(gè)批次的數(shù)量就是batch_size。假設(shè)我們?cè)O(shè)置batch_size為100众辨,則需要迭代100次才能將10000個(gè)數(shù)據(jù)全部執(zhí)行完端三。因此test_iter設(shè)置為100。執(zhí)行完一次全部數(shù)據(jù)鹃彻,稱之為一個(gè)epoch技肩。
test_interval: 500
在訓(xùn)練集中每迭代500次,在測(cè)試集進(jìn)行一次測(cè)試浮声。
base_lr: 0.01
lr_policy: "inv"
gamma: 0.0001
power: 0.75
這四個(gè)參數(shù)用于學(xué)習(xí)率的設(shè)置虚婿。只要是梯度下降法來(lái)求解優(yōu)化,都會(huì)有一個(gè)學(xué)習(xí)率泳挥,也叫步長(zhǎng)然痊。base_lr
用于設(shè)置基礎(chǔ)學(xué)習(xí)率,在迭代的過(guò)程中屉符,可以對(duì)基礎(chǔ)學(xué)習(xí)率進(jìn)行調(diào)整剧浸。怎么樣進(jìn)行調(diào)整,就是調(diào)整的策略矗钟,由lr_policy
來(lái)設(shè)置唆香。
lr_policy
可以設(shè)置為下面這些值,相應(yīng)的學(xué)習(xí)率的計(jì)算為:
- fixed:保持
base_lr
不變. - step:如果設(shè)置為step,則還需要設(shè)置一個(gè)stepsize, 返回
base_lr * gamma ^ (floor(iter / stepsize))
,其中iter表示當(dāng)前的迭代次數(shù) - exp:返回
base_lr * gamma ^ iter
吨艇, iter為當(dāng)前迭代次數(shù) - inv:如果設(shè)置為inv,還需要設(shè)置一個(gè)power, 返回
base_lr * (1 + gamma * iter) ^ (- power)
- multistep:如果設(shè)置為multistep,則還需要設(shè)置一個(gè)stepvalue躬它。這個(gè)參數(shù)和step很相似,step是均勻等間隔變化东涡,而multistep則是根據(jù)stepvalue值變化
- poly:學(xué)習(xí)率進(jìn)行多項(xiàng)式誤差, 返回
base_lr (1 - iter/max_iter) ^ (power)
- sigmoid:學(xué)習(xí)率進(jìn)行sigmod衰減冯吓,返回
base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
weight_decay: 0.0005
momentum :0.9
type: SGD
- Stochastic Gradient Descent (type: "SGD")
- AdaDelta (type: "AdaDelta")
- Adaptive Gradient (type: "AdaGrad")
- Adam (type: "Adam")
- Nesterov’s Accelerated Gradient (type: "Nesterov")
- RMSprop (type: "RMSProp")
1.3 Solver優(yōu)化方式
在深度學(xué)習(xí)中使用SGD,比較好的初始化參數(shù)的策略是把學(xué)習(xí)率設(shè)為0.01左右(base_lr: 0.01)疮跑,在訓(xùn)練的過(guò)程中组贺,如果loss開(kāi)始出現(xiàn)穩(wěn)定水平時(shí),對(duì)學(xué)習(xí)率乘以一個(gè)常數(shù)因子(gamma)祖娘,這樣的過(guò)程重復(fù)多次失尖。
對(duì)于momentum,一般取值在0.5--0.99之間渐苏。通常設(shè)為0.9淋纲,momentum可以讓使用SGD的深度學(xué)習(xí)方法更加穩(wěn)定以及快速私恬。
對(duì)于RMSProp障贸,AdaGrad, AdaDelta and Adam , 還可以設(shè)置delta參數(shù)谒麦。
對(duì)于Adam solver, 設(shè)置momentum2
對(duì)于RMSProp, 設(shè)置rms_decay
2. Caffe的I/O模塊
2.1 對(duì)Layer做參數(shù)配置(Datalayer為例)
layer {
name: "cifar"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "cifar10_train_lmdb"
batch_size: 100
backend: LMDB
}
}
name: 表示該層的名稱公黑,可隨意取邑商。
type: 層類型摄咆,如果是Data,表示數(shù)據(jù)來(lái)源于LevelDB或LMDB人断。根據(jù)數(shù)據(jù)的來(lái)源不同吭从,數(shù)據(jù)層的類型也不同。
top或bottom: 每一層用bottom來(lái)輸入數(shù)據(jù)恶迈,用top來(lái)輸出數(shù)據(jù)涩金。如果只有top沒(méi)有bottom,則此層只有輸出暇仲,沒(méi)有輸入步做。反之亦然。如果有多個(gè) top或多個(gè)bottom奈附,表示有多個(gè)blobs數(shù)據(jù)的輸入和輸出全度。
data 與 label: 在數(shù)據(jù)層中,至少有一個(gè)命名為data的top斥滤。如果有第二個(gè)top将鸵,一般命名為label。 這種(data,label)配對(duì)是分類模型所必需的佑颇。
include: 一般訓(xùn)練的時(shí)候和測(cè)試的時(shí)候顶掉,模型的層是不一樣的。該層(layer)是屬于訓(xùn)練階段的層挑胸,還是屬于測(cè)試階段的層痒筒,需要用include來(lái)指定。如果沒(méi)有include參數(shù)嗜暴,則表示該層既在訓(xùn)練模型中凸克,又在測(cè)試模型中。
Transformations: 數(shù)據(jù)的預(yù)處理闷沥,可以將數(shù)據(jù)變換到定義的范圍內(nèi)。如設(shè)置scale為0.00390625咐容,實(shí)際上就是1/255, 即將輸入數(shù)據(jù)由0-255歸一化到0-1之間舆逃。
所有數(shù)據(jù)預(yù)處理都在這里設(shè)置:
transform_param {
scale: 0.00390625
mean_file_size: “examples/cifar10/mean.binaryproto" # 用一個(gè)配置文件來(lái)進(jìn)行均值操作
mirror: 1 # 1表示開(kāi)啟鏡像,0表示關(guān)閉戳粒,也可用ture和false來(lái)表示
crop_size: 227 # 剪裁一個(gè) 227*227的圖塊路狮,在訓(xùn)練階段隨機(jī)剪裁,在測(cè)試階段從中間裁剪
}
- 通常數(shù)據(jù)的預(yù)處理(如減去均值, 放大縮小, 裁剪和鏡像等)蔚约,Caffe使用OpenCV做處理奄妨。
- 數(shù)據(jù)來(lái)自于數(shù)據(jù)庫(kù)(如LevelDB和LMDB)
層類型(layer type):Data
必須設(shè)置的參數(shù):
source
包含數(shù)據(jù)庫(kù)的目錄名稱,如examples/mnist/mnist_train_lmdb
batch_size
每次處理的數(shù)據(jù)個(gè)數(shù)苹祟,如64
可選的參數(shù):
rand_skip
在開(kāi)始的時(shí)候砸抛,路過(guò)某個(gè)數(shù)據(jù)的輸入评雌。通常對(duì)異步的SGD很有用。
backend
選擇是采用LevelDB還是LMDB, 默認(rèn)是LevelDB. - 數(shù)據(jù)來(lái)自于內(nèi)存
層類型:MemoryData
必須設(shè)置的參數(shù):
batch_size
每一次處理的數(shù)據(jù)個(gè)數(shù)直焙,比如2
channels
通道數(shù)
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
}
}
- 數(shù)據(jù)來(lái)自于圖片
層類型:ImageData
必須設(shè)置的參數(shù):
source
一個(gè)文本文件的名字景东,每一行給定一個(gè)圖片文件的名稱和標(biāo)簽(label)
batch_size
每一次處理的數(shù)據(jù)個(gè)數(shù),即圖片數(shù)
可選參數(shù):
rand_skip
在開(kāi)始的時(shí)候奔誓,路過(guò)某個(gè)數(shù)據(jù)的輸入斤吐。通常對(duì)異步的SGD很有用。
shuffle
隨機(jī)打亂順序厨喂,默認(rèn)值為false
new_height,new_width
如果設(shè)置和措,則將圖片進(jìn)行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
}
}
- 數(shù)據(jù)來(lái)自于HDF5
層類型:HDF5Data
必須設(shè)置的參數(shù):
source
讀取的文件名稱
batch_size
每一次處理的數(shù)據(jù)個(gè)數(shù)
layer {
name: "data"
type: "HDF5Data"
top: "data"
top: "label"
hdf5_data_param {
source: "examples/hdf5_classification/data/train.txt"
batch_size: 10
}
}
- 數(shù)據(jù)來(lái)源于Windows
層類型:WindowData
必須設(shè)置的參數(shù):
source
一個(gè)文本文件的名字
batch_size
每一次處理的數(shù)據(jù)個(gè)數(shù),即圖片數(shù)
layer{…
window_data_param…
}
2.2 將圖片數(shù)據(jù)轉(zhuǎn)化為L(zhǎng)MDB數(shù)據(jù)集
第一步:創(chuàng)建圖片文件列表清單蜕煌,一般為一個(gè)txt文件臼婆,一行一張圖片
第二步:使用Caffe工具命令
convert_imageset [FLAGS] [ROOTFOLDER/] [LISTFILE] [DB_NAME]
需要帶四個(gè)參數(shù):
FLAGS
圖片參數(shù)組
- gray: 是否以灰度圖的方式打開(kāi)圖片。程序調(diào)用opencv庫(kù)中的imread()函數(shù)來(lái)打開(kāi)圖片幌绍,默認(rèn)為false
- shuffle: 是否隨機(jī)打亂圖片順序颁褂。默認(rèn)為false
- backend:需要轉(zhuǎn)換成的db文件格式,可選為leveldb或lmdb,默認(rèn)為lmdb
- resize_width/resize_height: 改變圖片的大小傀广。在運(yùn)行中颁独,要求所有圖片的尺寸一致,因此需要改變圖片大小伪冰。 程序調(diào)用opencv庫(kù)的resize()函數(shù)來(lái)對(duì)圖片放大縮小誓酒,默認(rèn)為0,不改變
- check_size: 檢查所有的數(shù)據(jù)是否有相同的尺寸贮聂。默認(rèn)為false,不檢查
- encoded: 是否將原圖片編碼放入最終的數(shù)據(jù)中靠柑,默認(rèn)為false
- encode_type: 與前一個(gè)參數(shù)對(duì)應(yīng),將圖片編碼為哪一個(gè)格式:‘png','jpg'......
ROOTFOLDER/
圖片存放的絕對(duì)路徑吓懈,從linux系統(tǒng)根目錄開(kāi)始
LISTFILE
圖片文件列表清單歼冰,一般為一個(gè)txt文件,一行一張圖片
DB_NAME
最終生成的db文件存放目錄
有/test/female/,/test/male,/train/female/,/test/male/
文件夾放有圖片
label_name.txt
0 female
1 male
ls train/female/
ls train/female | sed "s:^:female/:" | sed "s:$: 0:" >> t_train.txt
ls train/male | sed "s:^:male/:" | sed "s:$: 1:" >> t_train.txt
ls test/female | sed "s:^:female/:" | sed "s:$: 0:" >> t_test.txt
ls test/male | sed "s:^:male/:" | sed "s:$: 1:" >> t_test.txt
convert_imageset --resize_width=40 --resize_height=40 /home/yourname/samples/caffe/data/train/ ./t_train.txt ./t_train_lmdb
convert_imageset --resize_width=40 --resize_height=40 /home/yourname/samples/caffe/data/test/ ./t_test.txt ./t_test_lmdb
3. 使用訓(xùn)練好的模型
3.1 均值文件
將所有訓(xùn)練樣本的均值保存為文件
圖片減去均值后耻警,再進(jìn)行訓(xùn)練和測(cè)試隔嫡,會(huì)提高速度和精度
運(yùn)行方法:(使用Caffe工具)
compute_image_mean [train_lmdb] [mean.binaryproto]
3.2 deploy文件改寫
- 把數(shù)據(jù)層(Data Layer)和連接數(shù)據(jù)層的Layers去掉(即top:data的層)
- 去掉輸出層和連接輸出層的Layers(即bottom:label)
- 重新建立輸入
input: "data"
input_shape {
dim: 1 # batchsize,每次forward的時(shí)候輸入的圖片個(gè)數(shù)
dim: 3 # number of colour channels - rgb
dim: 28 # width
dim: 28 # height
}
- 重新建立輸出
layer {
name: "prob"
type: "Softmax"
bottom: "ip2"
top: "prob"
}
- 修改后的mnist的deploy文件可以參考caffe/example/mnist/lenet_train.prototxt
使用修改后的mnist的deploy文件,輸入一張圖片甘穿,輸出分類結(jié)果腮恩。
lenet_iter_10000.caffemodel
mnist_deploy.prototxt
test_mnist.cpp
代碼
g++ -o test_mnist test_mnist.cpp -lopencv_dnn -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lstdc++ -lopencv_core
./test_mnist
3.4 fine turning微調(diào)網(wǎng)絡(luò)
- 準(zhǔn)備新數(shù)據(jù)的數(shù)據(jù)庫(kù)(如果需要用mean file,還要準(zhǔn)備對(duì)應(yīng)的新的mean file), 具體方法和圖片轉(zhuǎn)換lmdb方式一樣。
- 調(diào)整網(wǎng)絡(luò)層參數(shù):
將來(lái)訓(xùn)練的網(wǎng)絡(luò)配置prototxt中的數(shù)據(jù)層source換成新數(shù)據(jù)的數(shù)據(jù)庫(kù)温兼。
調(diào)整學(xué)習(xí)率秸滴,因?yàn)樽詈笠粚邮侵匦聦W(xué)習(xí),因此需要有更快的學(xué)習(xí)速率相比較其他層募判,因此我們將荡含,weight和bias的學(xué)習(xí)速率加快咒唆。 - 修改solver參數(shù)
原來(lái)的數(shù)據(jù)是從原始數(shù)據(jù)開(kāi)始訓(xùn)練的,因此一般來(lái)說(shuō)學(xué)習(xí)速率内颗、步長(zhǎng)钧排、迭代次數(shù)都比較大,fine turning微調(diào)時(shí)均澳,因?yàn)閿?shù)據(jù)量可能減少了恨溜,所以一般來(lái)說(shuō),test_iter,base_lr,stepsize都要變小一點(diǎn)找前,其他的策略可以保持不變糟袁。 - 重新訓(xùn)練時(shí),要指定之前的權(quán)值文件:
# caffe train --solver [新的solver文件] --weights [舊的caffemodel]