caffe 框架梳理(待续)
本文更多資料來(lái)源于羅韻北京深度學(xué)習(xí)資料和Ian Goodfellow的書(shū)籍《Deep Learning》
鏈接: http://pan.baidu.com/s/1jIRJ6mU
提取密碼:xehi
caffe:全稱(chēng)Convolutional Architecture for Fast Feature Embedding,是一個(gè)計(jì)算CNN 相關(guān)算法的框架,用C++和Python實(shí)現(xiàn)的。
Caffe的優(yōu)點(diǎn)與局限性
優(yōu)點(diǎn):
? 1. 第一個(gè)主流的工業(yè)級(jí)深度學(xué)習(xí)工具。
? 2. 專(zhuān)精于圖像處理
? 局限性:
? 1. 它有很多擴(kuò)展,但是由于一些遺留的架構(gòu)問(wèn)題,不夠靈活且對(duì)遞歸網(wǎng)絡(luò)和語(yǔ)言建模的支持很差。
? 2. 基于層的網(wǎng)絡(luò)結(jié)構(gòu),其擴(kuò)展性不好,對(duì)于新增加的層,需要
自己實(shí)現(xiàn)(forward, backward and gradient update)
Caffe目錄結(jié)構(gòu)
? data/ 用于存放下載的訓(xùn)練數(shù)據(jù)
? docs/ 幫助文檔
? examples/ 代碼樣例
? matlab/ MATLAB接文件
? python/ PYTHON接文件
? models/ 一些配置好的模型參數(shù)
? scripts/ 一些文檔和數(shù)據(jù)會(huì)用到的腳本核心代碼
? tools/ 保存的源碼是用于生成二進(jìn)制處理程序的,caffe在訓(xùn)練時(shí)實(shí)際是直接調(diào)用這些二進(jìn)制文件
? include/ Caffe的實(shí)現(xiàn)代碼的頭文件
? src/ 實(shí)現(xiàn)Caffe的源文件
src/ 文件結(jié)構(gòu)
gtest/ google test 一個(gè)用于測(cè)試的庫(kù),你make runtest時(shí)看見(jiàn)的很多綠?色RUN OK就是它,這個(gè)與caffe的學(xué)習(xí)無(wú)關(guān),不過(guò)是個(gè)有用的庫(kù)
caffe/ 關(guān)鍵代碼
? test/ 用gtest測(cè)試caffe的代碼
? util/ 數(shù)據(jù)轉(zhuǎn)換時(shí)用的一些代碼。caffe速度快,很大程度得益于內(nèi)存設(shè)計(jì)上的優(yōu)化(blob數(shù)據(jù)結(jié)構(gòu)采用proto)和對(duì)卷積的優(yōu)化(部分與im2col相
關(guān))
? proto/ 即所謂的“Protobuf”,全稱(chēng)“Google Protocol Buffer”,是一種數(shù)據(jù)存儲(chǔ)格式,幫助caffe提速
? layers/ 深度神經(jīng)網(wǎng)絡(luò)中的基本結(jié)構(gòu)就是一層層互不相同的網(wǎng)絡(luò)了,這個(gè)
文件夾下的源文件以及目前位置“src/caffe”中包含所有.cpp文件就是caffe的核心目錄下的核心代碼了。
Caffe核心代碼
? blob[.cpp .h] 基本的數(shù)據(jù)結(jié)構(gòu)Blob類(lèi)
? common[.cpp .h] 定義Caffe類(lèi)
? internal_thread[.cpp .h] 使用boost::thread線(xiàn)程庫(kù)
? net[.cpp .h] 網(wǎng)絡(luò)結(jié)構(gòu)類(lèi)Net
? solver[.cpp .h] 優(yōu)化方法類(lèi)Solver
? data_transformer[.cpp .h] 輸入數(shù)據(jù)的基本操作類(lèi)DataTransformer
? syncedmem[.cpp .h] 分配內(nèi)存和釋放內(nèi)存類(lèi)CaffeMallocHost,用于同步GPU,CPU數(shù)據(jù)
? layer[.cpp .h] 層類(lèi)Layer
? layers/ 此文件夾下面的代碼全部至少繼承了類(lèi)Layer, 從layer_factory中注冊(cè)繼承
1. Caffe三級(jí)結(jié)構(gòu)(Blobs,Layers,Nets)
? Blob:用于數(shù)據(jù)的保存、交換和操作,Caffe基礎(chǔ)存儲(chǔ)結(jié)構(gòu)
? Layer:用于模型和計(jì)算的基礎(chǔ)
? Net:整合連接Layers
1.1 Blobs結(jié)構(gòu)
? 在內(nèi)存中表示4維數(shù)組,在caffe/blob.hpp中,維度包括
(width_,height_,channels_,num_)
? num_用于存儲(chǔ)數(shù)據(jù)或權(quán)值(data)和權(quán)值增量(diff)
? Blob 在caffe源碼 blob.hpp中是一個(gè)模板類(lèi)。
? protected 的成員變量有:data_ , diff_ , shape_ , count_ , capacity_ ,其中data_ 和diff_ 是共享SyncedMemory 類(lèi)(在syncedmem的源碼中定義)的智能指針,shape_是int型的vector,count_ 和capacity_ 是整型變量。
? 其成員函數(shù)主要有:Reshape 、ReshapeLike、SharedData、 Updata 等等
? blob.hpp 包含了caffe.pb.h ,說(shuō)明caffe protobuf 會(huì)向blob 傳遞參數(shù)。
“caffe/proto/caffe.pb.h”
? caffe.pb.h是google protocol buffer根據(jù)caffe.proto自動(dòng)生成的,可以到src/caffe/proto/caffe.proto里看下caffe里面用到的各個(gè)數(shù)據(jù)的定義,比如BlobProto,Datum,NetParameter等。使用這個(gè)protocol buffer看起來(lái)確實(shí)方便,一方面可以用文本文件定義結(jié)構(gòu)化的數(shù)據(jù)類(lèi)型,另一方面可以生成查詢(xún)效率更高、占空間更小的二進(jìn)制文件。
“caffe/common.hpp”
? 主要singleton化Caffe類(lèi),并封裝了boost和CUDA隨機(jī)數(shù)生成的函數(shù),提供了統(tǒng)一的接口。
“caffe/syncedmem.hpp”
? 定義了以下的接?口:
? inline void CaffeMallocHost(void** ptr, size_t size)
? inline void CaffeFreeHost(void* ptr)
? 主要是分配內(nèi)存和釋放內(nèi)存的。而class SyncedMemory定義了內(nèi)存分配管理和CPU與GPU之間同步的函數(shù)。
“caffe/util/math_functions.hpp”
? 封裝了很多cblas矩陣運(yùn)算
caffe.proto里面BlobProto的定義
message BlobProto {optional BlobShape shape = 7;repeated float data = 5 [packed = true];repeated float diff = 6 [packed = true];repeated double double_data = 8 [packed = true];repeated double double_diff = 9 [packed = true];// 4D dimensions -- deprecated. Use "shape" instead.optional int32 num = 1 [default = 0];optional int32 channels = 2 [default = 0];optional int32 height = 3 [default = 0];optional int32 width = 4 [default = 0]; }? 對(duì)于BlobProto,可以看到定義了四個(gè)optional的int32類(lèi)型的名字(name)num、channels、height和width,optional意味著B(niǎo)lob可以有一個(gè)或者沒(méi)有這個(gè)參數(shù),每個(gè)名字(name)后面都有一個(gè)數(shù)字,這個(gè)數(shù)字是其名字的一個(gè)標(biāo)簽。這個(gè)數(shù)字就是用來(lái)在生成的二進(jìn)制文件中搜索查詢(xún)的標(biāo)簽。關(guān)于這個(gè)數(shù)字,1到15會(huì)花費(fèi)1byte的編碼空間,16到2047花費(fèi)2byte。所以?一般建議把那些頻繁使用的名字的標(biāo)簽設(shè)為1到15之間的值。而后面的repeated意味著float類(lèi)型的data和diff可以重復(fù)任意次,而加上[packed = true]是為了更高效的編碼。 ? 主要數(shù)據(jù)有兩個(gè)data和diff,用num、channels、height和width這四個(gè)維度來(lái)確定數(shù)據(jù)的具體位置,做一些數(shù)據(jù)查詢(xún)和Blob reshape的操作。Blobs封裝了運(yùn)行時(shí)的數(shù)據(jù)信息,提供了CPU和GPU的同步。從數(shù)學(xué)上來(lái)說(shuō), Blob就是一個(gè)N維數(shù)組。它是caffe中的數(shù)據(jù)操作基本單位,就像matlab中以矩陣為基本操作對(duì)象一樣。只是矩陣是二維的,而B(niǎo)lob是N維的。N可以是2,3,4等等。
對(duì)于圖片數(shù)據(jù)來(lái)說(shuō),Blob可以表示為(N*C*H*W)這樣一個(gè)4D數(shù)組。其中N表示圖片的數(shù)量,C表示圖片的通道數(shù),H和W分別表示圖片的高度和寬度。
當(dāng)然,除了圖片數(shù)據(jù),Blob也可以用于非圖片數(shù)據(jù)。比如傳統(tǒng)的多層感知機(jī),就是比較簡(jiǎn)單的全連接網(wǎng)絡(luò),用2D的Blob,調(diào)用innerProduct層來(lái)計(jì)算就可以了。
在模型中設(shè)定的參數(shù),也是用Blob來(lái)表示和運(yùn)算。它的維度會(huì)根據(jù)參數(shù)的類(lèi)型不同而不同。比如:在一個(gè)卷積層中,輸入一張3通道圖片,有96個(gè)卷積核,每個(gè)核大小為11*11,因此這個(gè)Blob是96*3*11*11. 而在一個(gè)全連接層中,假設(shè)輸入1024通道圖片,輸出1000個(gè)數(shù)據(jù),則Blob為1000*1024。
1.2 Layer的五種類(lèi)型
? Layer
? 所有的Pooling,Convolve,apply nonlinearities等操作都在這里實(shí)現(xiàn)。在Layer中input data用bottom表示,output data用top表示。每一層定義了三種操作setup(Layer初始化), forward(正向傳導(dǎo),根據(jù)input計(jì)算output), backward(反向傳導(dǎo)計(jì)算,根據(jù)output計(jì)算input的梯度)。forward和backward有GPU和CPU兩個(gè)版本的實(shí)現(xiàn)。
層是網(wǎng)絡(luò)模型的組成要素和計(jì)算的基本單位。層的類(lèi)型比較多,如Data,Convolution,Pooling,ReLU,Softmax-loss,Accuracy等,一個(gè)層的定義大至如下圖:
從bottom進(jìn)行數(shù)據(jù)的輸入 ,計(jì)算后,通過(guò)top進(jìn)行輸出。圖中的黃色多邊形表示輸入輸出的數(shù)據(jù),藍(lán)色矩形表示層。
每一種類(lèi)型的層都定義了三種關(guān)鍵的計(jì)算:setup,forward and backword
setup: 層的建立和初始化,以及在整個(gè)模型中的連接初始化。
forward: 從bottom得到輸入數(shù)據(jù),進(jìn)行計(jì)算,并將計(jì)算結(jié)果送到top,進(jìn)行輸出。
backward: 從層的輸出端top得到數(shù)據(jù)的梯度,計(jì)算當(dāng)前層的梯度,并將計(jì)算結(jié)果送到bottom,向前傳遞。
正向傳播的是數(shù)據(jù),反向傳播的是誤差損失和梯度。
? 5種衍生Layers:
? data_layer
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: 100backend: LMDB} } name: 表示該層的名稱(chēng),可隨意取type: 層類(lèi)型,如果是Data,表示數(shù)據(jù)來(lái)源于LevelDB或LMDB。根據(jù)數(shù)據(jù)的來(lái)源不同,數(shù)據(jù)層的類(lèi)型也不同。一般都是采 用的LevelDB或LMDB數(shù)據(jù),因此層類(lèi)型設(shè)置為Data。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ì)是分類(lèi)模型所必需的。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之間mirror # 1表示開(kāi)啟鏡像,0表示關(guān)閉,也可用ture和false來(lái)表示 crop_size: 227剪裁一個(gè) 227*227的圖塊,在訓(xùn)練階段隨機(jī)剪裁,在測(cè)試階段從中間裁剪
data_layer主要包含與數(shù)據(jù)有關(guān)的文件。在官方文檔中指出data是caffe數(shù)據(jù)的入口是網(wǎng)絡(luò)的最低層,并且支持多種格式,在這之中又有5種LayerType
? DATA 用于LevelDB或LMDB數(shù)據(jù)格式的輸入的類(lèi)型,輸入?yún)?shù)有source,batch_size, (rand_skip), (backend)。后兩個(gè)是可選。
數(shù)據(jù)來(lái)自于數(shù)據(jù)庫(kù)(如LevelDB和LMDB)
層類(lèi)型(layer type):Data
必須設(shè)置的參數(shù):
source: 包含數(shù)據(jù)庫(kù)的目錄名稱(chēng),如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.
? MEMORY_DATA 這種類(lèi)型可以直接從內(nèi)存讀取數(shù)據(jù)使用時(shí)需要調(diào)用MemoryDataLayer::Reset,輸入?yún)?shù)有batch_size, channels, height, width。
數(shù)據(jù)來(lái)自于內(nèi)存層類(lèi)型:MemoryData必須設(shè)置的參數(shù):
batch_size:每一次處理的數(shù)據(jù)個(gè)數(shù),比如2,channels:通道數(shù)
height:高度,width: 寬度
示例:
? HDF5_DATA HDF5數(shù)據(jù)格式輸入的類(lèi)型,輸入?yún)?shù)有source, batch_size。
? HDF5_OUTPUT HDF5數(shù)據(jù)格式輸出的類(lèi)型,輸入?yún)?shù)有file_name。
數(shù)據(jù)來(lái)自于HDF5
層類(lèi)型:HDF5Data
必須設(shè)置的參數(shù):
source: 讀取的文件名稱(chēng)
batch_size: 每一次處理的數(shù)據(jù)個(gè)數(shù)
示例:
? IMAGE_DATA 圖像格式數(shù)據(jù)輸入的類(lèi)型,輸入?yún)?shù)有source, batch_size,(rand_skip), (shuffle), (new_height), (new_width)。
數(shù)據(jù)來(lái)自于圖片
層類(lèi)型:ImageData
必須設(shè)置的參數(shù):
source: 一個(gè)文本文件的名字,每一行給定一個(gè)圖片文件的名稱(chēng)和標(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
示例:
? 其實(shí)還有兩種WINDOW_DATA, DUMMY_DATA?用于測(cè)試和預(yù)留的接?口,不重要。
數(shù)據(jù)來(lái)源于Windows
層類(lèi)型:WindowData
必須設(shè)置的參數(shù):
source: 一個(gè)文本文件的名字
batch_size: 每一次處理的數(shù)據(jù)個(gè)數(shù),即圖片數(shù)
示例:
? neuron_layer
同樣是數(shù)據(jù)的操作層,neuron_layer實(shí)現(xiàn)里大量激活函數(shù),主要是元素級(jí)別的操作,具有相同的bottom,top size。
? Caffe中實(shí)現(xiàn)了大量激活函數(shù)GPU和CPU的都有很多。它們的父類(lèi)都是
NeuronLayer
1、Sigmoid
對(duì)每個(gè)輸入數(shù)據(jù),利用sigmoid函數(shù)執(zhí)行操作。這種層設(shè)置比較簡(jiǎn)單,沒(méi)有額外的參數(shù)。
層類(lèi)型:Sigmoid
示例
layer {name: "encode1neuron"bottom: "encode1"top: "encode1neuron"type: "Sigmoid" }2、ReLU / Rectified-Linear and Leaky-ReLU
ReLU是目前使用最多的激活函數(shù),主要因?yàn)槠涫諗扛?#xff0c;并且能保持同樣效果。
標(biāo)準(zhǔn)的ReLU函數(shù)為max(x, 0),當(dāng)x>0時(shí),輸出x; 當(dāng)x<=0時(shí),輸出0
f(x)=max(x,0)層類(lèi)型:ReLU
可選參數(shù):
negative_slope:默認(rèn)為0. 對(duì)標(biāo)準(zhǔn)的ReLU函數(shù)進(jìn)行變化,如果設(shè)置了這個(gè)值,那么數(shù)據(jù)為負(fù)數(shù)時(shí),就不再設(shè)置為0,而是用原始數(shù)據(jù)乘以negative_slope
一般的參數(shù)設(shè)置格式如下(以ReLU為例)
layers { name: "relu1" type: RELU bottom: "conv1" top: "conv1" }RELU層支持in-place計(jì)算,這意味著bottom的輸出和輸入相同以避免內(nèi)存的消耗。
3、TanH / Hyperbolic Tangent
利用雙曲正切函數(shù)對(duì)數(shù)據(jù)進(jìn)行變換。
層類(lèi)型:TanH
layer {name: "layer"bottom: "in"top: "out"type: "TanH" }4、Absolute Value
求每個(gè)輸入數(shù)據(jù)的絕對(duì)值。
f(x)=Abs(x)層類(lèi)型:AbsVal
layer {name: "layer"bottom: "in"top: "out"type: "AbsVal" }5、Power
對(duì)每個(gè)輸入數(shù)據(jù)進(jìn)行冪運(yùn)算
f(x)= (shift + scale * x) ^ power層類(lèi)型:Power
可選參數(shù):
power: 默認(rèn)為1
scale: 默認(rèn)為1
shift: 默認(rèn)為0
6、BNLL
binomial normal log likelihood的簡(jiǎn)稱(chēng)
f(x)=log(1 + exp(x))層類(lèi)型:BNLL
layer {name: "layer"bottom: "in"top: "out"type: “BNLL” }? loss_layer
Loss層計(jì)算網(wǎng)絡(luò)誤差,loss_layer.hpp頭文件調(diào)用情況
? #include “caffe/blob.hpp" ? #include “caffe/common.hpp" ? #include “caffe/layer.hpp" ? #include “caffe/neuron_layers.hpp" ? #include “caffe/proto/caffe.pb.h"可以看見(jiàn)調(diào)用了neuron_layers.hpp,估計(jì)是需要調(diào)用里面的函數(shù)計(jì)算Loss,一般來(lái)說(shuō)Loss放在最后一層。caffe實(shí)現(xiàn)了大量loss function,它們的父類(lèi)都是LossLayer。
? template <typename Dtype> ? class LossLayer : public Layer<Dtype>softmax-loss
softmax-loss層和softmax層計(jì)算大致是相同的。softmax是一個(gè)分類(lèi)器,計(jì)算的是類(lèi)別的概率(Likelihood),是Logistic Regression 的一種推廣。Logistic Regression 只能用于二分類(lèi),而softmax可以用于多分類(lèi)。
softmax與softmax-loss的區(qū)別:
softmax計(jì)算公式:
而softmax-loss計(jì)算公式
關(guān)于兩者的區(qū)別更加具體的介紹,可參考:softmax vs. softmax-loss
用戶(hù)可能最終目的就是得到各個(gè)類(lèi)別的概率似然值,這個(gè)時(shí)候就只需要一個(gè) Softmax層,而不一定要進(jìn)行softmax-Loss 操作;或者是用戶(hù)有通過(guò)其他什么方式已經(jīng)得到了某種概率似然值,然后要做最大似然估計(jì),此時(shí)則只需要后面的 softmax-Loss 而不需要前面的 Softmax 操作。因此提供兩個(gè)不同的 Layer 結(jié)構(gòu)比只提供一個(gè)合在一起的 Softmax-Loss Layer 要靈活許多。
不管是softmax layer還是softmax-loss layer,都是沒(méi)有參數(shù)的,只是層類(lèi)型不同而也
layer {name: "loss"type: "SoftmaxWithLoss"bottom: "ip1"bottom: "label"top: "loss" }softmax layer: 輸出似然值
layers {bottom: "cls3_fc"top: "prob"name: "prob"type: “Softmax" }? common_layer
這一層主要進(jìn)行的是vision_layer的連接
聲明了9個(gè)類(lèi)型的common_layer,部分有GPU實(shí)現(xiàn)
Inner Product
全連接層,把輸入當(dāng)作成一個(gè)向量,輸出也是一個(gè)簡(jiǎn)單向量(把輸入數(shù)據(jù)blobs的width和height全變?yōu)?)。
輸入: n*c0*h*w
輸出: n*c1*1*1
全連接層實(shí)際上也是一種卷積層,只是它的卷積核大小和原數(shù)據(jù)大小一致。因此它的參數(shù)基本和卷積層的參數(shù)一樣。
層類(lèi)型:InnerProduct
lr_mult: 學(xué)習(xí)率的系數(shù),最終的學(xué)習(xí)率是這個(gè)數(shù)乘以solver.prototxt配置文件中的base_lr。如果有兩個(gè)lr_mult, 則第一個(gè)表示權(quán)值的學(xué)習(xí)率,第二個(gè)表示偏置項(xiàng)的學(xué)習(xí)率。一般偏置項(xiàng)的學(xué)習(xí)率是權(quán)值學(xué)習(xí)率的兩倍。
必須設(shè)置的參數(shù):
num_output: 過(guò)濾器(filfter)的個(gè)數(shù)
其它參數(shù):
weight_filler: 權(quán)值初始化。 默認(rèn)為“constant",值全為0,很多時(shí)候我們用"xavier"算法來(lái)進(jìn)行初始化,也可以設(shè)置為”gaussian"bias_filler: 偏置項(xiàng)的初始化。一般設(shè)置為"constant",值全為0。bias_term: 是否開(kāi)啟偏置項(xiàng),默認(rèn)為true, 開(kāi)啟
layer {name: "ip1"type: "InnerProduct"bottom: "pool2"top: "ip1"param {lr_mult: 1}param {lr_mult: 2}inner_product_param {num_output: 500weight_filler {type: "xavier"}bias_filler {type: "constant"}} }accuracy
輸出分類(lèi)(預(yù)測(cè))精確度,只有test階段才有,因此需要加入include參數(shù)。
層類(lèi)型:Accuracy
reshape
在不改變數(shù)據(jù)的情況下,改變輸入的維度。
層類(lèi)型:Reshape
示例如下
有一個(gè)可選的參數(shù)組shape, 用于指定blob數(shù)據(jù)的各維的值(blob是一個(gè)四維的數(shù)據(jù):n*c*w*h)。
dim:0 表示維度不變,即輸入和輸出是相同的維度。
dim:2 或 dim:3 將原來(lái)的維度變成2或3
dim:-1 表示由系統(tǒng)自動(dòng)計(jì)算維度。數(shù)據(jù)的總量不變,系統(tǒng)會(huì)根據(jù)blob數(shù)據(jù)的其它三維來(lái)自動(dòng)計(jì)算當(dāng)前維的維度值 。
假設(shè)原數(shù)據(jù)為:64*3*28*28, 表示64張3通道的28*28的彩色圖片
經(jīng)過(guò)reshape變換:
輸出數(shù)據(jù)為:64*3*14*56
Dropout
Dropout是一個(gè)防止過(guò)擬合的trick??梢噪S機(jī)讓網(wǎng)絡(luò)某些隱含層節(jié)點(diǎn)的權(quán)重不工作。
先看例子:
layer {name: "drop7"type: "Dropout"bottom: "fc7-conv"top: "fc7-conv"dropout_param {dropout_ratio: 0.5} }只需要設(shè)置一個(gè)dropout_ratio即可。
? vision_layer
主要是實(shí)現(xiàn)Convolution和Pooling操作, 主要有以下幾個(gè)類(lèi):
? ConvolutionLayer 最常用的卷積操作
更多細(xì)節(jié)可見(jiàn)卷積步長(zhǎng)
卷積中的卷
示例
layer {name: "conv1"type: "Convolution"bottom: "data"top: "conv1"param {lr_mult: 1}param {lr_mult: 2}convolution_param {num_output: 20kernel_size: 5stride: 1weight_filler {type: "xavier"}bias_filler {type: "constant"}} }? Im2colLayer 與MATLAB里面的im2col類(lèi)似,即image-tocolumn
transformation,轉(zhuǎn)換后方便卷積計(jì)算
? LRNLayer 全稱(chēng)local response normalization layer,在Hinton論文中有詳細(xì)介紹ImageNet Classification with Deep Convolutional Neural Networks 。
此層是對(duì)一個(gè)輸入的局部區(qū)域進(jìn)行歸一化,達(dá)到“側(cè)抑制”的效果。 參數(shù):全部為可選,沒(méi)有必須local_size: 默認(rèn)為5。如果是跨通道LRN,則表示求和的通道數(shù);如果是在通道內(nèi)LRN,則表示求和的正方形區(qū)域長(zhǎng)度。alpha: 默認(rèn)為1,歸一化公式中的參數(shù)。beta: 默認(rèn)為5,歸一化公式中的參數(shù)。norm_region: 默認(rèn)為ACROSS_CHANNELS。有兩個(gè)選擇,ACROSS_CHANNELS表示在相鄰的通道間求和歸一化。WITHIN_CHANNEL表示在一個(gè)通道內(nèi)部特定的區(qū)域內(nèi)進(jìn)行求和歸一化。與前面的local_size參數(shù)對(duì)應(yīng)。歸一化公式:對(duì)于每一個(gè)輸入, 去除以 ,得到歸一化后的輸出
layers {name: "norm1"type: LRNbottom: "pool1"top: "norm1"lrn_param {local_size: 5alpha: 0.0001beta: 0.75} }? PoolingLayer Pooling操作
池化層,為了減少運(yùn)算量和數(shù)據(jù)維度而設(shè)置的一種層。 層類(lèi)型:Pooling 必須設(shè)置的參數(shù):kernel_size: 池化的核大小。也可以用kernel_h和kernel_w分別設(shè)定。 其它參數(shù):pool: 池化方法,默認(rèn)為MAX。目前可用的方法有MAX, AVE, 或STOCHASTICpad: 和卷積層的pad的一樣,進(jìn)行邊緣擴(kuò)充。默認(rèn)為0stride: 池化的步長(zhǎng),默認(rèn)為1。一般我們?cè)O(shè)置為2,即不重疊。也可以用stride_h和stride_w來(lái)設(shè)置。示例
layer {name: "pool1"type: "Pooling"bottom: "conv1"top: "pool1"pooling_param {pool: MAXkernel_size: 3stride: 2} }pooling層的運(yùn)算方法基本是和卷積層是一樣的。輸入:n*c*w0*h0 輸出:n*c*w1*h1 和卷積層的區(qū)別就是其中的c保持不變w1=floor((w0+2*pad-kernel_size)/stride)+1;向下取整h1=floor((h0+2*pad-kernel_size)/stride)+1;向下取整 如果設(shè)置stride為2,前后兩次卷積部分不重疊。100*100的特征圖池化后,變成50*50. 由pad, kernel_size和stride三者共同決定。
更多細(xì)節(jié)可見(jiàn)卷積步長(zhǎng)
池化層
1.3 Nets結(jié)構(gòu)
Net由一系列的Layer組成(無(wú)回路有向圖DAG),Layer之間的連接由一個(gè)文本文件描述。模型初始化Net::Init()會(huì)產(chǎn)生blob和layer并調(diào)用Layer::SetUp。在此過(guò)程中Net會(huì)報(bào)告初始化進(jìn)程。這里的初始化與設(shè)備無(wú)關(guān),在初始化之后通過(guò)Caffe::set_mode()設(shè)置Caffe::mode()來(lái)選擇運(yùn)行
平臺(tái)CPU或GPU,結(jié)果是相同的。
Net
就像搭積木一樣,一個(gè)net由多個(gè)layer組合而成。
現(xiàn)給出 一個(gè)簡(jiǎn)單的2層神經(jīng)網(wǎng)絡(luò)的模型定義( 加上loss 層就變成三層了),先給出這個(gè)網(wǎng)絡(luò)的拓?fù)洹?/p>
第一層:name為mnist, type為Data,沒(méi)有輸入(bottom),只有兩個(gè)輸出(top),一個(gè)為data,一個(gè)為label
第二層:name為ip,type為InnerProduct, 輸入數(shù)據(jù)data, 輸出數(shù)據(jù)ip
第三層:name為loss, type為SoftmaxWithLoss,有兩個(gè)輸入,一個(gè)為ip,一個(gè)為label,有一個(gè)輸出loss,沒(méi)有畫(huà)出來(lái)。
對(duì)應(yīng)的配置文件prototxt就可以這樣寫(xiě):
第一行將這個(gè)模型取名為L(zhǎng)ogReg, 然后是三個(gè)layer的定義,參數(shù)都比較簡(jiǎn)單,只列出必須的參數(shù)。
卷積神經(jīng)網(wǎng)絡(luò)示例
優(yōu)化求解過(guò)程Solver
solver算是caffe的核心的核心,它協(xié)調(diào)著整個(gè)模型的運(yùn)作。caffe程序運(yùn)行必帶的一個(gè)參數(shù)就是solver配置文件。運(yùn)行代碼一般為
./build/tools/caffe train --solver=examples/myfile/solver.prototxt -gpu all &> examples/myfile/output/output.log #或者 ./build/tools/caffe train -solver examples/myfile/solver.prototxt -gpu all &> examples/myfile/output/output.log在Deep Learning中,往往loss function是非凸的,沒(méi)有解析解,我們需要通過(guò)優(yōu)化方法來(lái)求解。
? 求解器Solver是什么?
? Caffe的重中之重(核心)——Solver
? 負(fù)責(zé)對(duì)模型優(yōu)化,讓損失函數(shù)(loss function)達(dá)到全局最小。
? solver的主要作用就是交替調(diào)用前向(forward)算法和后向(backward)算法來(lái)更新參數(shù),實(shí)際上就是一種迭代的優(yōu)化算法。
優(yōu)化算法
caffe提供了六種優(yōu)化算法來(lái)求解最優(yōu)參數(shù),在solver配置文件中,通過(guò)設(shè)置type類(lèi)型來(lái)選擇。
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的流程
1. 設(shè)計(jì)好需要優(yōu)化的對(duì)象,以及用于學(xué)習(xí)的訓(xùn)練網(wǎng)絡(luò)和用于評(píng)估的測(cè)試網(wǎng)絡(luò)。(通過(guò)調(diào)用另外一個(gè)配置文件prototxt來(lái)進(jìn)行)2. 通過(guò)forward和backward迭代的進(jìn)行優(yōu)化來(lái)跟新參數(shù)。3. 定期的評(píng)價(jià)測(cè)試網(wǎng)絡(luò)。 (可設(shè)定多少次訓(xùn)練后,進(jìn)行一次測(cè)試)4. 在優(yōu)化過(guò)程中顯示模型和solver的狀態(tài)在每一次的迭代過(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)。示例
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設(shè)置深度網(wǎng)絡(luò)模型。每一個(gè)模型就是一個(gè)net,需要在一個(gè)專(zhuān)門(mén)的配置文件中對(duì)net進(jìn)行配置,每個(gè)net由許多的layer所組成。注意的是:文件的路徑要從caffe的根目錄開(kāi)始,其它的所有配置都是這樣。
net: "examples/mnist/lenet_train_test.prototxt"也可用train_net和test_net來(lái)對(duì)訓(xùn)練模型和測(cè)試模型分別設(shè)定。例如:
train_net:"examples/hdf5_classification/logreg_auto_train.prototxt" test_net: "examples/hdf5_classification/logreg_auto_test.prototxt"test_iter要與test layer中的batch_size結(jié)合起來(lái)理解。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ù),稱(chēng)之為一個(gè)epoch
test_iter: 100測(cè)試間隔。也就是每訓(xùn)練500次,才進(jìn)行一次測(cè)試。
test_interval: 500下面四行用于學(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è)置。
base_lr: 0.01 lr_policy: "inv" gamma: 0.0001 power: 0.75lr_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))))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: 9500momentum上一次梯度更新的權(quán)重
momentum :0.9優(yōu)化算法選擇。這一行可以省掉,因?yàn)槟J(rèn)值就是SGD,總共有六種方法可選擇。
type: SGD權(quán)重衰減項(xiàng),防止過(guò)擬合的一個(gè)參數(shù)。
weight_decay: 0.0005每訓(xùn)練100次,在屏幕上顯示一次。如果設(shè)置為0,則不顯示。
display: 100最大迭代次數(shù)。這個(gè)數(shù)設(shè)置太小,會(huì)導(dǎo)致沒(méi)有收斂,精確度很低。設(shè)置太大,會(huì)導(dǎo)致震蕩,浪費(fèi)時(shí)間。
max_iter: 20000快照。將訓(xùn)練出來(lái)的model和solver狀態(tài)進(jìn)行保存,snapshot用于設(shè)置訓(xùn)練多少次后進(jìn)行保存,默認(rèn)為0,不保存。snapshot_prefix設(shè)置保存路徑。
還可以設(shè)置snapshot_diff,是否保存梯度值,默認(rèn)為false,不保存。
也可以設(shè)置snapshot_format,保存的類(lèi)型。有兩種選擇:HDF5 和BINARYPROTO ,默認(rèn)為BINARYPROTO
設(shè)置運(yùn)行模式。默認(rèn)為GPU,如果你沒(méi)有GPU,則需要改成CPU,否則會(huì)出錯(cuò)。
solver_mode: CPUsolver優(yōu)化方法
caffe的六種優(yōu)化方法:
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就是用來(lái)使loss最小化的優(yōu)化方法。對(duì)于一個(gè)數(shù)據(jù)集D,需要優(yōu)化的目標(biāo)函數(shù)是整個(gè)數(shù)據(jù)集中所有數(shù)據(jù)loss的平均值。
其中,fW(x(i)) 計(jì)算的是數(shù)據(jù) x(i) 上的 loss, 先將每個(gè)單獨(dú)的樣本 x 的 loss 求出來(lái),然后求和,最后求均值。 r(W) 是正則項(xiàng)(weight_decay),為了減弱過(guò)擬合現(xiàn)象。
如果采用這種Loss 函數(shù),迭代一次需要計(jì)算整個(gè)數(shù)據(jù)集,在數(shù)據(jù)集非常大的這情況下,這種方法的效率很低,這個(gè)也是我們熟知的梯度下降采用的方法。
在實(shí)際中,通過(guò)將整個(gè)數(shù)據(jù)集分成幾批(batches), 每一批就是一個(gè)mini-batch,其數(shù)量(batch_size)為N<<|D|,此時(shí)的loss 函數(shù)為
有了loss函數(shù)后,就可以迭代的求解loss和梯度來(lái)優(yōu)化這個(gè)問(wèn)題。在神經(jīng)網(wǎng)絡(luò)中,用forward pass來(lái)求解loss,用backward pass來(lái)求解梯度。
在caffe中,默認(rèn)采用的Stochastic Gradient Descent(SGD)進(jìn)行優(yōu)化求解。后面幾種方法也是基于梯度的優(yōu)化方法(like SGD),因此本文只介紹一下SGD。
1、Stochastic gradient descent(SGD)
隨機(jī)梯度下降(Stochastic gradient descent)是在梯度下降法(gradient descent)的基礎(chǔ)上發(fā)展起來(lái)的,梯度下降法也叫最速下降法。SGD在通過(guò)負(fù)梯度和上一次的權(quán)重更新值Vt的線(xiàn)性組合來(lái)更新W,迭代公式如下:
其中, α 是負(fù)梯度的學(xué)習(xí)率(base_lr),μ 是上一次梯度值的權(quán)重(momentum),用來(lái)加權(quán)之前梯度方向?qū)ΜF(xiàn)在梯度下降方向的影響。這兩個(gè)參數(shù)需要通過(guò)tuning來(lái)得到最好的結(jié)果,一般是根據(jù)經(jīng)驗(yàn)設(shè)定的。
在深度學(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)定以及快速。關(guān)于更多的momentum,請(qǐng)參看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.9lr_policy設(shè)置為step,則學(xué)習(xí)率的變化規(guī)則為 base_lr * gamma ^ (floor(iter / stepsize))
lr_policy設(shè)置為step,則學(xué)習(xí)率的變化規(guī)則為 base_lr * gamma ^ (floor(iter / stepsize))
即前1000次迭代,學(xué)習(xí)率為0.01; 第1001-2000次迭代,學(xué)習(xí)率為0.001; 第2001-3000次迭代,學(xué)習(xí)率為0.00001,第3001-3500次迭代,學(xué)習(xí)率為10-5
上面的設(shè)置只能作為一種指導(dǎo),它們不能保證在任何情況下都能得到最佳的結(jié)果,有時(shí)候這種方法甚至不work。如果學(xué)習(xí)的時(shí)候出現(xiàn)diverge(比如,你一開(kāi)始就發(fā)現(xiàn)非常大或者NaN或者inf的loss值或者輸出),此時(shí)你需要降低base_lr的值(比如,0.001),然后重新訓(xùn)練,這樣的過(guò)程重復(fù)幾次直到你找到可以work的base_lr。
2、AdaDelta
AdaDelta是一種”魯棒的學(xué)習(xí)率方法“,是基于梯度的優(yōu)化方法(like SGD)。
具體的介紹文獻(xiàn):
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從最后兩行可看出,設(shè)置solver type為Adadelta時(shí),需要設(shè)置delta的值。
3、AdaGrad
自適應(yīng)梯度(adaptive gradient)是基于梯度的優(yōu)化方法(like SGD)
自適應(yīng)梯度(adaptive gradient)是基于梯度的優(yōu)化方法(like SGD)
具體的介紹文獻(xiàn):
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
是一種基于梯度的優(yōu)化方法(like SGD)。
具體的介紹文獻(xiàn):
D. Kingma, J. Ba. Adam: A Method for Stochastic Optimization. International Conference for Learning Representations, 2015.
5、NAG
Nesterov 的加速梯度法(Nesterov’s accelerated gradient)作為凸優(yōu)化中最理想的方法,其收斂速度非常快。
具體的介紹文獻(xiàn):
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課程演講中提出來(lái)的,也是一種基于梯度的優(yōu)化方法(like SGD)
具體的介紹文獻(xiàn):
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最后兩行,需要設(shè)置rms_decay值。
2. Caffe 的 I/O 模塊
將圖片數(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
示例文件及代碼見(jiàn)首行中的百度云共享。
#Image to txt:at the path of "scripts" ls IO2LMDB/blue | sed "s:^:blue/:" | sed "s:$: 0:" >> data.txt ls IO2LMDB/red | sed "s:^:red/:" | sed "s:$: 1:" >> data.txt#txt to LMDB : at the path of "OI2LMDB" convert_imageset -shuffle:'true' ./data.txt db_train_lmdb對(duì)Layer做參數(shù)配置(Data Layer參數(shù)配置為例)
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: 100backend: LMDB} }name: 表示該層的名稱(chēng),可隨意取。
type: 層類(lèi)型,如果是Data,表示數(shù)據(jù)來(lái)源于LevelDB或LMDB。根
據(jù)數(shù)據(jù)的來(lái)源不同,數(shù)據(jù)層的類(lèi)型也不同(后面會(huì)詳細(xì)闡述)。一
般在練習(xí)的時(shí)候,我們都是采用的LevelDB或LMDB數(shù)據(jù),因此層
類(lèi)型設(shè)置為Data。
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ì)是分類(lèi)模型所
必需的。
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è)置:
通常數(shù)據(jù)的預(yù)處理(如減去均值, 放大縮小, 裁剪和鏡像等),Caffe使用OpenCV做處理
layer {name: "cifar"type: "Data"top: "data"top: "label"include {phase: TEST}transform_param {mean_file: "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è)試階段從中間裁剪}data_param {source: "examples/cifar10/cifar10_test_lmdb"batch_size: 100backend: LMDB} }3. Caffe 中五種層的實(shí)現(xiàn)和參數(shù)配置
3.1 卷積層參數(shù)配置
layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 #學(xué)習(xí)率1,和權(quán)值更新相關(guān) } param { lr_mult: 2 #學(xué)習(xí)率2,和權(quán)值更新相關(guān) } convolution_param { num_output: 50 # 50個(gè)輸出的map kernel_size: 5 #卷積核大小為5*5 stride: 1 #卷積步?長(zhǎng)為1 weight_filler { #權(quán)值初始化方式 type: “xavier" #默認(rèn)為“constant",值全為0,很多時(shí)候我們也可以?用"xavier"或者”gaussian"來(lái)進(jìn)行初始化 } bias_filler { #偏置值的初始化?方式 type: “constant"#該參數(shù)的值和weight_filler類(lèi)似, ?一般設(shè)置為"constant",值全為0 } } }3.2 池化層參數(shù)配置
layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX #Pool為池化方式,默認(rèn)值為MAX,可以選擇的參數(shù)有MAX、AVE、STOCHASTIC kernel_size: 2 #池化區(qū)域的大小,也可以用kernel_h和kernel_w分別設(shè) 置長(zhǎng)和寬 stride: 2 #步長(zhǎng),即每次池化區(qū)域左右或上下移動(dòng)的距離,一般和kernel_size相同,即為不重疊池化。也可以也可以小于kernel_size,即為重疊池化,Alexnet中就用到了重疊池化的方法 } }3.3 全連接層參數(shù)配置
#參數(shù)和卷積層表達(dá)?一樣 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.4 激活函數(shù)層參數(shù)配置
激活函數(shù)作用:激活函數(shù)是用來(lái)引入非線(xiàn)性因素的。
激活函數(shù)一般具有以下性質(zhì):
■ 非線(xiàn)性: 線(xiàn)性模型的不足我們前邊已經(jīng)提到。
■ 處處可導(dǎo):反向傳播時(shí)需要計(jì)算激活函數(shù)的偏導(dǎo)數(shù),所以要求激活函數(shù)除個(gè)別點(diǎn)外,處處可導(dǎo)。
■ 單調(diào)性:當(dāng)激活函數(shù)是單調(diào)的時(shí)候,單層網(wǎng)絡(luò)能夠保證是凸函數(shù)。
■ 輸出值的范圍: 當(dāng)激活函數(shù)輸出值是有限的時(shí)候,基于梯度的優(yōu)化方法會(huì)更加穩(wěn)定,因?yàn)樘卣鞯谋硎臼苡邢迿?quán)值的影響更顯著
Type為該層類(lèi)型,可取值分別為:
(1)ReLU:表示我們使用relu激活函數(shù),relu層支持in-place計(jì)算,這意味
著該層的輸入和輸出共享一塊內(nèi)存,以避免內(nèi)存的消耗。
(2)Sigmoid:代表使用sigmoid函數(shù);
(3) TanH:代表使用tanh函數(shù);
(4) AbsVal:計(jì)算每個(gè)輸入的絕對(duì)值f(x)=Abs(x)
(5)power對(duì)每個(gè)輸入數(shù)據(jù)進(jìn)行冪運(yùn)算
f(x)= (shift + scale * x) ^
power
層類(lèi)型:Power
可選參數(shù):
power: 默認(rèn)為1
scale: 默認(rèn)為1
shift:默認(rèn)值為0
3.5 softmax層
#可以計(jì)算給出每個(gè)樣本 對(duì)應(yīng)的損失函數(shù)值 layer { name: "loss" type: "SoftmaxWithLoss" bottom: "ip2" bottom: "label" top: "loss" }#輸出為每個(gè)類(lèi)別的概率值 layers { name: "prob" type: “Softmax" bottom: " ip2" top: "prob" }4. Caffe的可視化
4.1 網(wǎng)絡(luò)結(jié)構(gòu)可視化和特征可視化
可參考
http://blog.csdn.net/jiandanjinxin/article/details/50686461
http://blog.csdn.net/jiandanjinxin/article/details/50410290
4.2 可視化loss和accurary 曲線(xiàn)
cd caffer-master sh data/mnist/get_mnist.sh sh examples/mnist/create_mnist.sh sh examples/mnist/train_lenet.sh &> output.log plot_training_log.py.example -h #可查看用法 ./tools/extra/plot_training_log.py.example 0 testaccuracyvsiters.png output.log ./tools/extra/plot_training_log.py.example 2 testaccuracyvsiters.png output.log使用訓(xùn)練好的模型
均值文件mean file
■ 將所有訓(xùn)練樣本的均值保存為文件
■ 圖片減去均值后,再進(jìn)?行訓(xùn)練和測(cè)試,會(huì)提高速度和精度
■ 運(yùn)行方法:(使用Caffe?工具)
compute_image_mean [train_lmdb] [mean.binaryproto]
fine-turn微調(diào)網(wǎng)絡(luò)
■ 1. 準(zhǔn)備新數(shù)據(jù)的數(shù)據(jù)庫(kù)(如果需要用mean file,還要準(zhǔn)備對(duì)應(yīng)的新的mean file), 具體方法和圖片轉(zhuǎn)換lmdb方式一樣。
■ 2. 調(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í)速率加快。
■ 3. 修改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),其他的策略可以保持不
變。
■ 4. 重新訓(xùn)練時(shí),要指定之前的權(quán)值文件:
■ # caffe train –solver [新的solver文件] –weights [舊的caffemodel]
5. 深度學(xué)習(xí)模型訓(xùn)練 Tricks
更多trick可見(jiàn)書(shū)籍《Neural Networks: Tricks of the Trade》
5.1 數(shù)據(jù)準(zhǔn)備與擴(kuò)增
1.1 數(shù)據(jù)準(zhǔn)備:
一般數(shù)據(jù)集可能不會(huì)給出驗(yàn)證集,所以自?己會(huì)從給的訓(xùn)練集中按照一定比例(9:1)分離出驗(yàn)證集。
1.2 數(shù)據(jù)的擴(kuò)增
因?yàn)樯疃染W(wǎng)絡(luò)需要在大規(guī)模的訓(xùn)練圖像上來(lái)滿(mǎn)足性能,所以當(dāng)原始圖像中的訓(xùn)練數(shù)據(jù)集規(guī)模不夠多時(shí),較好的辦法是擴(kuò)增數(shù)據(jù)來(lái)提升模型性能。換言之,數(shù)據(jù)擴(kuò)增對(duì)于訓(xùn)練深度網(wǎng)絡(luò)來(lái)說(shuō)是必須的。
常用的方法:
1. 沿著x軸將圖片左右翻轉(zhuǎn)
2. 隨機(jī)的剪切、縮放、旋轉(zhuǎn)
3. 顏色抖動(dòng)
4. 提高圖像中像素的飽和度和值(即 HSV顏色空間的 S 和 V 成分)到 0.250.25 和44 之間(在一個(gè)樣本圖像內(nèi)要保證各個(gè)像素該值是一樣的),再在圖像上加上一個(gè)范圍在 [?0.1,0.1][?0.1,0.1] 之間的值給 H( hue ,即 HSV 中的色調(diào))這個(gè)成分。
5. 用pca來(lái)改變RGB的強(qiáng)度值,產(chǎn)生分別對(duì)應(yīng)的特征值和特征向量,然后用均值為0方差為0.1的隨機(jī)數(shù)與特征值和特征向量相乘得到新的數(shù)據(jù)。(《ImageNet Classification with Deep Convolutional Neural Networks》)
5.2 圖像預(yù)處理
常見(jiàn)的是減均值、除方差,還有變化到-1?1,主要針對(duì)不同尺度的特征,進(jìn)行尺度變換normaliz。
常用的預(yù)處理方法:
1. 去均值和規(guī)范化
通常作為第一步且較簡(jiǎn)單的一種方式是去均值(zero-centered ,通俗地說(shuō):讓每個(gè)樣本都減去整體樣本的均值,使整體樣本的新均值為 0),并規(guī)范化(normalize)它們。
另一種在預(yù)處理用于規(guī)范化(normalize)數(shù)據(jù)的方法是將每一個(gè)維度的最大最小值分別限定為1 和 ?1 。
在此過(guò)程中,數(shù)據(jù)先經(jīng)過(guò)去均值,然后計(jì)算出(能刻畫(huà)數(shù)據(jù)內(nèi)部相關(guān)結(jié)果的)協(xié)方差矩陣:
>>> X -= np.mean(X, axis = 0) # 去均值 >>> cov = np.dot(X.T, X) / X.shape[0] # 計(jì)算協(xié)?方差矩陣之后對(duì)數(shù)據(jù)去相關(guān),?方法是將(剛剛?cè)ゾ岛蟮?#xff09;原始數(shù)據(jù)投影到特征基(eigenbasis )上:
>>> U,S,V = np.linalg.svd(cov) # 對(duì)數(shù)據(jù)的協(xié)?方差矩陣計(jì)算 SVD 分解 >>> Xrot = np.dot(X, U) # 對(duì)數(shù)據(jù)去相關(guān)最后一步是白化,它對(duì)去相關(guān)后的數(shù)據(jù)在每個(gè)維度上的特征值做尺度規(guī)范化處理:
>>> Xwhite = Xrot / np.sqrt(S + 1e-5) # 除以特征值(其實(shí)是奇異值的開(kāi)平方根)5.3 參數(shù)初始化
■ 訓(xùn)練網(wǎng)絡(luò)前對(duì)參數(shù)做初始化。
■ 常用的初始化方法:
1. 全零初始化 —> 錯(cuò)誤
2. 小隨機(jī)數(shù)初始化
是一種接近 0 但不是 0的權(quán)重初始化方法。
做法是初始化權(quán)重為接近 0 的隨機(jī)小數(shù),因?yàn)楹芙咏?0 但不相等,這也被稱(chēng)為“對(duì)稱(chēng)破缺”( symmetry breaking )。
在訓(xùn)練中計(jì)算出的更新是不同的,并在之后整合自己的“貢獻(xiàn)”作為整個(gè)
網(wǎng)絡(luò)的不同部分。權(quán)重初始化的過(guò)程多少有點(diǎn)像 weights0.001×N(0,1),其中 N(0,1)N表示均值為 0 ,標(biāo)準(zhǔn)差為 1 的高斯分布。當(dāng)然也可以使用服從均勻分布的隨機(jī)小數(shù),但在二者在實(shí)際中的性能表現(xiàn)上只有很微弱的差別。
先前通過(guò)校準(zhǔn)神經(jīng)元上的方差來(lái)初始化參數(shù)并未考慮使用 ReLUs這樣的激活函數(shù)。最近一篇論?文《Surpassing Human-Level Performance on ImageNet Classification》討論了如何為 ReLUs這樣的激活函數(shù)做參數(shù)初始化,從而使網(wǎng)絡(luò)中神經(jīng)元的方差為 2.0/n,初始化?方式如下:
5.4 卷積參數(shù)的Tricks
■ 1. 圖片輸入是2的冪次方,例如32、64、96、224等。
■ 2. 卷積核大小是3*3或者5*5。
■ 3. 輸入圖片上下左右需要用0補(bǔ)充,即padding,且假如卷積核大小是5
那么padding就是2(圖?片左右上下都補(bǔ)充2),卷積核大小是3padding
大小就是1。
5.5 池化層參數(shù)初始化Tricks
■ 1. poolin層也能防?止過(guò)擬合,使用overlapped pooling,即用來(lái)池化
的數(shù)據(jù)有重疊,但是pooling的?大小不要超過(guò)3,常用的池化是2X2。
■ 2. max pooling比avg pooling效果會(huì)好一些。
5.6 學(xué)習(xí)率
■ 1. 0.1是學(xué)習(xí)率的常用值
■ 2. 在實(shí)際中,如果在驗(yàn)證集上看不到性能的提升(如損失函數(shù)值下降或者準(zhǔn)確率上升),那就可以對(duì)當(dāng)前的學(xué)習(xí)率除以 2(或 5 )看看效果并循環(huán)這一過(guò)程,或許能給你一個(gè)驚喜。
5.7 正則化:防止過(guò)擬合
過(guò)擬合,就是擬合函數(shù)需要顧忌每一個(gè)點(diǎn),最終形成的擬合函數(shù)波動(dòng)很大。在某些很小的區(qū)間里,函數(shù)值的變化很劇烈。這就意味著函數(shù)在某些小區(qū)間里的導(dǎo)數(shù)值(絕對(duì)值)非常大,由于自變量值可大可小,所以只有系數(shù)足夠大,才能保證導(dǎo)數(shù)值很大。而正則化是通過(guò)約束參數(shù)的范數(shù)使其不要太大,所以可以在一定程度上減少過(guò)擬合情況。
常用防止過(guò)擬合方式:
1. L2正則化
2. L1正則化
3. 最大模限制
4. Dropout
Dropout 是一個(gè)超級(jí)有效、簡(jiǎn)單且是前陣子由 Srivastava 等人提出
《Dropout: A Simple Way to Prevent Neural Networks from
Overfitting》的,它是其它正則方法(如 L1 、 L2 、 最大模限制 )的
補(bǔ)充。在訓(xùn)練中, dropout 可理解為對(duì)整個(gè)神經(jīng)網(wǎng)絡(luò)進(jìn)行抽樣(出的
網(wǎng)絡(luò)),并基于輸入數(shù)據(jù)僅僅更新抽樣網(wǎng)絡(luò)的參數(shù)。(因?yàn)檫@些抽樣
得到的網(wǎng)絡(luò)是共享參數(shù)的,所以這些抽樣出的網(wǎng)絡(luò)的權(quán)重參數(shù)并非是
獨(dú)立的)。
5.8 觀察損失曲線(xiàn):學(xué)習(xí)率
5.9 放大損失曲線(xiàn):學(xué)習(xí)率、batch大小
5.10 觀察準(zhǔn)確率曲線(xiàn)
5.11 fine-turn的方法
■ 如果你的數(shù)據(jù)量有限,那么,一般不建議自己完全從頭訓(xùn)練起caffe
模型。一般是找相關(guān)的項(xiàng)目或者模型,先f(wàn)inetuning一下,之后再慢
慢的調(diào)整。一般fine tuning的方式,都是把learning rate(solver.prototxt)調(diào)低(為原來(lái)的十分之一),之后把訓(xùn)練模型的
最后一層或者兩層的學(xué)習(xí)速率調(diào)大一點(diǎn)————這就相當(dāng)于,把模
型的前面那些層的學(xué)習(xí)調(diào)低,使得參數(shù)更新的慢一點(diǎn)以達(dá)到微調(diào)的目的。
■ 微調(diào)的時(shí)候,有時(shí)候訓(xùn)練數(shù)據(jù)特別少,而且希望模型的前面幾層的
參數(shù)保持不變。方法是使得這幾個(gè)層的學(xué)習(xí)速率為0就可以了,比
如設(shè)定lr_mult為0。
5.12 模型集成
■ 在機(jī)器學(xué)習(xí)中,集成方法( ensemble methods )是指訓(xùn)練多個(gè)學(xué)習(xí)器并在之后將它們組合使用,最終得到一個(gè)強(qiáng)有力的分類(lèi)器的方法。
■ 幾種集成方式的技巧:
■ 1. 集成不同初始化的模型
使用交叉驗(yàn)證集來(lái)確定最佳的超參數(shù),再在基于最佳超參數(shù)的情況下,使用不同的隨機(jī)初始化方法來(lái)初始化權(quán)重來(lái)訓(xùn)練多個(gè)模型。該方法的風(fēng)險(xiǎn)在于權(quán)重初始化方法的不同產(chǎn)生的差異。
■ 2.集成 topN 表現(xiàn)的模型
使用交叉驗(yàn)證集確定了最佳的超參數(shù)后,再選取表現(xiàn)最佳的前 topN 個(gè)模型進(jìn)行集成。這可以提升集成模型的多樣性,但?風(fēng)險(xiǎn)就是這幾個(gè)模型都是局部最優(yōu)模型。實(shí)際實(shí)踐中,這種做法可以達(dá)到不錯(cuò)的性能,因?yàn)椴恍枰?#xff08;在交叉驗(yàn)證后)對(duì)模型進(jìn)行額外的重新訓(xùn)練。實(shí)際上,可以直接在 Caffe Model Zoo 中選擇表現(xiàn)性能在 topN 的幾個(gè)深度模型進(jìn)行集成。
總結(jié)
以上是生活随笔為你收集整理的caffe 框架梳理(待续)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 云中神殿露峥嵘!《新大话3》年度资料片倒
- 下一篇: NIPS 2016上22篇论文的实现汇集