1. 程式人生 > >採用ReLU作為啟用函式的簡單深度神經網路matlab程式碼設計

採用ReLU作為啟用函式的簡單深度神經網路matlab程式碼設計

本文介紹下如何實現神經元啟用函式為ReLU深度神經網路。ReLU函式的數學公式很簡單ReLU(x)=max(x,0)。若DNN用於資料分類,則可以簡單的認為其主要由兩個部分組成:多隱層網路+分類器。分類器採用softmax

第一步:準備資料

1)將你需要分類的樣本資料以每列的形式保存於矩陣中;->TrainData 2)將每個樣本的類別標記按資料順序存為一行向量,類別為1,2,3,…,n->TrainLabel

將資料儲存入MyData.mat資料檔案中。

採用以下程式實現資料的生成。 

x=1:10

y=1:8:80

rt=x.*x-50*x+40*y-y.^2;

TrainData=[x;y];

for k=1:10

    v_rt_k=rt(k)

    if rt(k)<=0

        TrainLabel(k)=1;

    else

        TrainLabel(k)=2;

    end

end

save('MyData.mat','TrainData','TrainLabel')

:網路配置、引數初始化和轉換

將第一步中準備好的資料載入記憶體中,並採用以下程式執行資料。

1. Main_function without minFunc

clear all

clc

close all

load MyData.mat

inputsize=size(TrainData ,1);%獲取資料的維度

datanum=size(TrainData ,2);%獲取資料的數量

% netsize=[inputsize,50,50,50];

%可以簡單地用一個向量來定義網路的深度,以及每層神經元數目。這表示一個三隱藏層的DNN,神經元數都為50

netsize=[inputsize,4,3];

classnum=2;%類別數目

lastsize=netsize(end)+1;%網路最後一層神經元數數目,再考慮一個偏置。

stack = initializeNet(netsize);%初始化網路引數,以結構體的形式儲存。

v_stack=stack

v_stack_1=stack{1}

v_stack_1_w=stack{1}.w

v_stack_1_b=stack{1}.b

v_stack_2=stack{2}

v_stack_2_w=stack{2}.w

v_stack_2_b=stack{2}.b

%在訓練時,往往需要將引數轉成一列向量,提供給損失函式。stack ->stackThetanetconfig儲存一些結構引數

[stackTheta, netconfig] = stack2params(stack);

v_stackTheta=stackTheta

v_netconfig=netconfig

v_netconfig_layersizes=netconfig.layersizes

v_lastsize=lastsize

SoftmaxTheta = 0.0005 * randn(lastsize * classnum, 1);

v_SoftmaxTheta=SoftmaxTheta

Theta=[ SoftmaxTheta ; stackTheta ];%最終網路需要的引數

% the following part is for the traing epoch.

batchsize=10;

% batchsize=5;

%%每次訓練的小批量樣本數</span>  

batchnum=floor(size(TrainData,2)/batchsize);  

DataNum=size(TrainData,2);  

alpha=1e-2;

%這是學習率,一般隨著網路的懸念都需要不斷的減小  

lambda = 1e-4; % Weight decay parameter

for epoch=1:16000

    v_epoch=epoch

    idx=randperm(DataNum);

    for t=1:batchnum

        subdata=TrainData(:,idx((t-1)*batchsize+1:(t)*batchsize));

        sublabel=TrainLabel(idx((t-1)*batchsize+1:(t)*batchsize));

        [cost,grad]=ReLUDNNCost(Theta,classnum,lastsize,netconfig,lambda,subdata,sublabel);

        Theta=Theta-alpha*grad;

        v_grad=grad

    end      

end

% Note: Theta傳遞進入損失函式內部時,還需要從Theta抽出stackTheta,再轉成stack程式碼如下,都是Andrew Ng的教程裡面的提供的。

2. Main_function with minFunc of UFLDL

clear all

clc

close all

load MyData.mat

inputsize=size(TrainData ,1);%獲取資料的維度

datanum=size(TrainData ,2);%獲取資料的數量

% netsize=[inputsize,50,50,50];

