精华内容
下载资源
问答
  • 卷积神经网络matlab代码,代入数据就可以成功运行!!
  • cnn的matlab运行程序, 深度学习Matlab工具箱代码cnnbp.m,cnnapplygrads.m,cnnff.m等。
  • 卷积神经网络matlab代码下载

    热门讨论 2014-05-19 22:19:45
    卷积神经网络matlab代码,直接可运行
  • CNN卷积神经网络Matlab实现例程,使用了matlabR2019a自带的深度学习工具箱
  • 卷积神经网络Matlab实现,卷积神经网络matlab代码,matlab源码
  • CNN卷积神经网络实现,Matlab仿真,识别手写数字集。
  • 卷积神经网络MATLAB代码,现有的代码大都是基于Python或者R编写的。
  • 卷积神经网络(cnn)的matlab程序,包含了14个m文件。
  • CNN卷积神经网络MATLAB代码,mnist_uint8.mat是数据文件,其他的函数都有相应的解释。
  • 原创深度学习卷积神经网络Matlab工具箱源代码下载-DeepLearnToolbox_CNN_lzbV2.0.zip [原创]深度学习Matlab工具箱源代码下载
  • 卷积神经网络matlab 代码理解

    万次阅读 2016-12-06 14:14:14
    转载地址:http://blog.csdn.net/bingningning/article/details/52388974?locationNum=6&fps=1  网络结构图:  打开路径\tests\test_example_cnn.m ...addpath D:\matlab文档\Dee

    转载地址:http://blog.csdn.net/bingningning/article/details/52388974?locationNum=6&fps=1  

    网络结构图: 
    这里写图片描述

    打开路径\tests\test_example_cnn.m

    function test_example_CNN
    clc,
    clear;
    addpath D:\matlab文档\DeepLearnToolbox\data\ %按照文档所在路径进行加载 
    addpath D:\matlab文档\DeepLearnToolbox\CNN\  
    addpath D:\matlab文档\DeepLearnToolbox\util\  
    load mnist_uint8;  %加载训练、测试数据
    
    train_x = double(reshape(train_x',28,28,60000))/255;   % 训练集变成60000张28*28的图片 28*28*60000,像素点归一化到[0,1]  
    test_x = double(reshape(test_x',28,28,10000))/255;      %  测试集   28*28*10000  
    train_y = double(train_y');   %10*6000   
    test_y = double(test_y');  
    
    %% ex1 Train a 6c-2s-12c-2s Convolutional neural network   
    %will run 1 epoch in about 200 second and get around 11% error.   
    %With 100 epochs you'll get around 1.2% error  
    rand('state',0)  %如果指定状态,产生随机结果就相同
    
    cnn.layers = {        %%% 设置各层feature maps个数及卷积模板大小等属性  
        struct('type', 'i') %input layer  
        struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %卷积层有6张特征图,卷积核大小为5*5  
        struct('type', 's', 'scale', 2) %抽样层,定义2*2的临域相连接  
        struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %同上 
        struct('type', 's', 'scale', 2) %同上  
    };  
    
    opts.alpha = 1;    %迭代下降的速率  
    opts.batchsize = 50;   %每次选择50个样本进行更新
    opts.numepochs = 1;   %迭代次数  
    
    cnn = cnnsetup(cnn, train_x, train_y); %对各层参数进行初始化 包括权重和偏置  
    cnn = cnntrain(cnn, train_x, train_y, opts); %训练的过程,包括bp算法及迭代过程  
    
    [er, bad] = cnntest(cnn, test_x, test_y);  
    %plot mean squared error  
    figure; plot(cnn.rL);  
    assert(er<0.12, 'Too big error');  
    end
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    \CNN\cnnsetup.m

    function net = cnnsetup(net, x, y)   %对各层参数进行初始化 包括权重和偏置  
        assert(~isOctave() || compare_versions(OCTAVE_VERSION, '3.8.0', '>='), ['Octave 3.8.0 or greater is required for CNNs as there is a bug in convolution in previous versions. See http://savannah.gnu.org/bugs/?39314. Your version is ' myOctaveVersion]);
        inputmaps = 1;   %输入图片数量
        mapsize = size(squeeze(x(:, :, 1)));   % 图片的大小 squeeze 要不要都行28 28,squeeze的功能是删除矩阵中的单一维
    
        for l = 1 : numel(net.layers)   %layer层数
            if strcmp(net.layers{l}.type, 's')
                mapsize = mapsize / net.layers{l}.scale;%% sumsampling的featuremap长宽都是上一层卷积层featuremap的不重叠平移scale大小
                %分别为24/2=12;8/2=4
                %%assert:断言函数
                assert(all(floor(mapsize)==mapsize), ['Layer ' num2str(l) ' size must be integer. Actual: ' num2str(mapsize)]);
    
                for j = 1 : inputmaps % 就是上一层有多少张特征图,通过初始化为1然后依层更新得到
                    net.layers{l}.b{j} = 0; 
                    % 将偏置初始化0, 权重weight,这段代码subsampling层将weight设为1/4 而偏置参数设为0,故subsampling阶段无需参数  
                end
            end
            if strcmp(net.layers{l}.type, 'c')
                mapsize = mapsize - net.layers{l}.kernelsize + 1; % 得到当前层feature map的大小,卷积平移,默认步长为1   
                fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;% 隐藏层的大小,是一个(后层特征图数量)*(用来卷积的kernel的大小)  
                for j = 1 : net.layers{l}.outputmaps  %当前层feature maps的个数 
                    fan_in = inputmaps * net.layers{l}.kernelsize ^ 2;  %对于每一个后层特征图,有多少个参数链到前层,包含权重的总数分别为1*25;6*25
                    for i = 1 : inputmaps  %  共享权值,故kernel参数个数为inputmaps*outputmaps个数,每一个大小都是5*5  
                        net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));
                        % 初始化每个feature map对应的kernel参数 -0.5 再乘2归一化到[-1,1]
                        % 最终归一化到[-sqrt(6 / (fan_in + fan_out)),+sqrt(6 / (fan_in + fan_out))] why?? 
                    end
                    net.layers{l}.b{j} = 0; % 初始话feture map对应的偏置参数 初始化为0  
                end
                inputmaps = net.layers{l}.outputmaps;% 修改输入feature maps的个数以便下次使用
            end
        end
        % 'onum' is the number of labels, that's why it is calculated using size(y, 1). If you have 20 labels so the output of the network will be 20 neurons.
        %  onum 是标签数,也就是最后输出层神经元的个数。你要分多少个类,自然就有多少个输出神经元;
        % 'fvnum' is the number of output neurons at the last layer, the layer just before the output layer.
        %  fvnum是最后输出层的前面一层的神经元个数,这一层的上一层是经过pooling后的层,
        %包含有inputmaps个特征map。每个特征map的大小是mapsize。所以,该层的神经元个数是 inputmaps * (每个特征map的大小); 
        % 'ffb' is the biases of the output neurons.
        % ffb 是输出层每个神经元对应的基biases  
        % 'ffW' is the weights between the last layer and the output neurons. Note that the last layer is fully connected to the output layer, that's why the size of the weights is (onum * fvnum)
        % ffW 输出层前一层 与 输出层 连接的权值,这两层之间是全连接的  
        fvnum = prod(mapsize) * inputmaps;% prod函数用于求数组元素的乘积,fvnum=4*4*12=192,是全连接层的输入数量 
        onum = size(y, 1);%最终分类的个数  10类  ,最终输出节点的数量
        % 这里是最后一层神经网络的设定 
        net.ffb = zeros(onum, 1);%softmat回归的偏置参数个数 
        net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum)); %% softmaxt回归的权值参数 为10*192个 全连接
    end
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    \CNN\cnnff.m

    function net = cnntrain(net, x, y, opts)  %%训练的过程,包括bp算法及迭代过程  
    
        m = size(x, 3); %% m为样本照片的数量,size(x)=[28*28*6000] 
        numbatches = m / opts.batchsize;% 循环的次数 共1200次,每次使用50个样本进行
        if rem(numbatches, 1) ~= 0
            error('numbatches not integer');
        end
        net.rL = [];%rL是最小均方误差的平滑序列,绘图要用
        for i = 1 : opts.numepochs    %迭代次数  
            disp(['epoch ' num2str(i) '/' num2str(opts.numepochs)]);
            tic;
            kk = randperm(m); %% 随机产生m以内的不重复的m个数  
            for l = 1 : numbatches  %% 循环1200次,每次选取50个不重复样本进行更新 
                batch_x = x(:,:, kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));%50个样本的训练数据 
                batch_y = y(:,    kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));%50个样本所对应的标签
    
                net = cnnff(net, batch_x);%计算前向传导过程 
                net = cnnbp(net, batch_y);%计算误差并反向传导,计算梯度
                net = cnnapplygrads(net, opts); %% 应用梯度迭代更新模型
                %net.L为模型的costFunction,即最小均方误差mse
                %rL是最小均方误差的平滑序列
                if isempty(net.rL)%为空
                    net.rL(1) = net.L; %loss function的值
                end
                net.rL(end + 1) = 0.99 * net.rL(end) + 0.01 * net.L; 
                %相当于对每一个batch的误差进行累积(加权平均)
            end
            toc;
        end
    end
    
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    \CNN\cnnff.m 
    back propagation 计算gradient

    function net = cnnff(net, x)%完成训练的前向过程,  
        n = numel(net.layers);  
        net.layers{1}.a{1} = x; % a是输入map,是一个【28,28,50】的矩阵
        inputmaps = 1;
    
        for l = 2 : n   %针对每一个卷积层
            if strcmp(net.layers{l}.type, 'c')
                for j = 1 : net.layers{l}.outputmaps   % 针对该层的每一个feture map  
                    %  create temp output map
                    z = zeros(size(net.layers{l - 1}.a{1}) - [net.layers{l}.kernelsize - 1 net.layers{l}.kernelsize - 1 0]);
                    %z=zeros([28,28,50]-[5-1,5-1,0])=([24,24,50])
                    % 该层feture map的大小,最后一位是样本图片个数 初始化为0  
                    for i = 1 : inputmaps  %针对每一个输入feature map 
                        z = z + convn(net.layers{l - 1}.a{i}, net.layers{l}.k{i}{j}, 'valid');
                        %做卷积操作  k{i}{j} 是5*5的double类型,其中a{i}是输入图片的feature map 大小为28*28*50 50为图像数量  
                        %卷积操作这里的k已经旋转了180度,z保存的就是该层中所有的特征
                    end 
                    % 通过非线性加偏值
                    net.layers{l}.a{j} = sigm(z + net.layers{l}.b{j});%%获取sigmoid function的值 
                end
                inputmaps = net.layers{l}.outputmaps; %% 设置新的输入feature maps的个数      
    
            elseif strcmp(net.layers{l}.type, 's')% 下采样采用的方法是,2*2相加乘以权值1/4,  没有取偏置和取sigmoid  
                %  downsample
                for j = 1 : inputmaps
                    %这里做的是mean-pooling
                    z = convn(net.layers{l - 1}.a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2), 'valid');  
                     %先卷积后各行各列取结果
                    net.layers{l}.a{j} = z(1 : net.layers{l}.scale : end, 1 : net.layers{l}.scale : end, :);
                     %得到的结果是上一层卷积层行列的一半  a=z  
                end
            end
        end
        %  收纳到一个vector里面,方便后面用~~  
        %  concatenate all end layer feature maps into vector
        net.fv = []; %%用来保存最后一个隐藏层所对应的特征 将feature maps变成全连接的形式 
        %%net.fv: 最后一层隐藏层的特征矩阵,采用的是全连接方式
        for j = 1 : numel(net.layers{n}.a) % fv每次拼合入subFeaturemap2[j],[包含50个样本]
            sa = size(net.layers{n}.a{j}); % 每一个featureMap的大小为a=sa=4*4*50,得到sfm2的一个输入图的大小
            %rashape(A,m,n)
            %把矩阵A改变形状,变为m行n列(元素个数不变,原矩阵按列排成一队,再按行排成若干队)
            %把net.layers{numLayers}.a[j](一个sfm2)排列成为[4*4行,1列]的一个向量
            %把所有的sfm2拼合成为一个列向量fv
            net.fv = [net.fv; reshape(net.layers{n}.a{j}, sa(1) * sa(2), sa(3))];
            % 最后得到192*50的矩阵,每一列对应一个样本图像的特征 
        end                        
        %feedforward into output perceptrons
        %net.ffW是【10,192】的权重矩阵
        %net.ffW*net.fv是一个【10,50】的矩阵
        %repat(net.ffb,1,size(net.fv,2))把bias复制成50份排开
        net.o = sigm(net.ffW * net.fv + repmat(net.ffb, 1, size(net.fv, 2))); 
        %结果为10*50的矩阵,每一列表示一个样本图像的标签结果 取了sigmoid function表明是k个二分类器,各类之间不互斥,当然也可以换成softmax回归  
    end
    
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    \CNN\cnnbp.m

    function net = cnnbp(net, y)%计算并传递神经网络的error,并计算梯度(权重的修改量) 
        n = numel(net.layers); %layers层个数 
        %   error
        net.e = net.o - y; % 10*50  每一列表示一个样本图像
        %  loss function,均方误差
        net.L = 1/2* sum(net.e(:) .^ 2) / size(net.e, 2);%没有加入参数构成贝叶斯学派的观点
    
        %% backprop deltas
        %计算尾部单层感知机的误差
        net.od = net.e .* (net.o .* (1 - net.o));   %  输出层的误差 sigmoid误差
        %fvd,feature vector delta,特征向量误差,上一层收集下层误差,size=[192*50]
        net.fvd = (net.ffW' * net.od);            
        %如果MLP的前一层(特征抽取最后一层)是卷基层,卷基层的输出经过sigmoid函数处理,error需要求导
        %在数字识别这个网络中不需要用到
        if strcmp(net.layers{n}.type, 'c')          %  only conv layers has sigm function
            %对于卷基层,它的特征向量误差 再求导
            net.fvd = net.fvd .* (net.fv .* (1 - net.fv)); %% 如果最后一个隐藏层是卷积层,直接用该公式就能得到误差
        end
    
        %  reshape feature vector deltas into output map style
        %把单层感知机的输入层featureVector 的误差矩阵,恢复为subFeatureMap2的4*4二位矩阵形式
        sa = size(net.layers{n}.a{1}); %size(a{1})=[4*4*50],一共有a{1}~a{12}}
        fvnum = sa(1) * sa(2);%fvnum 一个图所含有的特征向量数量,4*4
        for j = 1 : numel(net.layers{n}.a)   %subFeatureMap的数量,1:12
            %net最后一层的delta,由特征向量delta,依次取一个featureMap大小,然后组合成为一个featureMap的形状
            %在fvd里面保存的是所有样本的特征向量(在cnnff.m函数中用特征map拉成的),这里需要重新变换回来特征map的形式
            net.layers{n}.d{j} = reshape(net.fvd(((j - 1) * fvnum + 1) : j * fvnum, :), sa(1), sa(2), sa(3));
            %size(net.layers{numLayers}.d{j})=【4*4*50】
            %size(net.fvd)=[192*50]
        end
    
        for l = (n - 1) : -1 : 1   %实际是到2终止了,1是输入层,没有误差要求
            %l层是卷积层,误差从下层(降采样层传来),采用从后往前均摊的方式传播误差,上层误差内摊2倍,再除以4
            if strcmp(net.layers{l}.type, 'c')  %卷积层的计算方式
                for j = 1 : numel(net.layers{l}.a)   %第n-1层具有的feature maps的个数,进行遍历 每个d{j}是8*8*50的形式, 由于下一层为下采样层,故后一层d{j}扩展为8*8的(每个点复制成2*2的),按照bp求误差公式就可以得出,这里权重就为1/4,
                    %net.layers{l}.a{j}.*(1-net.layers{l}.a{j})为sigmoid的倒数
                    %(expand(net.layers{l+1}.d{j},[net.layers{j+1}.scale net.layers{l+1}.scale 1]))
                    %expand多项式展开相乘
                    %net.layers{l+1}.scale^2
                    net.layers{l}.d{j} = net.layers{l}.a{j} .* (1 - net.layers{l}.a{j}) .* (expand(net.layers{l + 1}.d{j}, [net.layers{l + 1}.scale net.layers{l + 1}.scale 1]) / net.layers{l + 1}.scale ^ 2);%克罗内克积进行扩充,求采样曾的卷基层的残差,d表示残差,a表示输出值
                end
                %l层是降采样层,误差从下层(卷积层传来),采用卷积的方式得到
            elseif strcmp(net.layers{l}.type, 's') 
                for i = 1 : numel(net.layers{l}.a)  %l层输出层的数量
                    z = zeros(size(net.layers{l}.a{1}));  %z得到一个feature map的大小的零矩阵
                    for j = 1 : numel(net.layers{l + 1}.a) %从l+1层收集错误
                        %net.layers{l+1}.d{j}下一层(卷积层)的灵敏度
                        %net.layers{l+1}.k{i}{j},下一层(卷积层)的卷积核
                         z = z + convn(net.layers{l + 1}.d{j}, rot180(net.layers{l + 1}.k{i}{j}), 'full');
                    end  
                    net.layers{l}.d{i} = z;  %% 因为是下采样层,所以a=z,就f(z)=z,导数就等于1,所以误差就是所连接结点权值与后一层误差和  
                end
            end
        end
    
        %%  calc gradients    
        %计算特征抽取层(卷积+降采样)的梯度
        for l = 2 : n
            if strcmp(net.layers{l}.type, 'c')%卷积层
                for j = 1 : numel(net.layers{l}.a)%l层的featureMap的数量
                    for i = 1 : numel(net.layers{l - 1}.a)
                        %卷积核的修改量=输入图像*输出图像的delta
                        net.layers{l}.dk{i}{j} = convn(flipall(net.layers{l - 1}.a{i}), net.layers{l}.d{j}, 'valid') / size(net.layers{l}.d{j}, 3);% 可以看论文中的推导!与论文中先将k rot180,然后再rot整体效果是一样的。 
                    end
                    %net.layers{l}.d{j}(:)是一个24*24*50的矩阵,db仅除以50
                    net.layers{l}.db{j} = sum(net.layers{l}.d{j}(:)) / size(net.layers{l}.d{j}, 3);  %% 对偏置参数b的导数 
                end
            end
        end
        %计算尾部单层感知机的梯度
        %sizeof(net.od)=[10,50]
        %修改量,求和除以50(batch大小)
        net.dffW = net.od * (net.fv)' / size(net.od, 2);  %softmax回归中参数所对应的导数  
        net.dffb = mean(net.od, 2);%% 第二维取均值  
    
        function X = rot180(X)
            X = flipdim(flipdim(X, 1), 2);% flipdim(X, 1) 行互换  flipdim(X, 2) 列互换  
        end
    end
    
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    在这里插入一张图片便于大家理解: 
    这里写图片描述 
    \CNN\cnnapplygrads.m 
    该函数完成权重修改,更新模型的功能 
    1更新特征抽取层的权重 weight+bias 
    2 更新末尾单层感知机的权重 weight+bias

    function net = cnnapplygrads(net, opts)%% 把计算出来的梯度加到原始模型上去  
        %特征抽取层(卷积降采样)的权重更新
        for l = 2 : numel(net.layers)%从第二层开始
            if strcmp(net.layers{l}.type, 'c')%对于每个卷积层
                for j = 1 : numel(net.layers{l}.a)%美剧该层的每个输出
                    for ii = 1 : numel(net.layers{l - 1}.a)
                        net.layers{l}.k{ii}{j} = net.layers{l}.k{ii}{j} - opts.alpha * net.layers{l}.dk{ii}{j};
                        % 梯度下降求更新后的参数 
                    end
                    %修改bias
                    net.layers{l}.b{j} = net.layers{l}.b{j} - opts.alpha * net.layers{l}.db{j};
                end
            end
        end
        %单层感知机的权重更新
        net.ffW = net.ffW - opts.alpha * net.dffW;%更新权重
        net.ffb = net.ffb - opts.alpha * net.dffb;%更新偏置
    end
    
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    \CNN\cnntest.m 
    验证测试样本的准确率

    function [er, bad] = cnntest(net, x, y)%测试当前模型的准确率
        %  feedforward
        net = cnnff(net, x);
        [~, h] = max(net.o);
        [~, a] = max(y);
        bad = find(h ~= a);%计算预测错误的样本数量 
        er = numel(bad) / size(y, 2);%计算错误率
    end
    
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    0

    展开全文
  • 卷积神经网络matlab版源码,实现对手写体图片的数字识别。实验所需数据可到https://download.csdn.net/download/u013479571/10664562下载
  • CNN_python_卷积神经网络matlab代码_CNN
  • CNN_python_卷积神经网络matlab代码_CNN_源码.zip
  • CNN卷积神经网络MATLAB程序,及注解
  • RNN-LSTM 卷积神经网络 Matlab 实现,简单的数据拟合。 RNN-LSTM 卷积神经网络 Matlab 实现。...RNN-LSTM卷积神经网络Matlab实现 RNN卷积神经网络,LSTM,使用matlab实现,简单的数据拟合 RNN Matlab
  • 上传一张车牌照片,可以是远距离拍摄的,代码会先进行车牌定位,然后切割出车牌区域,再经过灰度化,二值化等导入训练好的神经网络,得到车牌;另外神经网络可以调节层数,学习速率,训练次数等参数来训练调整新的...
  • 代码是基于Matlab卷积神经网络代码案例,本代码本人使用Matlab2014b可以正常运行。欢迎大家留言评论,互相学习研讨。
  • RNN-LSTM卷积神经网络Matlab实现

    千次下载 2018-12-10 12:53:18
    RNN卷积神经网络,LSTM,使用matlab实现,简单的数据拟合
  • 不会脉冲神经网络没关系,这个matlab程序将卷积神经网络转换为脉冲神经网络
  • MATLAB实现卷积神经网络,并对图像进行特征提取 文件列表: CNN CNN\cnnapplygrads.m CNN\cnnbp.m CNN\cnnff.m CNN\cnnnumgradcheck.m CNN\cnnsetup.m CNN\cnntest.m CNN\cnntrain.m CNN\expand.m CNN\...
  • 卷积神经网络CNN代码解析,对了解卷积神经网络非常有帮助,欢迎研究学习下载
  • 卷积神经网络(CNN)反向传播算法公式详细推导 网上有很多关于CNN的教程讲解,在这里我们抛开长篇大论,只针对代码来谈。本文用的是matlab编写的deeplearning toolbox,包括NN、CNN、DBN、SAE、CAE。在这里我们感谢...
    1. 经典反向传播算法公式详细推导 
    2. 卷积神经网络(CNN)反向传播算法公式详细推导

    网上有很多关于CNN的教程讲解,在这里我们抛开长篇大论,只针对代码来谈。本文用的是matlab编写的deeplearning toolbox,包括NN、CNN、DBN、SAE、CAE。在这里我们感谢作者编写了这样一个简单易懂,适用于新手学习的代码。由于本文直接针对代码,这就要求读者有一定的CNN基础,可以参考Lecun的Gradient-Based Learning Applied to Document Recognitiontornadomeet的博文 
    首先把Toolbox下载下来,解压缩到某位置。然后打开Matlab,把文件夹内的util和data利用Set Path添加至路径中。接着打开tests文件夹的test_example_CNN.m。最后在文件夹CNN中运行该代码。

    下面是test_example_CNN.m中的代码及注释,比较简单。

    load mnist_uint8;  %读取数据
    
    % 把图像的灰度值变成0~1,因为本代码采用的是sigmoid激活函数
    train_x = double(reshape(train_x',28,28,60000))/255;
    test_x = double(reshape(test_x',28,28,10000))/255;
    train_y = double(train_y');
    test_y = double(test_y');
    
    %% 卷积网络的结构为 6c-2s-12c-2s 
    % 1 epoch 会运行大约200s, 错误率大约为11%。而 100 epochs 的错误率大约为1.2%。
    
    rand('state',0) %指定状态使每次运行产生的随机结果相同
    
    cnn.layers = {
        struct('type', 'i') % 输入层
        struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) % 卷积层
        struct('type', 's', 'scale', 2) % pooling层
        struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) % 卷积层
        struct('type', 's', 'scale', 2) % pooling层
    };
    
    
    opts.alpha = 1;  % 梯度下降的步长
    opts.batchsize = 50; % 每次批处理50张图
    opts.numepochs = 1; % 所有图片循环处理一次
    
    cnn = cnnsetup(cnn, train_x, train_y); % 初始化CNN
    cnn = cnntrain(cnn, train_x, train_y, opts); % 训练CNN
    
    [er, bad] = cnntest(cnn, test_x, test_y); % 测试CNN
    
    %plot mean squared error
    figure; plot(cnn.rL);
    assert(er<0.12, 'Too big error');

    下面是cnnsetup.m中的代码及注释。

    function net = cnnsetup(net, x, y)
        assert(~isOctave() || compare_versions(OCTAVE_VERSION, '3.8.0', '>='), ['Octave 3.8.0 or greater is required for CNNs as there is a bug in convolution in previous versions. See http://savannah.gnu.org/bugs/?39314. Your version is ' myOctaveVersion]);  %判断版本
        inputmaps = 1;  % 由于网络的输入为1张特征图,因此inputmaps为1
        mapsize = size(squeeze(x(:, :, 1)));  %squeeze():除去x中为1的维度,即得到28*28
    
        for l = 1 : numel(net.layers)   % 网络层数
            if strcmp(net.layers{l}.type, 's') % 如果是pooling层
                mapsize = mapsize / net.layers{l}.scale; % pooling之后图的大小            
                assert(all(floor(mapsize)==mapsize), ['Layer ' num2str(l) ' size must be integer. Actual: ' num2str(mapsize)]);
                for j = 1 : inputmaps
                    net.layers{l}.b{j} = 0; % 偏置项
                end
            end
            if strcmp(net.layers{l}.type, 'c') % 如果是卷积层
                mapsize = mapsize - net.layers{l}.kernelsize + 1; % 确定卷积之后图像大小
                fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2; % 上一层连到该层的权值参数总个数
                for j = 1 : net.layers{l}.outputmaps  % 第l层特征图的数量
                    fan_in = inputmaps * net.layers{l}.kernelsize ^ 2; % 上一层连到该层的第j个特征图的权值参数
                    for i = 1 : inputmaps  % 上一层特征图的数量
                        net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));   % 初始化权值,见论文Understanding the difficulty of training deep feedforward neural networks
                    end
                    net.layers{l}.b{j} = 0; % 偏置项
                end
                inputmaps = net.layers{l}.outputmaps;  % 用该层的outputmaps更新inputmaps的值并为下一层所用
            end
        end
        % 'onum' is the number of labels, that's why it is calculated using size(y, 1). If you have 20 labels so the output of the network will be 20 neurons.
        % 'fvnum' is the number of output neurons at the last layer, the layer just before the output layer.
        % 'ffb' is the biases of the output neurons.
        % 'ffW' is the weights between the last layer and the output neurons. Note that the last layer is fully connected to the output layer, that's why the size of the weights is (onum * fvnum)
        fvnum = prod(mapsize) * inputmaps; % 最终输出层前一层的结点数目
        onum = size(y, 1);  % 类别数目
    
        % 最后一层全连接网络的参数
        net.ffb = zeros(onum, 1); 
        net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));
    end
    

    下面是cnntrain.m中的代码及注释。

    function net = cnntrain(net, x, y, opts)
        m = size(x, 3);
        numbatches = m / opts.batchsize; 
        if rem(numbatches, 1) ~= 0
            error('numbatches not integer');
        end
        net.rL = [];
        for i = 1 : opts.numepochs
            disp(['epoch ' num2str(i) '/' num2str(opts.numepochs)]);
            tic; %tic和toc配套使用来求运行时间 
            kk = randperm(m);
            for l = 1 : numbatches
                batch_x = x(:, :, kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));
                batch_y = y(:,    kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));
    
                net = cnnff(net, batch_x);   % 前向传播
                net = cnnbp(net, batch_y);   % BP反向传播
                net = cnnapplygrads(net, opts);
                if isempty(net.rL)
                    net.rL(1) = net.L;
                end
                net.rL(end + 1) = 0.99 * net.rL(end) + 0.01 * net.L;
            end
            toc;
        end
    
    end

    下面是cnnff.m中的代码及注释。

    function net = cnnff(net, x)
        n = numel(net.layers);
        net.layers{1}.a{1} = x;
        inputmaps = 1;
    
        for l = 2 : n   % 除输入层以外的每一层
            if strcmp(net.layers{l}.type, 'c') % 卷积层
                %  !!below can probably be handled by insane matrix operations
                for j = 1 : net.layers{l}.outputmaps   % 该层的每一个特征图
                    % 该层的输出:上一层图片大小-kernel+1
                    z = zeros(size(net.layers{l - 1}.a{1}) - [net.layers{l}.kernelsize - 1 net.layers{l}.kernelsize - 1 0]);
                    for i = 1 : inputmaps   % 对于每一个输入特征图(本例中为全连接)
                        % 每个特征图的卷积都相加,convn()为matlab自带卷积函数
                        z = z + convn(net.layers{l - 1}.a{i}, net.layers{l}.k{i}{j}, 'valid');
                    end
                    % 加入偏置项,并通过sigmoid函数(现今一般采用RELU)
                    net.layers{l}.a{j} = sigm(z + net.layers{l}.b{j});
                end
                % 用该层的outputmaps更新inputmaps的值并为下一层所用
                inputmaps = net.layers{l}.outputmaps;
            elseif strcmp(net.layers{l}.type, 's')
                % mean-pooling
                for j = 1 : inputmaps
                    z = convn(net.layers{l - 1}.a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2), 'valid');   %  !! replace with variable
                    % 取出有效的mean-pooling矩阵,即每隔net.layers{l}.scale提取一个值
                    net.layers{l}.a{j} = z(1 : net.layers{l}.scale : end, 1 : net.layers{l}.scale : end, :);
                end
            end
        end
    
        % 把最后一层展开变成一行向量方便操作
        net.fv = [];
        for j = 1 : numel(net.layers{n}.a)
            sa = size(net.layers{n}.a{j});
            net.fv = [net.fv; reshape(net.layers{n}.a{j}, sa(1) * sa(2), sa(3))];
        end
        % 加上权值和偏置项并通入sigmoid(多类别神经网络的输出一般采用softmax形式,损失函数使用cross entropy )
        net.o = sigm(net.ffW * net.fv + repmat(net.ffb, 1, size(net.fv, 2)));
    
    end
    

    下面是cnnbp.m中的代码及注释,比较复杂。首先要有普通BP的基础,可以参考CeleryChen的博客,而CNN的反向传播略有不同,可以参考tornadomeet的博客

    function net = cnnbp(net, y)
        n = numel(net.layers);
        net.e = net.o - y; % 误差
        % loss函数,这里采用的方法是MSE(多类别神经网络的输出一般采用softmax形式,损失函数使用cross entropy)
        net.L = 1/2* sum(net.e(:) .^ 2) / size(net.e, 2);
    
        %%  backprop deltas
        net.od = net.e .* (net.o .* (1 - net.o));   %  输出层delta,包括sigmoid求导(delta为loss函数对该层未经激活函数结点的导数)
        net.fvd = (net.ffW' * net.od);              %  隐藏层(倒数第二层)delta
        if strcmp(net.layers{n}.type, 'c')         % 只有卷积层才可以通过sigmoid函数,本CNN结构最后一个隐藏层为pooling
            net.fvd = net.fvd .* (net.fv .* (1 - net.fv));
        end
    
        % 把最后一隐藏层的delta向量变成形如a的向量
        sa = size(net.layers{n}.a{1});
        fvnum = sa(1) * sa(2);
        for j = 1 : numel(net.layers{n}.a)
            net.layers{n}.d{j} = reshape(net.fvd(((j - 1) * fvnum + 1) : j * fvnum, :), sa(1), sa(2), sa(3));
        end
    
        % 逆向传播,计算各层的delta
        for l = (n - 1) : -1 : 1
            if strcmp(net.layers{l}.type, 'c') % 卷积层且下一层为pooling层
                for j = 1 : numel(net.layers{l}.a) % 对该层每一个特征图操作(考虑sigmoid函数,upsample)
                    net.layers{l}.d{j} = net.layers{l}.a{j} .* (1 - net.layers{l}.a{j}) .* (expand(net.layers{l + 1}.d{j}, [net.layers{l + 1}.scale net.layers{l + 1}.scale 1]) / net.layers{l + 1}.scale ^ 2);
                end
            elseif strcmp(net.layers{l}.type, 's') % pooling层且下一层为卷积层
                for i = 1 : numel(net.layers{l}.a)
                    z = zeros(size(net.layers{l}.a{1}));
                    for j = 1 : numel(net.layers{l + 1}.a) % 第l+1层所有特征核的贡献之和
                        X =  net.layers{l + 1}.k{i}{j};
                        z = z + convn(net.layers{l + 1}.d{j}, flipdim(flipdim(X, 1), 2), 'full');
                        %z = z + convn(net.layers{l + 1}.d{j}, rot180(net.layers{l + 1}.k{i}{j}), 'full');
                    end
                    net.layers{l}.d{i} = z;
                end
            end
        end
    
        %% 通过delta计算梯度
        for l = 2 : n
            if strcmp(net.layers{l}.type, 'c')  % 只有卷积层计算梯度,pooling层的参数固定不变
                for j = 1 : numel(net.layers{l}.a)
                    for i = 1 : numel(net.layers{l - 1}.a)
                        net.layers{l}.dk{i}{j} = convn(flipall(net.layers{l - 1}.a{i}), net.layers{l}.d{j}, 'valid') / size(net.layers{l}.d{j}, 3);  % 旋转180°,卷积,再旋转180°
                    end
                    net.layers{l}.db{j} = sum(net.layers{l}.d{j}(:)) / size(net.layers{l}.d{j}, 3); % 所有delta相加,除以每一次批处理的个数
                end
            end
        end
        net.dffW = net.od * (net.fv') / size(net.od, 2); %除以每次批处理个数
        net.dffb = mean(net.od, 2);
    
        function X = rot180(X)
            X = flipdim(flipdim(X, 1), 2);
        end
    end

    下面是cnnapplygrads.m中的代码,比较简单,在这里就不进行注释了。

    function net = cnnapplygrads(net, opts) 
    
        for l = 2 : numel(net.layers) 
    
            if strcmp(net.layers{l}.type, ‘c’) 
    
                for j = 1 : numel(net.layers{l}.a) 
    
                    for ii = 1 : numel(net.layers{l - 1}.a) 
    
                        net.layers{l}.k{ii}{j} = net.layers{l}.k{ii}{j} - opts.alpha * net.layers{l}.dk{ii}{j}; 
    
                    end 
    
                    net.layers{l}.b{j} = net.layers{l}.b{j} - opts.alpha * net.layers{l}.db{j}; 
    
                end 
    
            end 
    
        end

    转载自:http://blog.csdn.net/walegahaha/article/details/51603040

    展开全文
  • 卷积神经网络CNN原理——结合实例matlab实现

    万次阅读 多人点赞 2016-10-22 21:32:00
    卷积神经网络CNN是深度学习的一个重要组成部分,由于其优异的学习性能(尤其是对图片的识别)。近年来研究异常火爆,出现了很多模型LeNet、Alex net、ZF net等等。由于大多高校在校生使用matlab比较多,而网上的教程...

    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936
    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936
    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936

    卷积神经网络CNN是深度学习的一个重要组成部分,由于其优异的学习性能(尤其是对图片的识别)。近年来研究异常火爆,出现了很多模型LeNet、Alex net、ZF net等等。由于大多高校在校生使用matlab比较多,而网上的教程代码基本都基于caffe框架或者python,对于新入门的同学来说甚是煎熬,所以本文采用matlab结合MNIst手写数据库完成对手写数字的识别。本人水平有限,如有纰漏,还望各路大神,帮忙指正。
    一、卷积网络原理

    1、动机

    卷积神经网络(CNN)是多层感知机(MLP)的一个变种模型,它是从生物学概念中演化而来的。从Hubel和Wiesel早期对猫的视觉皮层的研究工作,我们知道在视觉皮层存在一种细胞的复杂分布,,这些细胞对于外界的输入局部是很敏感的,它们被称为“感受野”(细胞),它们以某种方法来覆盖整个视觉域。这些细胞就像一些滤波器一样,它们对输入的图像是局部敏感的,因此能够更好地挖掘出自然图像中的目标的空间关系信息。

    此外,视觉皮层存在两类相关的细胞,S细胞(Simple Cell)和C(Complex Cell)细胞。S细胞在自身的感受野内最大限度地对图像中类似边缘模式的刺激做出响应,而C细胞具有更大的感受野,它可以对图像中产生刺激的模式的空间位置进行精准地定位。

    视觉皮层作为目前已知的最为强大的视觉系统,广受关注。学术领域出现了很多基于它的神经启发式模型。比如:NeoCognitron [Fukushima], HMAX [Serre07] 以及本教程要讨论的重点 LeNet-5 [LeCun98]。

    2、稀疏连接

    CNNs通过加强神经网络中相邻层之间节点的局部连接模式(Local Connectivity Pattern)来挖掘自然图像(中的兴趣目标)的空间局部关联信息。第m层隐层的节点与第m-1层的节点的局部子集,并具有空间连续视觉感受野的节点(就是m-1层节点中的一部分,这部分节点在m-1层都是相邻的)相连。可以用下面的图来表示这种连接。

    这里写图片描述

    假设,m-1层为视网膜输入层(接受自然图像)。根据上图的描述,在m-1层上面的m层的神经元节点都具有宽度为3的感受野,m层每一个节点连接下面的视网膜层的3个相邻的节点。m+1层的节点与它下面一层的节点有着相似的连接属性,所以m+1层的节点仍与m层中3个相邻的节点相连,但是对于输入层(视网膜层)连接数就变多了,在本图中是5。这种结构把训练好的滤波器(corresponding to the input producing the strongest response)构建成了一种空间局部模式(因为每个上层节点都只对感受野中的,连接的局部的下层节点有响应)。根据上面图,多层堆积形成了滤波器(不再是线性的了),它也变得更具有全局性了(如包含了一大片的像素空间)。比如,在上图中,第m+1层能够对宽度为5的非线性特征进行编码(就像素空间而言)。

    3、权值共享

    在CNNs中,每一个稀疏滤波器hi在整个感受野中是重复叠加的,这些重复的节点形式了一种特征图(feature map),这个特种图可以共享相同的参数,比如相同的权值矩阵和偏置向量。
    这里写图片描述

    在上图中,属于同一个特征图的三个隐层节点,因为需要共享相同颜色的权重, 他们的被限制成相同的。在这里, 梯度下降算法仍然可以用来训练这些共享的参数,只需要在原算法的基础上稍作改动即可。共享权重的梯度可以对共享参数的梯度进行简单的求和得到。

    二、网络的分析
    上面这些内容,基本就是CNN的精髓所在了,下面结合LeNet做具体的分析。
    结构图:
    这里写图片描述
    这里写图片描述
    LeNet算上输入输出一共为八层,下面逐层分析。
    第一层:数据输入层
    CNN的强项在于图片的处理,lenet的输入为3232的矩阵图片。这里需要注意的点:
    1、数据的归一化,这里的归一化是广义的,不一定要归到0-1,但要是相同的一个区间范围,一般我们的灰度图为0-255。
    2、数据的去均值,如果样本有非零的均值,而且与测试部分的非零均值不一致,可能就会导致识别率的下降。当然这不一定发生,我们这么做是为了增加系统的鲁棒性。
    这里写图片描述
    第二层:卷积层c1
    卷积层是卷积神经网络的核心,通过不同的卷积核,来获取图片的特征。卷积核相当于一个滤波器,不同的滤波器提取不同特征。打个比方,对于手写数字识别,某一个卷积核提取‘一’,另一个卷积核提取‘|’,所以这个数字很有可能就判定为‘7’。当然实际要比这复杂度得多,但原理大概就是这个样子。
    第三层:pooling层
    基本每个卷积层后边都会接一个pooling层,目的是为了降维。一般都将原来的卷积层的输出矩阵大小变为原来的一半,方便后边的运算。另外,pooling层增加了系统的鲁棒性,把原来的准确描述变为了概略描述(原来矩阵大小为28
    28,现在为14*14,必然有一部分信息丢失,一定程度上防止了过拟合)。
    第四层:卷积层
    与之前类似,在之前的特征中进一步提取特征,对原样本进行更深层次的表达。注意:这里不是全连接。这里不是全连接。这里不是全连接。X代表连接,空白代表不连。
    这里写图片描述
    第五层:pooling层
    与之前类似。
    第六层:卷积层(全连接)
    这里有120个卷积核,这里是全连接的。将矩阵卷积成一个数,方便后边网络进行判定。
    第七层:全连接层
    和MLP中的隐层一样,获得高维空间数据的表达。
    第八层:输出层
    这里一般采用RBF网络,每个RBF的中心为每个类别的标志,网络输出越大,代表越不相似,输出的最小值即为网络的判别结果。
    三、卷积网络的BP训练
    前面的都很好理解,卷积神经网络的难度在于BP过程。网上zouxy09的博文写的很好,可以看一下,自己搞明白。传送门:CNN的BP推导
    四、代码部分
    关于MNIST数据集,网上有很多现成的代码对其进行提取,但提取出来的都是乱序的很不利于使用。这里有提取好的分类后的,详情传送门
    简单起见,我们的代码选用一层卷积层。
    CNN_simple_mian.m

    %%%  matlab实现LeNet-5
    %%%  作者:xd.wp
    %%%  时间:2016.10.22  14:29
    %% 程序说明
    %          1、池化(pooling)采用平均2*2
    %          2、网络结点数说明:
    %                           输入层:28*28
    %                           第一层:24*24(卷积)*20
    %                           tanh
    %                           第二层:12*12(pooling)*20
    %                           第三层:100(全连接)
    %                           第四层:10(softmax)
    %          3、网络训练部分采用800个样本,检验部分采用100个样本
    clear all;clc;
    %% 网络初始化
    layer_c1_num=20;
    layer_s1_num=20;
    layer_f1_num=100;
    layer_output_num=10;
    %权值调整步进
    yita=0.01;
    %bias初始化
    bias_c1=(2*rand(1,20)-ones(1,20))/sqrt(20);
    bias_f1=(2*rand(1,100)-ones(1,100))/sqrt(20);
    %卷积核初始化
    [kernel_c1,kernel_f1]=init_kernel(layer_c1_num,layer_f1_num);
    %pooling核初始化
    pooling_a=ones(2,2)/4;
    %全连接层的权值
    weight_f1=(2*rand(20,100)-ones(20,100))/sqrt(20);
    weight_output=(2*rand(100,10)-ones(100,10))/sqrt(100);
    disp('网络初始化完成......');
    %% 开始网络训练
    disp('开始网络训练......');
    for iter=1:20
    for n=1:20
        for m=0:9
            %读取样本
            train_data=imread(strcat(num2str(m),'_',num2str(n),'.bmp'));
            train_data=double(train_data);
            % 去均值
    %       train_data=wipe_off_average(train_data);
            %前向传递,进入卷积层1
            for k=1:layer_c1_num
                state_c1(:,:,k)=convolution(train_data,kernel_c1(:,:,k));
                %进入激励函数
                state_c1(:,:,k)=tanh(state_c1(:,:,k)+bias_c1(1,k));
                %进入pooling1
                state_s1(:,:,k)=pooling(state_c1(:,:,k),pooling_a);
            end
            %进入f1层
            [state_f1_pre,state_f1_temp]=convolution_f1(state_s1,kernel_f1,weight_f1);
            %进入激励函数
            for nn=1:layer_f1_num
                state_f1(1,nn)=tanh(state_f1_pre(:,:,nn)+bias_f1(1,nn));
            end
            %进入softmax层
            for nn=1:layer_output_num
                output(1,nn)=exp(state_f1*weight_output(:,nn))/sum(exp(state_f1*weight_output));
            end
           %% 误差计算部分
            Error_cost=-output(1,m+1);
    %         if (Error_cost<-0.98)
    %             break;
    %         end
            %% 参数调整部分
            [kernel_c1,kernel_f1,weight_f1,weight_output,bias_c1,bias_f1]=CNN_upweight(yita,Error_cost,m,train_data,...
                                                                                                    state_c1,state_s1,...
                                                                                                    state_f1,state_f1_temp,...
                                                                                                    output,...
                                                                                                    kernel_c1,kernel_f1,weight_f1,weight_output,bias_c1,bias_f1);
            
        end    
    end
    end
    disp('网络训练完成,开始检验......');
    count=0;
    for n=1:20
        for m=0:9
            %读取样本
            train_data=imread(strcat(num2str(m),'_',num2str(n),'.bmp'));
            train_data=double(train_data);
            % 去均值
    %       train_data=wipe_off_average(train_data);
            %前向传递,进入卷积层1
            for k=1:layer_c1_num
                state_c1(:,:,k)=convolution(train_data,kernel_c1(:,:,k));
                %进入激励函数
                state_c1(:,:,k)=tanh(state_c1(:,:,k)+bias_c1(1,k));
                %进入pooling1
                state_s1(:,:,k)=pooling(state_c1(:,:,k),pooling_a);
            end
            %进入f1层
            [state_f1_pre,state_f1_temp]=convolution_f1(state_s1,kernel_f1,weight_f1);
            %进入激励函数
            for nn=1:layer_f1_num
                state_f1(1,nn)=tanh(state_f1_pre(:,:,nn)+bias_f1(1,nn));
            end
            %进入softmax层
            for nn=1:layer_output_num
                output(1,nn)=exp(state_f1*weight_output(:,nn))/sum(exp(state_f1*weight_output));
            end
            [p,classify]=max(output);
            if (classify==m+1)
                count=count+1;
            end
            fprintf('真实数字为%d  网络标记为%d  概率值为%d \n',m,classify-1,p);
        end
    end
    
    

    init_kernel.m

    function [kernel_c1,kernel_f1]=init_kernel(layer_c1_num,layer_f1_num)
    %% 卷积核初始化
    for n=1:layer_c1_num
        kernel_c1(:,:,n)=(2*rand(5,5)-ones(5,5))/12;
    end
    for n=1:layer_f1_num
        kernel_f1(:,:,n)=(2*rand(12,12)-ones(12,12));
    end
    end
    

    convolution.m

    function [state]=convolution(data,kernel)
    %实现卷积层操作
    [data_row,data_col]=size(data);
    [kernel_row,kernel_col]=size(kernel);
    for m=1:data_col-kernel_col+1
        for n=1:data_row-kernel_row+1
            state(m,n)=sum(sum(data(m:m+kernel_row-1,n:n+kernel_col-1).*kernel));
        end
    end
    end
    

    pooling.m

    function state=pooling(data,pooling_a)
    %% 实现取样层pooling操作
    [data_row,data_col]=size(data);
    [pooling_row,pooling_col]=size(pooling_a);
    for m=1:data_col/pooling_col
        for n=1:data_row/pooling_row
            state(m,n)=sum(sum(data(2*m-1:2*m,2*n-1:2*n).*pooling_a));
        end
    end
    end
    

    convolution_f1.m

    function [state_f1,state_f1_temp]=convolution_f1(state_s1,kernel_f1,weight_f1)
    %% 完成卷积层2操作
    layer_f1_num=size(weight_f1,2);
    layer_s1_num=size(weight_f1,1);
    
    %%
    for n=1:layer_f1_num
        count=0;
        for m=1:layer_s1_num
            temp=state_s1(:,:,m)*weight_f1(m,n);
            count=count+temp;
        end
        state_f1_temp(:,:,n)=count;
        state_f1(:,:,n)=convolution(state_f1_temp(:,:,n),kernel_f1(:,:,n));
    end
    end
    

    CNN_upweight.m

    function [kernel_c1,kernel_f1,weight_f1,weight_output,bias_c1,bias_f1]=CNN_upweight(yita,Error_cost,classify,train_data,state_c1,state_s1,state_f1,state_f1_temp,...
                                                                                                    output,kernel_c1,kernel_f1,weight_f1,weight_output,bias_c1,bias_f1)
    %%%     完成参数更新,权值和卷积核
    %% 结点数目
    layer_c1_num=size(state_c1,3);
    layer_s1_num=size(state_s1,3);
    layer_f1_num=size(state_f1,2);
    layer_output_num=size(output,2);
    
    [c1_row,c1_col,~]=size(state_c1);
    [s1_row,s1_col,~]=size(state_s1);
    
    [kernel_c1_row,kernel_c1_col]=size(kernel_c1(:,:,1));
    [kernel_f1_row,kernel_f1_col]=size(kernel_f1(:,:,1));
    %% 保存网络权值
    kernel_c1_temp=kernel_c1;
    kernel_f1_temp=kernel_f1;
    
    weight_f1_temp=weight_f1;
    weight_output_temp=weight_output;
    %% Error计算
    label=zeros(1,layer_output_num);
    label(1,classify+1)=1;
    delta_layer_output=output-label;
    %% 更新weight_output
    for n=1:layer_output_num
        delta_weight_output_temp(:,n)=delta_layer_output(1,n)*state_f1';
    end
    weight_output_temp=weight_output_temp-yita*delta_weight_output_temp;
    
    %% 更新bias_f1以及kernel_f1
    for n=1:layer_f1_num
        count=0;
        for m=1:layer_output_num
            count=count+delta_layer_output(1,m)*weight_output(n,m);
        end
        %bias_f1
        delta_layer_f1(1,n)=count*(1-tanh(state_f1(1,n)).^2);
        delta_bias_f1(1,n)=delta_layer_f1(1,n);
        %kernel_f1
        delta_kernel_f1_temp(:,:,n)=delta_layer_f1(1,n)*state_f1_temp(:,:,n);
    end
    bias_f1=bias_f1-yita*delta_bias_f1;
    kernel_f1_temp=kernel_f1_temp-yita*delta_kernel_f1_temp;
    %% 更新weight_f1
    for n=1:layer_f1_num
        delta_layer_f1_temp(:,:,n)=delta_layer_f1(1,n)*kernel_f1(:,:,n);
    end
    for n=1:layer_s1_num
        for m=1:layer_f1_num
            delta_weight_f1_temp(n,m)=sum(sum(delta_layer_f1_temp(:,:,m).*state_s1(:,:,n)));
        end
    end
    weight_f1_temp=weight_f1_temp-yita*delta_weight_f1_temp;
    
    %% 更新 bias_c1
    for n=1:layer_s1_num
        count=0;
        for m=1:layer_f1_num
            count=count+delta_layer_f1_temp(:,:,m)*weight_f1(n,m);   
        end
        delta_layer_s1(:,:,n)=count;
        delta_layer_c1(:,:,n)=kron(delta_layer_s1(:,:,n),ones(2,2)/4).*(1-tanh(state_c1(:,:,n)).^2);
        delta_bias_c1(1,n)=sum(sum(delta_layer_c1(:,:,n)));
    end
    bias_c1=bias_c1-yita*delta_bias_c1;
    %% 更新 kernel_c1
    for n=1:layer_c1_num
        delta_kernel_c1_temp(:,:,n)=rot90(conv2(train_data,rot90(delta_layer_c1(:,:,n),2),'valid'),2);
    end
    kernel_c1_temp=kernel_c1_temp-yita*delta_kernel_c1_temp;
    
    %% 网络权值更新
    kernel_c1=kernel_c1_temp;
    kernel_f1=kernel_f1_temp;
    
    weight_f1=weight_f1_temp;
    weight_output=weight_output_temp;
    
    end
    

    程序运行结果:
    这里写图片描述

    检验200个,196个识别正确,4个识别错误。
    这里写图片描述

    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936
    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936
    程序及数据下载链接:
    https://download.csdn.net/download/u010540396/10839936

    展开全文
  • 主要是卷积神经网络CNN的matlab算法实现,有具体的代码解析,可直接运行
  • 神经网络学习(十三)卷积神经网络MATLAB实现

    万次阅读 多人点赞 2018-03-27 16:08:28
    上一节,我们简单探讨了卷积神经网络的反向传播算法,本节我们着手实现了一个简单的卷积神经网,在此之前先以最基本的批量随机梯度下降法+L2正则化对对卷积神经网络的反向传播算法做一个很简单回顾。 需要确定...

    系列博客是博主学习神经网络中相关的笔记和一些个人理解,仅为作者记录笔记之用,不免有很多细节不对之处。博主用Numpy实现了一个小巧的深度学习框架kitorch,可以方便实现CNN: MNIST例子。请不要再私信我要matlab的代码了。

    卷积神经网络回顾

    上一节,我们简单探讨了卷积神经网络的反向传播算法,本节我们着手实现了一个简单的卷积神经网,在此之前先以最基本的批量随机梯度下降法+L2正则化对对卷积神经网络的反向传播算法做一个很简单回顾。

    需要确定参数有:

    • 小批量数据的大小 m m m
    • CNN模型的层数 L L L 和所有隐藏层的类型
    • 对于卷积层,要定义卷积核的大小 k k k,卷积核子矩阵的维度 d d d,填充大小 p p p,步幅 s s s
    • 对于池化层,要定义池化区域大小 h h h 和池化标准(max 或者 mean)
    • 对于全连接层,要定义全连接层的激活函数和各层的神经元个数
    • 对于输出层,要定义输出函数和代价函数,多分类任务一般采用 softmax 函数和交叉熵代价函数 C = y ln ( a ) C = y\texttt{ln}(a) C=yln(a)
    • 超参数:学习速率 η \eta η, 惩罚系数 λ \lambda λ,最大迭代次数 max_iter, 和停止条件 ϵ \epsilon ϵ

    计算步骤

    1. 初始化每个隐含层的 W , b W,b W,b 的值为随机数。一般可以采用标准正态分布进行初始化(选用 1 ( n i n ) \dfrac{ 1}{\sqrt{(n_{in})}} (nin) 1 进行来缩放优化初始值),也可以采用 ( − ξ , ξ ) (-\xi, \xi) (ξ,ξ) 的均匀分布( ξ \xi ξ 取小值)
      2.正向传播
      2.1).将输入数据 x x x 赋值于输入神经元 a 1 , a 1 = x a^1, a^1 = x a1,a1=x
      2.2).从第二层开始,根据下面3种情况进行前向传播计算:
      • 如果当前是全连接层:则有 a l = σ ( z l ) = σ ( W l a l − 1 + b l ) a^{l} = \sigma(z^{l}) = \sigma(W^la^{l-1} + b^{l}) al=σ(zl)=σ(Wlal1+bl)
      • 如果当前是卷积层:则有 a l = σ ( z l ) = σ ( W l ∗ a l − 1 + b l ) a^{l} = \sigma(z^{l}) = \sigma(W^l*a^{l-1} + b^{l}) al=σ(zl)=σ(Wlal1+bl)
      • 如果当前是池化层:则有 a l = pool ( a l − 1 ) a^{l}= \texttt{pool}(a^{l-1}) al=pool(al1)
      2.3).对于输出层第 L L L 层,计算输出 a L = softmax ( z l ) = softmax ( W l a l − 1 + b l ) a^{L}= \texttt{softmax}(z^{l}) = \texttt{softmax}(W^la^{l-1} + b^{l}) aL=softmax(zl)=softmax(Wlal1+bl)

    3. 反向传播
    3.1).通过损失函数计算输出层的 δ L \delta^L δL
    3.2).从倒数第二层开始,根据下面3种情况逐层进行反向传播计算:

    • 如果当前是全连接层:则有 δ l = ( W l + 1 ) T δ l + 1 ⊙ σ ′ ( z l ) \delta^{l} = (W^{l+1})^T\delta^{l+1}\odot \sigma^{'}(z^{l}) δl=(Wl+1)Tδl+1σ(zl)
    • 如果上层是卷积层:则有 δ l = δ l + 1 ∗ rot180 ( W l + 1 ) ⊙ σ ′ ( z l ) \delta^{l} = \delta^{l+1}*\texttt{rot180}(W^{l+1}) \odot \sigma^{'}(z^{l}) δl=δl+1rot180(Wl+1)σ(zl)
    • 如果上层是池化层:则有 δ l = upsample ( δ l + 1 ) ⊙ σ ′ ( z l ) \delta^{l} = \texttt{upsample}(\delta^{l+1})\odot \sigma^{'}(z^{l}) δl=upsample(δl+1)σ(zl)
    4. 根据以下两种情况进行模型更新
    4.1).如果当前是全连接层: W l = ( 1 − η λ n ) W l − η m ∑ [ δ l ( a l − 1 ) T ] W^l = \left(1-\frac{\eta\lambda}{n}\right)W^l -\frac{\eta}{m} \sum \left[ \delta^{l}(a^{ l-1})^T\right] Wl=(1nηλ)Wlmη[δl(al1)T] b l = b l − η m ∑ ( δ l ) b^l = b^l -\frac{\eta}{m} \sum \left( \delta^{l} \right) bl=blmη(δl)4.2).如果当前是卷积层,对于每一个卷积核有: W l = ( 1 − η λ n ) W l − η m ∑ [ δ l ∗ rot90 ( a l − 1 , 2 ) ] W^l = \left(1-\frac{\eta\lambda}{n}\right)W^l - \frac{\eta}{m} \sum \left[ \delta^{l}*\texttt{rot90}(a^{ l-1},2)\right] Wl=(1nηλ)Wlmη[δlrot90(al1,2)] b l = b l − η m ∑ [ mean ( δ l ) ] b^l = b^l - \frac{\eta}{m} \sum \left[ \texttt{mean}(\delta^{l})\right] bl=blmη[mean(δl)]

    MATLAB实现

    限于个人能力,我们目前先实现一个简单的 1+N 结构的卷积神经网络,即 1 个卷积层(包括池化层)和 N个全连接层。下面是这个简单网络的结构

    这里写图片描述
    下面对各层做简要的说明:
    1、 卷积层:无padding,步幅 stride 设置为 1,激活函数选择ReLU函数
    2、 池化层:无padding,池化类型只实现 ‘average’ 方法
    3、 展铺层:为方便计算设计的层,属于预先分配的内存空间,作为全连接层的输入
    4、 全连接层:激活函数为Sigmoid函数
    5、 输出层:分类函数选择Softmax函数,代价函数选择交叉熵代价函数+L2正则化

    网络定义的MATLAB代码如下:

    loadMnistDataScript; %加载数据
    ntrain = size(training_data_label,2);
    mini_batch_size = 100;
    cnn.ntrain = ntrain;
    cnn.eta = 1;       %学习速率
    cnn.lambda = 5;    %正则化惩罚系数
    
    cnn.layer = {
        % input layer: 'input', mini_size, [height,width] of image
        {'input',mini_batch_size,[28,28]};
        % convlution layer: 'conv', kernel_number, [height,width] of kernel
        {'conv',20,[9,9]};
        % pooling layer: 'pool', pooling_type, [height,width] of pooling area
        {'pool','average',[2,2]};
        % flatten layer: 'flat', a layer for pre-allocated memory
        {'flat'};
        % full connect layer: 'full', neuron number
        {'full',100};
        {'full',100};
        % output layer: 'output', neuron number
        {'output',10};
        };
    
    

    由于变量过多,将cnn设计为一个结构体,包含的成员变量有
    1、cnn.layer:网络结构的定义,元胞数组;
    2、cnn.z:每一层的带权输入,元胞数组;
    3、cnn.a:每一层的输出,元胞数组;
    4、cnn.delta::每一层的误差敏感项,元胞数组;
    5、cnn.weights:每一层的权重。元胞数组;
    6、cnn.biases:每一层的偏置,元胞数组;
    7、cnn.nabla_w:权重的梯度,元胞数组;
    8、cnn.nabla_b:偏置的梯度,元胞数组;
    9、其他一些超参数
    这样每一层包含7个量:带权输入( z z z),输出( a a a),误差( δ \delta δ),权重( W W W),偏置( b b b),权重梯度( ∇ W \nabla W W),偏置梯度( ∇ b \nabla b b)。并不是每一层都实际需要这7个量,不需要的层将其设置为空数组即可,下面是网络初始化的过程,假如第 n n n层为:
    1、输入层:

    a{n} = zeros([ImageHeight, ImageWidth, mini_batch_size])
    

    2、卷积层:

    ImageHeight = ImageHeight – KernelHeight+1
    ImageWidth = ImageWidth– KernelWidth+1
    z{n} = zeros([ImageHeight, ImageWidth, mini_batch_size, kernel_number])
    a{n} = zeros([ImageHeight, ImageWidth, mini_batch_size, kernel_number])
    delta{n} = zeros([ImageHeight, ImageWidth, mini_batch_size, kernel_number])
    weights{n} = rand([KernelHeight, KernelWidth, kernel_number])-0.5
    nabla_w =zeros( [KernelHeight, KernelWidth, kernel_number])
    biases{n} = rand([1, kernel_number])-0.5
    nabla_b{n} =zeros( [1, kernel_number])
    

    3、池化层

    ImageHeight = ImageHeight / KernelHeight
    mageWidth = ImageWidth / KernelWidth
    a{n} = zeros([ImageHeight, ImageWidth, mini_batch_size, kernel_number])
    delta{n} = zeros([ImageHeight, ImageWidth, mini_batch_size, kernel_number])
    

    4、展铺层

    a{n} = zeros([ImageHeight*ImageWidth* kernel_number, mini_batch_size])
    delta{n} = zeros([ImageHeight*ImageWidth* kernel_number, mini_batch_size])
    

    5、全连接层和输出层

    z{n} = zeros([neuron_number, mini_batch_size])
    a{n} = zeros([neuron_number, mini_batch_size])
    delta{n} = zeros([neuron_number, mini_batch_size])
    weights{n} = rand([neuron_number,prev_layer_neuron_number])-0.5
    nabla_w{n} = zeros([neuron_number,prev_layer_neuron_number])
    biases{n} = rand([neuron_number,1])-0.5
    nabla_b{n} = zeros([neuron_number,1])
    

    下面是详细代码

    function cnn = cnn_initialize(cnn)
    %CNN_INIT initialize the weights and biases, and other parameters
    %   
    index = 0;
    num_layer = numel(cnn.layer);
    for in = 1:num_layer
        switch cnn.layer{in}{1}
            case 'input'
                index = index + 1;
                height = cnn.layer{in}{3}(1);
                width = cnn.layer{in}{3}(2);
                mini_size = cnn.layer{in}{2};
                cnn.weights{index} = [];
                cnn.biases{index} = [];
                cnn.nabla_w{index} = [];
                cnn.nabla_b{index} = [];
                %n*n*m
                cnn.a{index} = [];
                cnn.z{index} = [];
                cnn.delta{index} = [];
                cnn.mini_size = mini_size;
            case 'conv'
                index = index + 1;
                %kernel height, width, number
                ker_height = cnn.layer{in}{3}(1);
                ker_width = cnn.layer{in}{3}(2);
                ker_num = cnn.layer{in}{2};
                cnn.weights{index} = grand(ker_height,ker_width,ker_num) - 0.5;
                cnn.biases{index} = grand(1,ker_num) - 0.5;
                cnn.nabla_w{index} = zeros(ker_height,ker_width,ker_num);
                cnn.nabla_b{index} = zeros(1,ker_num);
                height = height - ker_height + 1;
                width = width - ker_width + 1;
                cnn.a{index} = zeros(height,width,mini_size,ker_num);
                cnn.z{index} = zeros(height,width,mini_size,ker_num);
                cnn.delta{index} = zeros(height,width,mini_size,ker_num);
            case 'pool'
                index = index + 1;
                %kernel height, width, number
                ker_height = cnn.layer{in}{3}(1);
                ker_width = cnn.layer{in}{3}(2);
                cnn.weights{index} = [];
                cnn.biases{index} = [];
                cnn.nabla_w{index} = [];
                cnn.nabla_b{index} = [];
                height = height / ker_height;
                width = width / ker_width;
                cnn.a{index} = zeros(height,width,mini_size,ker_num);
                cnn.z{index} = [];
                cnn.delta{index} = zeros(height,width,mini_size,ker_num);
            case 'flat'
                index = index + 1;
                cnn.weights{index} = [];
                cnn.biases{index} = [];
                cnn.nabla_w{index} = [];
                cnn.nabla_b{index} = [];
    
                cnn.a{index} = zeros(height*width*ker_num,mini_size);
                cnn.z{index} = [];
                cnn.delta{index} = zeros(height*width*ker_num,mini_size);
            case 'full'
                index = index + 1;
                %kernel height, width, number
                neuron_num = cnn.layer{in}{2};
                neuron_num0 = size(cnn.a{in-1},1);
                
                cnn.weights{index} = grand(neuron_num,neuron_num0) - 0.5;
                cnn.biases{index} = grand(neuron_num,1) - 0.5;
                cnn.nabla_w{index} = zeros(neuron_num,neuron_num0);
                cnn.nabla_b{index} = zeros(neuron_num,1);
        
                cnn.a{index} = zeros(neuron_num,mini_size);
                cnn.z{index} = zeros(neuron_num,mini_size);
                cnn.delta{index} = zeros(neuron_num,mini_size);
                
            case 'output'
                 index = index + 1;
                %kernel height, width, number
                neuron_num = cnn.layer{in}{2};
                neuron_num0 = size(cnn.a{in-1},1);
                
                cnn.weights{index} = grand(neuron_num,neuron_num0) - 0.5;
                cnn.biases{index} = grand(neuron_num,1);
                cnn.nabla_w{index} = zeros(neuron_num,neuron_num0);
                cnn.nabla_b{index} = zeros(neuron_num,1);
        
                cnn.a{index} = zeros(neuron_num,mini_size);
                cnn.z{index} = zeros(neuron_num,mini_size);
                cnn.delta{index} = zeros(neuron_num,mini_size);
            otherwise
                
        end
    end
    end
    

    下面是正向计算过程(伪代码),假设第 n n n层为
    1、输入层:

    a{n} = x 
    

    2、卷积层:

    z{n} = conv(weights{n}*a{n-1})+biases{n} 
    a{n} = relu(z{n}) 
    

    3、池化层

    a{n}=pool(a{n-1}) %程序中同样使用卷积实现的 
    

    4、展铺层

    a{n} = reshape(a{n-1}) 
    

    5、全连接层

      z{n} = weights{n}*a{n-1}+biases{n} 
      a{n} = sigmoid(z{n})  
    

    6、输出层

    z{n} = weights{n}*a{n-1}+biases{n} 
    a{n} = softmax(z{n}) 
    

    具体代码如下:

    function cnn = cnn_feedforward(cnn,x)
    %CNN_FEEDFORWARD CNN feedforward
    %   
    num = numel(cnn.layer);
    for in = 1:num
    
    switch cnn.layer{in}{1}
        case 'input'
            cnn.a{in} = x;
         case 'conv'
             kernel_num = cnn.layer{in}{2};
             for ik = 1:kernel_num
                 cnn.z{in}(:,:,:,ik) = convn(cnn.a{in-1},...
                     cnn.weights{in}(:,:,ik),'valid')+cnn.biases{in}(ik);
             end
             cnn.a{in} = relu(cnn.z{in});
        
         case 'pool'
             
             ker_h = cnn.layer{in}{3}(1);
             ker_w = cnn.layer{in}{3}(2);
             kernel = ones(ker_h,ker_w)/ker_h/ker_w;
             
             tmp = convn(cnn.a{in-1},kernel,'valid');
             cnn.a{in} = tmp(1:ker_h:end,1:ker_w:end,:,:);
    
         case 'flat'
            [height,width,mini_size,kernel_num] = size(cnn.a{in-1});
            for ik = 1:mini_size
                cnn.a{in}(:,ik) = reshape(cnn.a{in-1}(:,:,ik,:),[height*width*kernel_num,1]);
            end
         case 'full'
             cnn.z{in}= bsxfun(@plus,cnn.weights{in}*cnn.a{in-1},cnn.biases{in});
             cnn.a{in} = sigmoid(cnn.z{in});
         case 'output'
             cnn.z{in}= bsxfun(@plus,cnn.weights{in}*cnn.a{in-1},cnn.biases{in});
             cnn.a{in} = softmax(cnn.z{in});
    	end
    	end
    end
    

    下面是反向计算过程(伪代码),假设第 n n n层为

    1、卷积层:

    delta{n} = upsample(delta{n+1}).*relu_prime(z{n})
    nabla_w{n} = conv2(delta{n},rot90(a{n-1},2),'valid')/mini_batch_size
    nabla_b{n} = mean(delta{n})
    
    

    2、池化层

    delta{n} = reshape(delta{n+1}) 
    

    3、展铺层

    delta{n} = weights{n+1}'*delta{n+1}
    

    4、全连接层

    delta{n} = weights{n+1}'*delta{n+1}.*sigmoid_prime(a{n})
    nabla_w{n} = delta{n}*a{n-1}'/mini_batch_size
    nabla_b{n} = mean(delta{n})
    

    5、输出层

    delta{n} = a{n}-y 
    nabla_w{n} = delta{n}*a{n-1}'/mini_batch_size
    nabla_b{n} = mean(delta{n})
    

    下面是反向传播和模型更新部分的 MATLAB 代码

    function cnn = cnn_backpropagation(cnn,y)
    %CNN_BP CNN backpropagation
    
    num = numel(cnn.layer);
    
    for in = num:-1:2
    
    switch cnn.layer{in}{1}
        case 'conv'
            
            ker_h = cnn.layer{in+1}{3}(1);
            ker_w = cnn.layer{in+1}{3}(2);
            kernel = ones(ker_h,ker_w)/ker_h/ker_w;
            [~,~,mini_size,kernel_num] = size(cnn.delta{in+1});
            cnn.nabla_w{in}(:) = 0;
            cnn.nabla_b{in}(:) = 0;
            for ik = 1:kernel_num
                for im = 1:mini_size
                    cnn.delta{in}(:,:,im,ik) = kron(cnn.delta{in+1}(:,:,im,ik),kernel).*relu_prime(cnn.z{in}(:,:,im,ik));
                    cnn.nabla_w{in}(:,:,ik) = cnn.nabla_w{in}(:,:,ik) +...
                        conv2(rot90(cnn.a{in-1}(:,:,im),2),cnn.delta{in}(:,:,im,ik),'valid');
                    cnn.nabla_b{in}(ik) = cnn.nabla_b{in}(ik) + mean(mean(cnn.delta{in}(:,:,im,ik)));
                end
                cnn.nabla_w{in}(:,:,ik) = cnn.nabla_w{in}(:,:,ik)/mini_size;
                cnn.nabla_b{in}(ik) = cnn.nabla_b{in}(ik)/mini_size;
            end
        case 'pool'
            [height,width,mini_size,kernel_num] = size(cnn.a{in});
            for ik = 1:mini_size
                cnn.delta{in}(:,:,ik,:) = reshape(cnn.delta{in+1}(:,ik),[height,width,kernel_num]);
            end
        case 'flat'
            cnn.delta{in} = cnn.weights{in+1}'*cnn.delta{in+1};
        case 'full'
            cnn.delta{in}= cnn.weights{in+1}'*cnn.delta{in+1}.*sigmoid_prime(cnn.z{in});
            cnn.nabla_w{in} = cnn.delta{in}*(cnn.a{in-1})'/cnn.mini_size;
            cnn.nabla_b{in} = mean(cnn.delta{in},2);
        case 'output'
            cnn.delta{in}= (cnn.a{in} - y);
            cnn.nabla_w{in} = cnn.delta{in}*(cnn.a{in-1})'/cnn.mini_size;
            cnn.nabla_b{in} = mean(cnn.delta{in},2);
        otherwise
            
    end
    
    end
    
    eta = cnn.eta;
    lambda = cnn.lambda;
    ntrain = cnn.ntrain;
    % update models
    for in = 1:num
        cnn.weights{in} = (1-eta*lambda/ntrain)*cnn.weights{in} - eta*cnn.nabla_w{in};
        cnn.biases{in} = (1-eta*lambda/ntrain)*cnn.biases{in} - eta*cnn.nabla_b{in};
    end
    
    end
    

    下面是主程序部分

    cnn = cnn_initialize(cnn);
    max_iter = 50000;
    for in = 1:max_iter
        pos = randi(ntrain-mini_batch_size);
        x = training_data(:,:,pos+1:pos+mini_batch_size);
        y = training_data_label(:,pos+1:pos+mini_batch_size);
        cnn = cnn_feedforward(cnn,x);
        cnn = cnn_backpropagation(cnn,y);
        if mod(in,100) == 0
            disp(in);
        end
        if mod(in,5000) == 0
            disp(['validtion accuracy: ',num2str(...
            cnn_evaluate(cnn,validation_data,validation_data_label)*100), '%']);
        end
    end
    

    运行结果为

    这里写图片描述

    迭代次数为50000次,mini_batch_size = 100,如果按照无放回的随机梯度计算,迭代次数为100个epoch。在校验数据(validation_data)上的识别率最高为 99.02%, 在测试数据(test_data)上的识别率为 99.13%。CNN的效率比较低,单线程迭代50000次,共耗时3个多小时。-_-||。

    本节代码可在这里下载到(没有积分的同学可私信我)。

    免费代码在这里呀,由于MATLAB版本的问题,可能会出错哦,自己调整下吧

    展开全文
  • 卷积神经网络完成程序matlab 卷积神经网络完成程序matlab
  • RNN卷积神经网络,LSTM,是使用matlab实现的,简单的模拟。欢迎大家来下载。
  • (MDNet代码)深度卷积神经网络目标跟踪(matlab代码

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,100
精华内容 2,040
关键字:

卷积神经网络matlab代码

matlab 订阅