Caffe源代碼學習 — AlexNet(Caffenet.py)

歡迎訪問我的個人博客:zengzeyu.com

導言


源碼位置:caffe/examples/pycaffe/caffenet.py
該文件源代碼是經典模型AlexNet的Caffe實現,有興趣的小夥伴去拜讀一下論文: ImageNet Classification with Deep Convolutional Neural Networks.

源碼解讀


1. 導入模塊

from __future__ import print_function
from caffe import layers as L, params as P, to_proto
from caffe.proto import caffe_pb2

2. 定義Layer函數

包括: 卷積層(Convolution Layer)、全連接層(Full Connected Layer)和池化層(Pooling Layer)

2.1 卷積層(Convolution Layer)函數

def conv_relu(bottom, ks, nout, stride=1, pad=0, group=1):
    conv = L.Convolution(bottom, kernel_size=ks, stride=stride,
                                num_output=nout, pad=pad, group=group)
    return conv, L.ReLU(conv, in_place=True)

1. 函數輸入
- bottom - 輸入節點(blob)名
- ks - 卷積核尺寸(kernel size
- nout - 輸出深度尺寸(number output
- stride - 卷積核滑窗距離
- pad - 圖像邊緣添加尺寸,即在圖像周圍一週添加尺寸爲pad的空白像素
- group - 將數據進行分開訓練堆數目

2. 調用Caffe卷基層生成函數
- conv = L.Convolution(bottom, kernel_size=ks, stride=stride,num_output=nout, pad=pad, group=group)

3. 返回參數
- conv - 卷積層配置
- L.ReLU(conv, in_place=True) - 卷積後的數據經過ReLU激活函數得到的數據

2.2 全連接層(Full Connected Layer)

def fc_relu(bottom, nout):
    fc = L.InnerProduct(bottom, num_output=nout)
    return fc, L.ReLU(fc, in_place=True)

1. 調用Caffe內積函數
- fc = L.InnerProduct(bottom, num_output=nout)

2. 返回參數
- fc, L.ReLU(fc, in_place=True) - 全連接分類之後數據通過ReLU函數

2.3 池化層(Pooling Layer)

def max_pool(bottom, ks, stride=1):
    return L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride)

調用Caffe池化層生成函數
- L.Pooling)()
- pool=P.Pooling.MAX - 池化類型選擇MAX,即取模板內最大值輸出

3. 定義網絡結構

data, label = L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2,
        transform_param=dict(crop_size=227, mean_value=[104, 117, 123], mirror=True))

         # the net itself
    conv1, relu1 = conv_relu(data, 11, 96, stride=4)
    pool1 = max_pool(relu1, 3, stride=2)
    norm1 = L.LRN(pool1, local_size=5, alpha=1e-4, beta=0.75)
    conv2, relu2 = conv_relu(norm1, 5, 256, pad=2, group=2)
    pool2 = max_pool(relu2, 3, stride=2)
    norm2 = L.LRN(pool2, local_size=5, alpha=1e-4, beta=0.75)
    conv3, relu3 = conv_relu(norm2, 3, 384, pad=1)
    conv4, relu4 = conv_relu(relu3, 3, 384, pad=1, group=2)
    conv5, relu5 = conv_relu(relu4, 3, 256, pad=1, group=2)
    pool5 = max_pool(relu5, 3, stride=2)
    fc6, relu6 = fc_relu(pool5, 4096)
    drop6 = L.Dropout(relu6, in_place=True)
    fc7, relu7 = fc_relu(drop6, 4096)
    drop7 = L.Dropout(relu7, in_place=True)
    fc8 = L.InnerProduct(drop7, num_output=1000)
    loss = L.SoftmaxWithLoss(fc8, label)

    if include_acc:
        acc = L.Accuracy(fc8, label)
        return to_proto(loss, acc)
    else:
        return to_proto(loss)

1. 函數輸入
- lmdb - 文件名
- batch_size - 每次訓練輸入樣本數目
- include_acc - 加速?

2. 調用Caffe數據層輸入函數(Data)
L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2,
transform_param=dict(crop_size=227, mean_value=[104, 117, 123], mirror=True))

- backend - 數據類型
- ntop - 輸出blob數目,因爲數據層處理數據輸出data和label,所以值爲 2
- transform_param - 對單個圖片處理: crop_size圖片剪裁大小,mean_valueRGB圖像需要減去的值(目的是更好突出特徵)和mirror鏡像處理。

3. 網絡結構
此博客繪製了AlexNet網絡結構圖和數據流動圖,方便直觀理解網絡結構,可移步:深度學習之圖像分類模型AlexNet解讀
第1-5層爲卷積層,如下表所示:

Layer Operation Output
Data crop_size:227, mean_value: [104, 117, 123], mirror: true data: 227x227x3; label: 227x227x1
1 conv1 -> relu1 -> pool1 -> norm1 27x27x96
2 conv2 -> relu2 -> pool2 -> norm2 13x13x256
3 conv3 -> relu3 11x11x384
4 conv4 -> relu4 11x11x384
5 conv5 -> relu5 -> pool5 6x6x256
6 fc6 -> relu6 -> drop6 4096
7 fc7 -> relu7 -> drop7 4096
8 fc8 -> loss 1000

以第1層代碼爲例進行分析:
1. 第1層 = 卷積層(conv1+relu1) + 池化層(pool1) + 歸一化(norm1)

(1). 第1層 - 卷積層(conv1+relu1)
作用:提取局部特徵,使用ReLU作爲CNN的激活函數,並驗證其效果在較深的網絡超過了Sigmoid,成功解決了Sigmoid在網絡較深時的梯度彌散問題。
conv1, relu1 = conv_relu(data, 11, 96, stride=4)
- 數據:數據層輸出data數據
- 卷積核大小: 11
- 輸出節點深度: 96
- 滑窗距離: 4

(2). 第1層 - 池化層(pool1)
作用:提取最大值,避免平均池化的模糊化效果。在AlexNet中提出讓步長比池化核的尺寸小,這樣池化層的輸出之間會有重疊和覆蓋,提升了特徵的豐富性。
pool1 = max_pool(relu1, 3, stride=2)
- 數據: relu1
- 模板核大小: 3
- 滑窗距離: 2

(3). 第1層 - 局部響應歸一化(Local Response Normalize)(norm1)
作用:對局部神經元的活動創建競爭機制,使得其中響應比較大的值變得相對更大,並抑制其他反饋較小的神經元,增強了模型的泛化能力
norm1 = L.LRN(pool1, local_size=5, alpha=1e-4, beta=0.75)
- 數據: pool1
- 取值模板尺寸: 5
- alpha: 0.0001
- beta: 0.75

4. 輸出網絡結構文件(.prototxt)


def make_net():
    with open('train.prototxt', 'w') as f:
        print(caffenet('/path/to/caffe-train-lmdb'), file=f)

    with open('test.prototxt', 'w') as f:
        print(caffenet('/path/to/caffe-val-lmdb', batch_size=50, include_acc=True), file=f)

5. 運行


if __name__ == '__main__':
    make_net()

總結


Caffene.py是入門Caffe較好的源代碼,結合原論文看,同時能加深對網絡結構的理解,補充理論知識。下面根據這個example形式構建自己的網絡結構,其中第一步,也是學習深度學習最重要的一步,編寫自己的數據類型接口層程序。

以上。


附:
1. AlexNet網絡總結
2. 深度學習之圖像分類模型AlexNet解讀


發佈了36 篇原創文章 · 獲贊 32 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章