%可以簡單地用一個向量來定義網路的深度,以及每層神經元數目。這表示一個三隱藏層的DNN,神經元數都為50

netsize=[inputsize,4,3];

classnum=2;%類別數目

lastsize=netsize(end)+1;%網路最後一層神經元數數目,再考慮一個偏置。

% v_lastsize=lastsize

stack = initializeNet(netsize);%初始化網路引數,以結構體的形式儲存。

v_stack=stack

v_stack_1=stack{1}

v_stack_1_w=stack{1}.w

v_stack_1_b=stack{1}.b

v_stack_2=stack{2}

v_stack_2_w=stack{2}.w

v_stack_2_b=stack{2}.b

%在訓練時,往往需要將引數轉成一列向量,提供給損失函式。stack ->stackThetanetconfig儲存一些結構引數

[stackTheta, netconfig] = stack2params(stack);

v_stackTheta=stackTheta

v_netconfig=netconfig

v_netconfig_layersizes=netconfig.layersizes

v_lastsize=lastsize

SoftmaxTheta = 0.0005 * randn(lastsize * classnum, 1);

v_SoftmaxTheta=SoftmaxTheta

Theta=[ SoftmaxTheta ; stackTheta ];%最終網路需要的引數

% the following part is for the minFunc in the UFLDL tutorial

options.Method = 'lbfgs';

options.maxIter = 20000;

options.MaxFunEvals=1000000;

options.display = 'on';

lambda = 1e-4;

[OptTheta, cost] = minFunc( @(p)ReLUDNNCost(p,classnum,lastsize,netconfig,lambda, TrainData,TrainLabel),Theta, options);

v_TrainLabel=TrainLabel

save('weights_matrix_minFunc.mat','OptTheta')

% % the following part is for the SGD traing epoch.

% batchsize=10;

% % batchsize=5;

% %%每次訓練的小批量樣本數</span>  

% batchnum=floor(size(TrainData,2)/batchsize);  

% DataNum=size(TrainData,2);  

% alpha=1e-2;

% %這是學習率,一般隨著網路的懸念都需要不斷的減小  

% lambda = 1e-4; % Weight decay parameter

% for epoch=1:16000

%     v_epoch=epoch

%     idx=randperm(DataNum);

%     for t=1:batchnum

%         subdata=TrainData(:,idx((t-1)*batchsize+1:(t)*batchsize));

%         sublabel=TrainLabel(idx((t-1)*batchsize+1:(t)*batchsize));

%         [cost,grad]=ReLUDNNCost(Theta,classnum,lastsize,netconfig,lambda,subdata,sublabel);

%         Theta=Theta-alpha*grad;

%         v_grad=grad

%     end      

% end

% save('weights_matrix_minFunc.mat','Theta')

3. Main_function2 with minFunc of UFLDL

clear all

clc

close all

load MyData.mat

inputsize=size(TrainData ,1);%獲取資料的維度

datanum=size(TrainData ,2);%獲取資料的數量

% netsize=[inputsize,50,50,50];

%可以簡單地用一個向量來定義網路的深度,以及每層神經元數目。這表示一個三隱藏層的DNN,神經元數都為50

netsize=[inputsize,4,3];

classnum=2;%類別數目

lastsize=netsize(end)+1;%網路最後一層神經元數數目,再考慮一個偏置。

% v_lastsize=lastsize

stack = initializeNet(netsize);%初始化網路引數,以結構體的形式儲存。

v_stack=stack

v_stack_1=stack{1}

v_stack_1_w=stack{1}.w

v_stack_1_b=stack{1}.b

v_stack_2=stack{2}

v_stack_2_w=stack{2}.w

v_stack_2_b=stack{2}.b

%在訓練時,往往需要將引數轉成一列向量,提供給損失函式。stack ->stackThetanetconfig儲存一些結構引數

[stackTheta, netconfig] = stack2params(stack);

v_stackTheta=stackTheta

v_netconfig=netconfig

v_netconfig_layersizes=netconfig.layersizes

v_lastsize=lastsize

SoftmaxTheta = 0.0005 * randn(lastsize * classnum, 1);

