mnist实例代码分析

原文连接:https://blog.csdn.net/u012273127/article/details/76206977
感谢这位博主的笔记
cnn_mnist_init.m文件代码

function net = cnn_mnist_init(varargin)
% 初始化CNN网络结构
% CNN_MNIST_LENET Initialize a CNN similar for MNIST

%默认参数设置
%开启批量归一化操作选项
%是否开启批量归一化的操作
opts.batchNormalization = true ;
%默认使用simpleNN网络封装器
opts.networkType = 'simplenn' ;
%根据外部参数修改参数默认值
opts = vl_argparse(opts, varargin) ;

%设置随机数发生器
rng('default');
rng(0) ;


% 设置网络结构
% f用于缩小随机初始化的conv层权值参数
f=1/100 ;
net.layers = {} ;

%卷积层参数:
% type -- 该层的类型
% weights -- 权重和偏置参数
% stride -- 步长参数
% pad -- 卷积图像边缘填充参数
% pad = 0 --图像块上的扩展宽度为0,即是不做任何扩展
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(5,5,1,20, 'single'), zeros(1, 20, 'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;

%池化层参数:
% type -- 该层的类型
% method -- 池化的类型,这里为最大池化
% pool -- 为池化模板的大小
% stride -- 步长参数
% pad -- 图像边缘填充参数
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
% 卷积层                       
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(5,5,20,50, 'single'),zeros(1,50,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
%最大池化层                       
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
% 卷积层                       
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(4,4,50,500, 'single'),  zeros(1,500,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
% relu激活层,即使用relu为激活函数激活层                       
net.layers{end+1} = struct('type', 'relu') ;
%卷积层
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(1,1,500,10, 'single'), zeros(1,10,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;                       
% softmax层                      
net.layers{end+1} = struct('type', 'softmaxloss') ;

% optionally switch to batch normalization
% 根据是否需要归一化在网络中插入相应的层
% 如果需要批量归一化则需要在相应的位置插入层
if opts.batchNormalization
  net = insertBnorm(net, 1) ;
  net = insertBnorm(net, 4) ;
  net = insertBnorm(net, 7) ;
end

% Meta parameters
% 设置网络的一些参数

% 设置输入图像的尺寸, 输入尺寸为28*28
net.meta.inputSize = [28 28 1] ;
% 设置学习率
net.meta.trainOpts.learningRate = 0.001 ;
% 训练回合次数
net.meta.trainOpts.numEpochs = 20 ;
% 一个批次传递的样本数量
% 即每次积累多少样本的误差进行一次梯度下降更新参数
net.meta.trainOpts.batchSize = 100 ;

% Fill in defaul values
% 填充一些默认的值
% 在网络中添加一些默认的属性值
net = vl_simplenn_tidy(net) ;

% Switch to DagNN if requested
% 如果网络是simplenn类型不做任何处理
% 如果网络是dagnn,需要做一些设置
switch lower(opts.networkType)
  case 'simplenn'
    % done
  case 'dagnn'
    net = dagnn.DagNN.fromSimpleNN(net, 'canonicalNames', true) ;
    net.addLayer('top1err', dagnn.Loss('loss', 'classerror'), ...
      {'prediction', 'label'}, 'error') ;
    net.addLayer('top5err', dagnn.Loss('loss', 'topkerror', ...
      'opts', {'topk', 5}), {'prediction', 'label'}, 'top5err') ;
  otherwise
    assert(false) ;
end

% --------------------------------------------------------------------
% 在net的第L和L+1层中间插入Bnorm层的实现函数,用于需要批量归一化的时候
function net = insertBnorm(net, l)
% --------------------------------------------------------------------
assert(isfield(net.layers{l}, 'weights'));
ndim = size(net.layers{l}.weights{1}, 4);
layer = struct('type', 'bnorm', ...
               'weights', {{ones(ndim, 1, 'single'), zeros(ndim, 1, 'single')}}, ...
               'learningRate', [1 1 0.05], ...
               'weightDecay', [0 0]) ;
net.layers{l}.weights{2} = [] ;  % eliminate bias in previous conv layer
net.layers = horzcat(net.layers(1:l), layer, net.layers(l+1:end)) ;

cnn_mnist.m文件代码

function [net, info] = cnn_mnist(varargin)
%CNN_MNIST  Demonstrates MatConvNet on MNIST

%将..\\..\\matlab\\vl_setupnn.m文件导入到当前workspace中
% 运行 vl_setupnn.m 文件
% vl_setupnn.m文件功能:将matconvnet框架工具箱添加到MATLAB的path中
run(fullfile(fileparts(mfilename('fullpath')),...
  '..', '..', 'matlab', 'vl_setupnn.m')) ;

%opt为可选参数,所有的参数
opts.batchNormalization = false ;       %是否批量处理,批量归一化
opts.network = [] ;
opts.networkType = 'simplenn' ;     %网络的模型,只有两种sinplenn或者dagnn
[opts, varargin] = vl_argparse(opts, varargin) ;  %根据外部参数修改参数默认值

%整个代码段构建实验路径
sfx = opts.networkType ;
if opts.batchNormalization, sfx = [sfx '-bnorm'] ; end

%配置实验结果存放路径: data\mnist-baseline-simplenn文件夹
%vl_rootnn为找到框架根目录
opts.expDir = fullfile(vl_rootnn, 'data', ['mnist-baseline-' sfx]) ;
[opts, varargin] = vl_argparse(opts, varargin) ;

%mnist原始数据所在的文件夹路径: matconvnet-1.0-beta24\data\mnist
opts.dataDir = fullfile(vl_rootnn, 'data', 'mnist') ;

%配置可以直接用的数据的路径
%不会直接用原始数据进行跑,会进行预处理,去除均值等
% imdb.mat中存储的就是可以直接用的数据,h*w*c*n这种形式的数据
% 设置网络可用数据的存储路径
%imdb结构体存放的路径: data\mnist-baseline-simplenn\imdb.mat
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');

opts.train = struct() ;

%解析参数,将传进来的参数赋值给网络参数
opts = vl_argparse(opts, varargin) ;

%默认使用cpu跑程序
%是否使用GPU编译程序
if ~isfield(opts.train, 'gpus'), opts.train.gpus = []; end;

% --------------------------------------------------------------------
%                                                         Prepare data
% --------------------------------------------------------------------


%判断网络持否已经初始化好
if isempty(opts.network)
    %如果没有初始化好一个网络,程序自己初始化一个网络
    % cnn_mnist_init函数 -- 初始化一个cnn网络
    % 根据前面的一些参数初始化一个网路
  net = cnn_mnist_init('batchNormalization', opts.batchNormalization, ...
    'networkType', opts.networkType) ;
else
    %已经初始化好一个网络
  net = opts.network ;
  opts.network = [] ;
end

%读取网络可使用的数据imdb
if exist(opts.imdbPath, 'file')
    %加载数据
  imdb = load(opts.imdbPath) ;
else
    % 从minst数据集中获取数据,减去图像均值,存放到Imdb结构体中
    % 即将原始数据转化成网络可以使用的数据格式,同时做一些预处理
    % 并将可以直接用的数据存储起来
  imdb = getMnistImdb(opts) ;
  mkdir(opts.expDir) ;
  save(opts.imdbPath, '-struct', 'imdb') ;
end

%数据集的lable类别
% 数据的类别, 1到10
net.meta.classes.name = arrayfun(@(x)sprintf('%d',x),1:10,'UniformOutput',false) ;

% --------------------------------------------------------------------
%                                                                Train
% --------------------------------------------------------------------

%根据网络类型选择不同的训练函数
% @为函数句柄
switch opts.networkType
  case 'simplenn', trainfn = @cnn_train ;
  case 'dagnn', trainfn = @cnn_train_dag ;
end


%训练网络
% getBatch每次获取一个batch的图输入
[net, info] = trainfn(net, imdb, getBatch(opts), ...
                'expDir', opts.expDir, ...
                 net.meta.trainOpts, ...     
                  opts.train, ...  
                 'val', find(imdb.images.set == 3)) ;   %选择验证机标签


%%每次获取一个batch的输入数据                 
% --------------------------------------------------------------------
function fn = getBatch(opts)
% --------------------------------------------------------------------
switch lower(opts.networkType)
  case 'simplenn'
    fn = @(x,y) getSimpleNNBatch(x,y) ;
  case 'dagnn'
    bopts = struct('numGpus', numel(opts.train.gpus)) ;
    fn = @(x,y) getDagNNBatch(bopts,x,y) ;
end

% --------------------------------------------------------------------
function [images, labels] = getSimpleNNBatch(imdb, batch)
% --------------------------------------------------------------------
images = imdb.images.data(:,:,:,batch) ;
labels = imdb.images.labels(1,batch) ;

% --------------------------------------------------------------------
function inputs = getDagNNBatch(opts, imdb, batch)
% --------------------------------------------------------------------
images = imdb.images.data(:,:,:,batch) ;
labels = imdb.images.labels(1,batch) ;
if opts.numGpus > 0
  images = gpuArray(images) ;
end
inputs = {'input', images, 'label', labels} ;



% --------------------------------------------------------------------
function imdb = getMnistImdb(opts)
% --------------------------------------------------------------------
% 从原始数据中生成和获取我们网络可以使用的imdb输入数据文件
% Preapre the imdb structure, returns image data with mean image subtracted

%原始输入数据
files = {'train-images-idx3-ubyte', ...
         'train-labels-idx1-ubyte', ...
         't10k-images-idx3-ubyte', ...
         't10k-labels-idx1-ubyte'} ;

if ~exist(opts.dataDir, 'dir')
  mkdir(opts.dataDir) ;
end

for i=1:4
% 读取files中的第一个文件,训练图像包含6万张尺寸为28*28的图像
  if ~exist(fullfile(opts.dataDir, files{i}), 'file')
    url = sprintf('http://yann.lecun.com/exdb/mnist/%s.gz',files{i}) ;
    fprintf('downloading %s\n', url) ;
    gunzip(url, opts.dataDir) ;
  end
end

%读取files中的第一个文件,训练图像集包含6万张尺寸为28*28的图像
f=fopen(fullfile(opts.dataDir, 'train-images-idx3-ubyte'),'r') ;
x1=fread(f,inf,'uint8');
fclose(f) ;
%调整成矩阵,60000张图像调整成一个矩阵
x1=permute(reshape(x1(17:end),28,28,60e3),[2 1 3]) ;

%读取files中的第二个文件
f=fopen(fullfile(opts.dataDir, 't10k-images-idx3-ubyte'),'r') ;
x2=fread(f,inf,'uint8');
fclose(f) ;
x2=permute(reshape(x2(17:end),28,28,10e3),[2 1 3]) ;

%读取files中的第三个文件--训练图像的标签
f=fopen(fullfile(opts.dataDir, 'train-labels-idx1-ubyte'),'r') ;
y1=fread(f,inf,'uint8');
fclose(f) ;
y1=double(y1(9:end)')+1 ;

%读取files中的第四个文件 -- 测试图像集的标签
f=fopen(fullfile(opts.dataDir, 't10k-labels-idx1-ubyte'),'r') ;
y2=fread(f,inf,'uint8');
fclose(f) ;
y2=double(y2(9:end)')+1 ;

% 用于表示样本集合中训练集和测试集的集和
% set中元素==1为训练集,==3为测试集
set = [ones(1,numel(y1)) 3*ones(1,numel(y2))];

% 将x1的训练集和x2的测试集在第三维拼接起来,构成完成的数据集,从uint8转成single
data = single(reshape(cat(3, x1, x2),28,28,1,[]));

%求出所有的训练集中所有图像的均值图像
dataMean = mean(data(:,:,:,set == 1), 4);

%bsxfun函数将minus算子应用到data的每个元素上,对所有的图像减去均值
data = bsxfun(@minus, data, dataMean) ;


%生成网络可以直接使用的输入数据类型
% 填充imdb结构体构造数据集
imdb.images.data = data ;      %存储所有的数据
imdb.images.data_mean = dataMean;   %存储所有训练图像的均值图像
imdb.images.labels = cat(2, y1, y2) ;  %将训练集和测试集标签的第二维拼接起来
imdb.images.set = set ;
imdb.meta.sets = {'train', 'val', 'test'} ; %set == 训练;==2验证;==3测试
imdb.meta.classes = arrayfun(@(x)sprintf('%d',x),0:9,'uniformoutput',false) ;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值