CNN卷积神经网络学习笔记4:代码学习

代码来自github上的一个DeepLearning Toolbox,地址:https://github.com/rasmusbergpalm/DeepLearnToolbox

主要参考这篇博客中的代码注释:
http://blog.csdn.net/zouxy09/article/details/9993743

CNN原理和公式推导见前文:
背景
网络结构
公式推导

单步调试后自己添加了一部分注释
如下:

test_example_CNN

function test_example_CNN
load mnist_uint8;

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');

%% 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 = {
    struct('type', 'i') %input layer
    struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer
    struct('type', 's', 'scale', 2) %sub sampling layer
    struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer
    struct('type', 's', 'scale', 2) %subsampling layer

};

% learning rate 学习率,决定收敛的速度
opts.alpha = 1;
% 把样本split为每50个一份,每用batchsize个样本训练一次,调整一次权值
opts.batchsize = 50;
% split次数
opts.numepochs = 1;

cnn = cnnsetup(cnn, train_x, train_y);
cnn = cnntrain(cnn, train_x, train_y, opts);

[er, bad] = cnntest(cnn, test_x, test_y);

%plot mean squared error
figure; plot(cnn.rL);
assert(er<0.12, 'Too big error');

cnnsetup

function net = cnnsetup(net, x, y)
    inputmaps = 1;
    % B=squeeze(A) 返回和矩阵A相同元素但所有单一维都移除的矩阵B,单一维是满足size(A,dim)=1的维。
    % train_x中图像的存放方式是三维的reshape(train_x',28,28,60000),前面两维表示图像的行与列,
    % 第三维就表示有多少个图像。这样squeeze(x(:, :, 1))就相当于取第一个图像样本后,再把第三维
    % 移除,就变成了28x28的矩阵,也就是得到一幅图像,再通过size函数就得到了训练样本图像的行数与列数
    mapsize = size(squeeze(x(:, :, 1)));

    % 下面通过传入net这个结构体来逐层构建CNN网络
    % n = numel(A)返回数组A中元素个数
    % net.layers中有五个struct类型的元素,实际上就表示CNN共有五层,这里的范围是5
    for l = 1 : numel(net.layers)   %  layer
        if strcmp(net.layers{l}.type, 's') % 如果这层是 子采样层
            % subsampling层的mapsize,最开始mapsize是每张图的大小28*28
            % 这里除以scale=2,就是pooling之后图的大小,pooling域之间没有重叠,所以pooling后的图像为14*14
            % 注意这里的右边的mapsize保存的都是上一层每张特征map的大小,它会随着循环进行不断更新
            mapsize = floor(mapsize / net.layers{l}.scale);
            for j = 1 : inputmaps % inputmap就是上一层有多少张特征图
                net.layers{l}.b{j} = 0; % 将偏置初始化为0
            end
        end
        if strcmp(net.layers{l}.type, 'c') % 如果这层是 卷积层
            % 旧的mapsize保存的是上一层的特征map的大小,那么如果卷积核的移动步长是1,那用
            % kernelsize*kernelsize大小的卷积核卷积上一层的特征map后,得到的新的map的大小就是下面这样
            mapsize = mapsize - net.layers{l}.kernelsize + 1;
            % 该层需要学习的参数个数。每张特征map是一个(后层特征图数量)*(用来卷积的patch图的大小)
            % 因为是通过用一个卷积核在上一个特征map层中移动(核窗口每次移动1个像素),遍历上一个特征map
            % 层的每个神经元。卷积核由kernelsize*kernelsize个元素组成,每个元素是一个独立的权值,所以
            % 就有kernelsize*kernelsize个需要学习的权值,再加一个偏置值。另外,由于是权值共享,也就是
            % 说同一个特征map层是用同一个具有相同权值元素的kernelsize*kernelsize的核窗口去感受输入上一
            % 个特征map层的每个神经元得到的,所以同一个特征map,它的权值是一样的,共享的,权值只取决于
            % 核窗口。然后,不同的特征map提取输入上一个特征map层不同的特征,所以采用的核窗口不一样,也
            % 就是权值不一样,所以outputmaps个特征map就有(kernelsize*kernelsize+1)* outputmaps那么多的权值了
            % 但这里fan_out只保存卷积核的权值W,偏置b在下面独立保存
            fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;
            for j =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值