MATLAB底層代碼實現深度學習LeNet網絡

  代碼下載地址:http://download.csdn.net/download/love_ljq/10189737
  最近在做一件覺得挺有意思的事情,而這件事情的基礎就是要先用Matlab底層代碼實現深度學習。之前自己沒有寫過,所以就找了LeNet這個最簡單的網絡。這裏要着重說明的是,我用Matlab底層代碼實現的是測試部分,並沒有實現參數訓練部分,這裏的網絡模型和網絡參數都是已經訓練好的。
  深度學習的網絡操作,主要來講就那麼幾種,卷積、全連接、激活(ReLU)、Softmax,大的網絡差不多也是由這麼一些基礎部件搭起來的,而LeNet這個小麻雀完全包含了這些五臟六腑,相對於Caffe一句話的實現,用底層代碼實現還是要複雜的多。
  首先我們來看一下LeNet這個網絡的結構。
這裏寫圖片描述
  上面的這個網絡結構圖是pyCaffe通過draw_net.py文件,根據lenet.prototxt進行繪製的,從圖中可以很直觀地看出LeNet的網絡結構。Convolution層,MaxPooling層,Convolution層,MaxPooling層,然後是InnerProductReLUInnerProductSoftmax
  除了網絡模型,我們還需要知道網絡每一層的參數,這些參數也是通過pyCaffe來讀取的並且保存爲.mat文件以供Matlab進行讀取。LeNet的參數都是浮點型的,第一層的卷積層的參數量爲(20*5*5+20)=520個,其中20個是偏置,其第二層卷積層的參數量爲(50*20*5*5+50)=520個,第三層內積層的參數量爲(500*800+500)=40500個,第四層內積層的參數量爲(10*500+10)=5010個,總計爲71080個。
  咱們之間來看一下代碼吧。

% 首先進行參數的讀取,一共是8個文件,每一層需要參數的操作對應一個w和一個b
load('.\parameters\conv1_w.mat');
load('.\parameters\conv1_b.mat');
load('.\parameters\conv2_w.mat');
load('.\parameters\conv2_b.mat');
load('.\parameters\ip1_w.mat');
load('.\parameters\ip1_b.mat');
load('.\parameters\ip2_w.mat');
load('.\parameters\ip2_b.mat');
% 讀取圖像並將圖像像素值除以255以歸一化到(0,1),圖像的尺寸爲28x28,單通道
image = double(imread('1.jpg'))/255; 
% 第一層卷積層操作,這裏的convolution是我自己寫的函數
% 因爲感覺Matlab自帶的函數不好用就自己寫了一個,這個子函數會提供源代碼
% 關於卷積操作的網絡應該有很多資料的
% 輸入爲我們的圖像,大小爲28x28,經過20個5x5卷積核的卷積,輸出爲24x24x20
A = zeros(24,24,20);
for i = 1:20
    A(:,:,i) = convolution(image,conv1_w(i,1,:,:)) + conv1_b(i);
end
% MaxPooling層,就是相鄰四個像素取極大值,輸出爲12x12x20
B = zeros(12,12,20);
for i = 1:20
    for row = 1:12
        for col = 1:12
            B(row,col,i) = max(max(A(2*row-1:2*row,2*col-1:2*col,i)));
        end
    end
end
% 第三層convolution層,輸出爲8x8x50
C = zeros(8,8,50);
for i = 1:50
    for j = 1:20
        C(:,:,i) = C(:,:,i) + convolution(B(:,:,j),conv2_w(i,j,:,:));
    end
    C(:,:,i) = C(:,:,i) + conv2_b(i);
end
% 第四層MaxPooling層
D = zeros(4,4,50);
for i = 1:50
    for row = 1:4
        for col = 1:4
            D(row,col,i) = max(max(C(2*row-1:2*row,2*col-1:2*col,i)));
        end
    end
end
% 首先將4x4x500的圖像展成1x800的圖像與參數進行匹配,再進行矩陣乘法並加上偏置
DRow = zeros(1,800);
for index = 1:50
    DRow(index*16-15:index*16) = [D(1,1:4,index),D(2,1:4,index),D(3,1:4,index),D(4,1:4,index)];
end
E = ip1_w * DRow' + ip1_b';
% ReLU層,選擇正數,拋棄負數部分
F = (E>0).*E;
% 內積點乘
G = ip2_w*F + ip2_b';
% 最後的SoftMax層,這裏的softMax也是我自己寫的函數
[~,result] = max(softMax(G'));
% 結果顯示
disp(['The classification Result is ',num2str(result-1)]);

  我們將softmax之後的結果與python的計算結果進行對比,發現兩者基本相同,但是因爲pythonmatlab在中間結果等精度不一致,導致兩者有約萬分之一的差。
  最後是實際實驗,我們測試了幾張手寫識別圖片,都得到了正確的結果,畢竟LeNet的精度大於99%。

% convolution function source code
% 因爲比較簡單,也沒有去優化,直接用了多重for循環
function result = convolution(image,core)
    [imageSize,~] = size(image);
    coreSize = 5;
    result = zeros(imageSize-(coreSize-1));
    for rowIndex = 1:size(result,1)
        for colIndex = 1:size(result,1)
            for x = 1:5
                for y = 1:5
                    result(rowIndex,colIndex) = result(rowIndex,colIndex) + image(rowIndex + x - 1, colIndex + y - 1)*double(core(1,1,x,y));
                end
            end
        end
    end
end
% softmax function source code
function softMaxResult = softMax(Array)
    [~,cols] = size(Array);
    ArrayCal = zeros(3,cols);
    ArrayCal(1,:) = exp(Array);
    sumOfArray = sum(ArrayCal(1,:));
    ArrayCal(2,:) = ArrayCal(1,:)/sumOfArray;
    softMaxResult = ArrayCal(2,:);
end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章