v_SoftmaxTheta=SoftmaxTheta

Theta=[ SoftmaxTheta ; stackTheta ];%最終網路需要的引數

% the following part is for the traing epoch.

batchsize=10;

% batchsize=5;

%%每次訓練的小批量樣本數</span>  

batchnum=floor(size(TrainData,2)/batchsize);  

DataNum=size(TrainData,2);  

alpha=1e-2;

%這是學習率,一般隨著網路的懸念都需要不斷的減小  

lambda = 1e-4; % Weight decay parameter

for epoch=1:16000

    v_epoch=epoch

    idx=randperm(DataNum);

    for t=1:batchnum

        subdata=TrainData(:,idx((t-1)*batchsize+1:(t)*batchsize));

        sublabel=TrainLabel(idx((t-1)*batchsize+1:(t)*batchsize));

        [cost,grad]=ReLUDNNCost(Theta,classnum,lastsize,netconfig,lambda,subdata,sublabel);

        Theta=Theta-alpha*grad;

        v_grad=grad

    end      

    v_trainLabels=sublabel

end

save('weights_matrix2.mat','Theta')

4. ReLUDNNCost

function [cost,grad] = ReLUDNNCost(theta,numClasses,lasthiddenSize, netconfig,lambda, trainData,trainLabels)

%引數獲取的一些操作

softmaxTheta = reshape(theta(1:lasthiddenSize*numClasses), numClasses, lasthiddenSize);

stack = params2stack(theta(lasthiddenSize*numClasses+1:end), netconfig);

%theta向量中抽取網路權值引數並轉化

stackgrad = cell(size(stack));

PARA=cell(numel(stack),1);%這裡儲存在應用BP演算法求梯度時需要的資料

datanum=size(trainData,2);%傳進來的樣本數

%開始前饋,網路雖然多層,但只是重複而已

data=trainData;

for d = 1:numel(stack)

PARA{d}.a=data;

z2=(stack{d}.w*data)+stack{d}.b*ones(1,datanum);

a2=relu(z2);%RelU函式

data=a2;

PARA{d}.daz=drelu(z2);%RelU函式的導函式

end

a2=[a2;ones(1,datanum)];

%開始求解損失

% v_trainLabels=trainLabels

% v_datanum=datanum

groundTruth = full(sparse(trainLabels, 1:datanum, 1));

% %這是Andrew NG教程原版的語句,但其在應用小批量樣本訓練時會出錯,下一行是另一種實現方式

% v_trainLabels=trainLabels

% v_numClasses=numClasses

% v_element1=repmat(trainLabels,numClasses,1)

% v_element2=(1:1:numClasses)'

