Layers Of Caffe
本文試圖描述構建一個網絡結構的layers,可以用prototxt腳本直接寫,也可以用python接口實現。
最簡單的神經網絡包含但不限於以下四部分:
數據層(Data): Data、ImageData
激活層(Activation): sigmoid、tanh、relu
視覺層(vision) :Convolution、Pooling、 Local Response Normalization (LRN)、 im2col
輸出層(output): softmax_loss、Inner Product、accuracy、reshape、dropout
A、數據層(Data)
數據層是每個模型的最底層,是模型的入口,不僅提供數據的輸入,也提供數據從Blobs轉換成別的格式進行保存輸出。通常數據的預處理(如減去均值, 放大縮小, 裁剪和鏡像等),也在這一層設置參數實現。
數據來源來自:
高效率:高效的數據庫(如LevelDB和LMDB)、內存;
低效率:磁盤的hdf5文件、圖片格式文件。
所有的數據層的都具有的公用參數:
layer { name: "cifar" type: "Data" top: "data" top: "label" include { phase: TRAIN } transform_param { mean_file:"examples/cifar10/mean.binaryproto" scale: 0.00390625 # 用一個配置文件來進行均值操作 mirror: 1 # 1表示開啟鏡像,0表示關閉,也可用ture和false來表示 # 剪裁一個 227*227的圖塊,在訓練階段隨機剪裁,在測試階段從中間裁剪 如果超過這個數據就會裁剪 crop_size: 227 shuffle: true #隨機打亂數據 } 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之間
1、數據來自於數據庫(如LevelDB和LMDB)
LMDB數據制作:圖像數據轉換成db(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、數據來自於圖片image
層類型:ImageData
必須設置的參數:
source: 一個文本文件的名字,每一行給定一個圖片文件的名稱和標簽(label)
/iamges/aaa.jpg 0
/images/bbb.jpg 1
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 } }
B、激活層(Activation)
在激活層中,對輸入數據進行激活操作(實際上就是一種函數變換),是逐元素進行運算的。從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" }
python代碼:
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的輸出和輸入相同以避免內存的消耗。
python代碼實現
relu = Layers.ReLU(inputs, in_place=True)
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” }
C、視覺層(vision)
視覺層(Vision Layers)的參數,視覺層包括Convolution, Pooling, Local Response Normalization (LRN), im2col等層。
前一節中Data層用python代碼實現:
data, label = L.Data(source=lmbd_file, backend=P.Data.LMDB, batch_size=batch_size_num,ntop=2,transform_parm=dict(crop_size=40,mean_file=mean_file,mirror=True))
這塊預留ImageData的python實現代碼:
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" #0 } } }
用python代碼實現:
conv1 = Layer.Convolution(data,kernel_size=5, stride=1, num_output=16,pad=2,weight_filler=dict(type=‘xavier‘))
參數:
data為數據層傳遞的數據
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,前後兩次卷積部分不重疊。100*100的特征圖池化後,變成50*50. python實現代碼:pool1 = Layer.Pooling(inputs,pool=Pooling.Max,kernel_size=3,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 } }
python代碼實現:
待續。。
4、im2col層
如果對matlab比較熟悉的話,就應該知道im2col是什麽意思。它先將一個大矩陣,重疊地劃分為多個子矩陣,對每個子矩陣序列化成向量,最後得到另外一個矩陣。
看一看圖就知道了:
在caffe中,卷積運算就是先對數據進行im2col操作,再進行內積運算(inner product)。這樣做,比原始的卷積操作速度更快。
看看兩種卷積操作的異同:
D、輸出層(output)
包括: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" }
python代碼:
loss = Layers.SoftmaxWithLoss(fc,label) #label是數據層的label
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" } } }
python實現代碼:
fc = Layers.InnerProduct(pool2, num_output=1024,weight_filler=dict(type=‘xavier‘))
3、accuracy
輸出分類(預測)精確度,只有test階段才有,因此需要加入include參數。
層類型:Accuracy
layer { name: "accuracy" type: "Accuracy" bottom: "ip2" bottom: "label" top: "accuracy" include { phase: TEST } }
python代碼實現:
accurary = Layers.Accurary(fc,label)
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 } }
只需要設置一個dropout_ratio就可以了。
還有其它更多的層,但用的地方不多,就不一一介紹了。
隨著深度學習的深入,各種各樣的新模型會不斷的出現,因此對應的各種新類型的層也在不斷的出現。這些新出現的層,我們只有在等caffe更新到新版本後,再去慢慢地摸索了。
https://www.cnblogs.com/denny402/tag/caffe/
Layers Of Caffe