% groundTruth=bsxfun(@eq,repmat(trainLabels,numClasses,1),(1:1:numClasses)');

% v_groundTruth=groundTruth

% pause

M = softmaxTheta*a2;

h = exp(M);

h = bsxfun(@rdivide, h, sum(h));

% v_size_groundTruth=size(groundTruth)

% v_log_h=size(log(h))

cost = -1/datanum*sum(sum(groundTruth.*log(h)))+lambda/2*sum(sum(softmaxTheta.^2));

%softmax 損失函式,沒啥好說的

softmaxThetaGrad = -1/datanum*((groundTruth-h)*a2')+lambda*softmaxTheta;

%softmax 目標函式對softmaxTheta 的導數,

predelta=-softmaxTheta'*(groundTruth-h);

%想理解這裡,還有後面的梯度是如何計算出的,建議看那本關於矩陣的工具書《The Matrix Cookbook

predelta=predelta(1:end-1,:);

for d = numel(stack):-1:1

delta=predelta.*PARA{d}.daz;

stackgrad{d}.w=delta*PARA{d}.a'/datanum;%.*PARA{d}.idx

stackgrad{d}.b=sum(delta,2)/datanum;

predelta=stack{d}.w'*delta;

end

grad = [softmaxThetaGrad(:) ; stack2params(stackgrad)];

end

5. relu

function re = relu(x)

re = max(x,0)-1;

end

6. drelu

function dre= drelu(x)

dre=zeros(size(x));

dre(x>0)=1;

dre(x==0)=0.5;%這句可以不要

end

7. initializeNet

function stack = initializeNet(netsize)

layersize=length(netsize(:));

stack = cell(layersize-1,1);

for l=1:layersize-1

    hiddenSize=netsize(l+1);

    visibleSize=netsize(l);

    r =sqrt(6) / sqrt(hiddenSize+visibleSize+1);

    stack{l}.w= rand(hiddenSize, visibleSize) * 2 * r - r; stack{l}.b= zeros(hiddenSize, 1);

end

end

8. params2stack

function stack = params2stack(params, netconfig)

depth = numel(netconfig.layersizes);

stack = cell(depth,1);

prevLayerSize = netconfig.inputsize; % the size of the previous layer

curPos = double(1); % mark current position in parameter vector

for d = 1:depth

% Create layer d

stack{d} = struct;

% Extract weights

wlen = double(netconfig.layersizes{d} * prevLayerSize);

stack{d}.w = reshape(params(curPos:curPos+wlen-1), netconfig.layersizes{d}, prevLayerSize);

curPos = curPos+wlen;

% Extract bias

blen = double(netconfig.layersizes{d});

stack{d}.b = reshape(params(curPos:curPos+blen-1), netconfig.layersizes{d}, 1);

curPos = curPos+blen;

% Set previous layer size

prevLayerSize = netconfig.layersizes{d};

end

end

9. stack2params

function [params, netconfig] = stack2params(stack)

params = [];

for d = 1:numel(stack)

    params = [params ; stack{d}.w(:) ;

        stack{d}.b(:) ];

end

if nargout > 1

    if numel(stack) == 0

        netconfig.inputsize = 0;

        netconfig.layersizes = {};

    else

        netconfig.inputsize = size(stack{1}.w, 2);

        netconfig.layersizes = {};

        for d = 1:numel(stack)

            netconfig.layersizes = [netconfig.layersizes ; size(stack{d}.w,1)];

        end

    end

end

end

採用已訓練的深度網路對輸入資料進行測試

1. Main_test_function

clear all

clc

close all

load MyData.mat

load weights_matrix.mat

inputsize=size(TrainData ,1);%獲取資料的維度

datanum=size(TrainData ,2);%獲取資料的數量

% netsize=[inputsize,50,50,50];

%可以簡單地用一個向量來定義網路的深度,以及每層神經元數目。這表示一個三隱藏層的DNN,神經元數都為50

netsize=[inputsize,4,3];

classnum=2;%類別數目

netconfig2.inputsize=netsize(1)

netconfig2.layersizes{1}=netsize(2)

netconfig2.layersizes{2}=netsize(3)

netconfig2.layersizes=netconfig2.layersizes'

lastsize=netsize(end)+1;%網路最後一層神經元數數目,再考慮一個偏置。

v_result = forward_computation(Theta,classnum,lastsize,netconfig2,TrainData)

v_TrainLabel=TrainLabel

2. forward_computation

function v_result = forward_computation(theta,numClasses,lasthiddenSize, netconfig,trainData,trainLabels)

%引數獲取的一些操作

softmaxTheta = reshape(theta(1:lasthiddenSize*numClasses), numClasses, lasthiddenSize);

stack = params2stack(theta(lasthiddenSize*numClasses+1:end), netconfig);

%theta向量中抽取網路權值引數並轉化

stackgrad = cell(size(stack));

PARA=cell(numel(stack),1);%這裡儲存在應用BP演算法求梯度時需要的資料

datanum=size(trainData,2);%傳進來的樣本數

%開始前饋,網路雖然多層,但只是重複而已

data=trainData;

for d = 1:numel(stack)

PARA{d}.a=data;

z2=(stack{d}.w*data)+stack{d}.b*ones(1,datanum);

a2=relu(z2);%RelU函式

data=a2;

PARA{d}.daz=drelu(z2);%RelU函式的導函式

end

a2=[a2;ones(1,datanum)];

M = softmaxTheta*a2;

h = exp(M);

h = bsxfun(@rdivide, h, sum(h));

v_result=h

end