【Matlab】基于MNIST数据集的图像识别(深度学习入门、卷积神经网络、Matlab,附完整学习资料)


Matlab——数字0~9的图像识别(Phil Kim著、Matlab)


本文可以为那些想对深度学习和人工智能有初步了解的朋友提供一些基础入门的帮助。


本文所用参考书:

《MATLAB深度学习 机器学习、神经网络与人工智能》
【美】Phil Kim著
敖富江 杜静 周浩 译
清华大学出版社
ISBN:978-7-302-49638-0


水平有限,本文仅作学习交流,笔记分享所用。

工程文件为上述参考书由给出,本文对该工程中部分函数作了一些注解,方便大家理解和应用。


所需的知识储备:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

阿汪先生做的印象笔记链接:


部分工程文件注解:

1、神经网络训练函数-MnistConv

function [W1, W5, Wo] = MnistConv(W1, W5, Wo, X, D)
%MnistConv函数接收神经网络的权重和训练数据,并返回经过训练后的权重。
%W1-卷积滤波器矩阵
%W5:池化-隐含层权重矩阵
%Wo:隐含-输出层权重矩阵
%X:训练数据的输入
%D:标准输出

alpha = 0.01;       %delta规则,参数学习率α,
                        %笔记:第2章-2.5、2.6-delta规则、广义delta规则
beta  = 0.95;       %β:小于1的正常数,动量,反向传播,提高学习效率,
                        %笔记:第3章-3.2-反向传播示例

momentum1 = zeros(size(W1));           %动量矩阵,生成全零矩阵
momentum5 = zeros(size(W5));           %公式,见笔记,第3章-3.2-反向传播示例
momentumo = zeros(size(Wo));

N = length(D);      %标准输出D数组的长度

bsize = 100;        %批次数,8000个训练数据,100批次
                    %权重的调整,次数为80次,完成80次调整为一个历元。
blist = 1:bsize:(N-bsize+1);
                    %保存置入minibatch的首个训练数据点的所在位置。       
        
% 一次历元epoch循环
%
for batch = 1:length(blist)
  dW1 = zeros(size(W1));
  dW5 = zeros(size(W5));
  dWo = zeros(size(Wo));
  
  % Mini-batch循环
  %
  begin = blist(batch);
  for k = begin:begin+bsize-1
    %
    x  = X(:, :, k);         % 输入 28x28 的原始图像
    y1 = Conv(x, W1);        % 卷积层(卷积滤波器)处理后,输出20个20x20的图像
    y2 = ReLU(y1);           %进入池化层前进行ReLU,避免梯度消失问题
    y3 = Pool(y2);           % 平均池化,输出20个10x10的图像
    y4 = reshape(y3, [], 1); %y3矩阵重排列,转换成1列多行的矩阵
    v5 = W5*y4;              % 
    y5 = ReLU(v5);           %
    v  = Wo*y5;              % 
    y  = Softmax(v);         %代入激活函数Softmax, 10个输出节点,输出10x1矩阵

    % 独热编码过程
    d = zeros(10, 1);
    d(sub2ind(size(d), D(k), 1)) = 1;
                            %sub2ind()生成线性索引编号
                            %matlab中矩阵的存储是按列优先的
    % 反向传播过程
    e      = d - y;                   % 输出层 
    delta  = e;

    e5     = Wo' * delta;             % 隐藏层(ReLU)
    delta5 = (y5 > 0) .* e5;

    e4     = W5' * delta5;            % 池化层(Pool)
    
    e3     = reshape(e4, size(y3));   %重新排列矩阵e4,排列成y3的相同行列数

    e2 = zeros(size(y2));           
    W3 = ones(size(y2)) / (2*2);
    for c = 1:20
      e2(:, :, c) = kron(e3(:, :, c), ones([2 2])) .* W3(:, :, c);
            %kron即为Kronecker积,所谓Kronecker积是一种矩阵运算          
            %C=kron (A,B)    
            %A为m×n矩阵,B为p×q矩阵,则C为mp×nq矩阵。
    end
    
    delta2 = (y2 > 0) .* e2;          % ReLU层
  
    delta1_x = zeros(size(W1));       % 卷积层
    for c = 1:20
      delta1_x(:, :, c) = conv2(x(:, :), rot90(delta2(:, :, c), 2), 'valid');
    end
    
    dW1 = dW1 + delta1_x; 
    dW5 = dW5 + delta5*y4';    
    dWo = dWo + delta *y5';
  end 
  
  % 更新权重数值
  %
  dW1 = dW1 / bsize;         %minibatch更新次数,
  dW5 = dW5 / bsize;         %见笔记,第2章-2.7、2.8-SGD、Batch和Mini Batch
  dWo = dWo / bsize;
  
  momentum1 = alpha*dW1 + beta*momentum1;   %采用动量来调整权重
  W1        = W1 + momentum1;               %见笔记,第3章-3.2-反向传播示例
  
  momentum5 = alpha*dW5 + beta*momentum5;
  W5        = W5 + momentum5;
   
  momentumo = alpha*dWo + beta*momentumo;
  Wo        = Wo + momentumo;  
end

end



2、测试文件-TestMnistConv-计算卷积神经网络输出结果的正确率

clear all

Images = loadMNISTImages('E:\code_matlab\matlab_kim\ch.6\MNIST\t10k-images.idx3-ubyte');
Images = reshape(Images, 28, 28, []);
Labels = loadMNISTLabels('E:\code_matlab\matlab_kim\ch.6\MNIST\t10k-labels.idx1-ubyte');
Labels(Labels == 0) = 10;    % 0 --> 10

rng(1);

% 训练数据进行学习
%
W1 = 1e-2*randn([9 9 20]);
W5 = (2*rand(100, 2000) - 1) * sqrt(6) / sqrt(360 + 2000);
Wo = (2*rand( 10,  100) - 1) * sqrt(6) / sqrt( 10 +  100);

X = Images(:, :, 1:8000);
D = Labels(1:8000);

for epoch = 1:3
  epoch();
  [W1, W5, Wo] = MnistConv(W1, W5, Wo, X, D);
end

save('MnistConv.mat');


% 测试部分
%
X = Images(:, :, 8001:10000);       %训练数据部分
D = Labels(8001:10000);             %验证数据部分

acc = 0;
N   = length(D);
for k = 1:N
  x = X(:, :, k);                   % 输入 28x28 的原始图像

  y1 = Conv(x, W1);                 % 卷积层(卷积滤波器)处理后,输出20个20x20的图像
  y2 = ReLU(y1);                    %
  y3 = Pool(y2);                    %y3矩阵重排列,转换成1列多行的矩阵
  y4 = reshape(y3, [], 1);          %                   
  v5 = W5*y4;                       % 
  y5 = ReLU(v5);                    %
  v  = Wo*y5;                       %代入激活函数Softmax,          10x1
  y  = Softmax(v);                  %

  %比较网络的输出和标注输出,并计数匹配的结果
  [~, i] = max(y);                  %将10x1的向量输出转换回一个数字
  if i == D(k)                      %将其和给定的标准输出进行比较
    acc = acc + 1;
  end
end

acc = acc / N;                      %计算卷积神经网络输出结果的正确率
fprintf('Accuracy is %f\n', acc);




3、屏幕显示输出-display_network-将矩阵显示在屏幕上

function [h, array] = display_network(A, opt_normalize, opt_graycolor, cols, opt_colmajor)

%此功能可将矩阵A中的过滤器可视化,将矩阵显示在屏幕上。
%A的每一列都是一个过滤器。 
%我们将每列重塑为正方形图像,并在可视化面板的每个单元上进行可视化。
%opt_normalize:是否需要标准化过滤器,以使所有过滤器具有相似的对比度。 默认值为true。
%opt_graycolor:是否使用灰色作为热图。 默认为true。
%列:显示屏中有几列。 默认值为A中列数的平方根。
%opt_colmajor:您可以将约定切换为A的行专业。
%在这种情况下,A的每一行都是一个过滤器。 默认值为false。

warning off all %不显示警告信息

if ~exist('opt_normalize', 'var') || isempty(opt_normalize)
    opt_normalize= true;
end

if ~exist('opt_graycolor', 'var') || isempty(opt_graycolor)
    opt_graycolor= true;
end

if ~exist('opt_colmajor', 'var') || isempty(opt_colmajor)
    opt_colmajor = false;
end

% rescale
%重新缩放
A = A - mean(A(:));

if opt_graycolor, colormap(gray); end

% compute rows, cols
%计算行,列
[L, M]=size(A);
sz=sqrt(L);
buf=1;
if ~exist('cols', 'var')
    if floor(sqrt(M))^2 ~= M
        n=ceil(sqrt(M));
        while mod(M, n)~=0 && n<1.2*sqrt(M), n=n+1; end
        m=ceil(M/n);
    else
        n=sqrt(M);
        m=n;
    end
else
    n = cols;
    m = ceil(M/n);
end

array=-ones(buf+m*(sz+buf),buf+n*(sz+buf));

if ~opt_graycolor
    array = 0.1.* array;
end


if ~opt_colmajor
    k=1;
    for i=1:m
        for j=1:n
            if k>M 
                continue; 
            end
            clim=max(abs(A(:,k)));
            if opt_normalize
                array(buf+(i-1)*(sz+buf)+(1:sz),buf+(j-1)*(sz+buf)+(1:sz))=reshape(A(:,k),sz,sz)/clim;
            else
                array(buf+(i-1)*(sz+buf)+(1:sz),buf+(j-1)*(sz+buf)+(1:sz))=reshape(A(:,k),sz,sz)/max(abs(A(:)));
            end
            k=k+1;
        end
    end
else
    k=1;
    for j=1:n
        for i=1:m
            if k>M 
                continue; 
            end
            clim=max(abs(A(:,k)));
            if opt_normalize
                array(buf+(i-1)*(sz+buf)+(1:sz),buf+(j-1)*(sz+buf)+(1:sz))=reshape(A(:,k),sz,sz)/clim;
            else
                array(buf+(i-1)*(sz+buf)+(1:sz),buf+(j-1)*(sz+buf)+(1:sz))=reshape(A(:,k),sz,sz);
            end
            k=k+1;
        end
    end
end

if opt_graycolor
    h=imagesc(array,'EraseMode','none',[-1 1]);
else
    h=imagesc(array,'EraseMode','none',[-1 1]);
end
axis image off

drawnow;

warning on all


4、卷积滤波器矩阵-Conv(x, W)

function y = Conv(x, W)
%Conv函数接收输入图像和卷积滤波器矩阵,并返回特征映射图。
%
[wrow, wcol, numFilters] = size(W);
[xrow, xcol, ~         ] = size(x);
    %将矩阵W的行数返回到输出变量wrow,将矩阵W的列数返回到输出变量wcol。
    %将矩阵x的行数返回到输出变量xrow,将矩阵x的列数返回到输出变量xcol。
yrow = xrow - wrow + 1;
ycol = xcol - wcol + 1;

y = zeros(yrow, ycol, numFilters);      %生成全零矩阵y
for k = 1:numFilters
  filter = W(:, :, k);                  %第k层W矩阵
  filter = rot90(squeeze(filter), 2);
             %squeeze,除去size为1的维度,获得一个二维的矩阵
             %将矩阵(图片)旋转2个90度
  y(:, :, k) = conv2(x, filter, 'valid');
              %用matlab内置的二维卷积函数--conv函数执行卷积计算
              %x(:, :, k):第k层x矩阵
              %valid 返回在卷积过程中,未使用边缘补0部分进行计算的卷积结果部分
              %image 的结果是一个2*2矩阵
end

end



5、平均池化层- Pool(x)- 2x2子矩阵进行平均池化

function y = Pool(x)
% 2x2子矩阵进行平均池化    
% 
[xrow, xcol, numFilters] = size(x);
%xrow:行
%xcol:列
%numFilters:滤波器个数

y = zeros(xrow/2, xcol/2, numFilters); %生成全零矩阵y
for k = 1:numFilters
  filter = ones(2) / (2*2);  %卷积滤波器,2*2的矩阵(元素为0.25)  
                             %池化层的滤波器filter值是预定义的。
  image  = conv2(x(:, :, k), filter, 'valid');
           %x(:, :, k):第k层x矩阵
           %conv2函数:二维卷积函数
           %valid 返回在卷积过程中,未使用边缘补0部分进行计算的卷积结果部分
           %image 的结果是一个2*2矩阵
  y(:, :, k) = image(1:2:end, 1:2:end);
           %每层(k层)2*2矩阵分别赋值
end

end
 

6、绘图函数-PlotFeatures


warning off all %不显示警告信息
clear all
load('MnistConv.mat')
k  = 32;
x  = X(:, :, k);
y1 = Conv(x, W1);                 % 卷积层Convolution,20张20x20的图像
y2 = ReLU(y1);                    %
y3 = Pool(y2);                    % 池化层Pool,输出20张10x10的图像
y4 = reshape(y3, [], 1);          %  转换成一维数据,2000个像素点  
v5 = W5*y4;                       % ReLU转化,
y5 = ReLU(v5);                    %去除非正值,明显化特征(去除图中黑色区域,灰度化) 
v  = Wo*y5;                       % 代入激活函数Softmax函数,
y  = Softmax(v);                  %
  

figure;                          
display_network(x(:));             %显示输入图像
title('Input Image')               %显示输入图像

convFilters = zeros(9*9, 20);     %初始化全零矩阵
for i = 1:20
  filter            = W1(:, :, i);
  convFilters(:, i) = filter(:);
end
figure                            
display_network(convFilters);      %显示经神经网络训练确定的卷积滤波器
title('Convolution Filters')     

fList = zeros(20*20, 20);           %初始化全零矩阵
for i = 1:20
  feature     = y1(:, :, i);
  fList(:, i) = feature(:);
end
figure                            %创建新窗口
display_network(fList);           %显示卷积滤波器处理的结果(特征图像)
title('Features [Convolution]')   

fList = zeros(20*20, 20);         %初始化全零矩阵
for i = 1:20
  feature     = y2(:, :, i);
  fList(:, i) = feature(:);
end
figure                              %创建新窗口
display_network(fList);             %显示特征图像经ReLU处理后的图像
title('Features [Convolution + ReLU]')

fList = zeros(10*10, 20);           %初始化全零矩阵
for i = 1:20
  feature     = y3(:, :, i);
  fList(:, i) = feature(:);
end
figure                                %创建新窗口
display_network(fList);               %显示卷积神经网络的最终输出图像
title('Features [Convolution + ReLU + MeanPool]')
                    %生成的图像被转换成一个一维向量,并存储在分类神经网络中。



7、线性整流函数-ReLU(x)-解决梯度消失问题

function y = ReLU(x)
  y = max(0, x);
end
%ReLU函数,线性整流函数,传递误差,解决梯度消失的问题。
%笔记位置,第5章-5.1-深度神经网络的改进

8、产生伪随机数-rng(x)

function rng(x)
  %rand和randn都是用来产生伪随机数的,发生器为'seed';
  randn('seed', x)
  rand('seed', x)
  %matlab推荐使用 %rng(0);代替使用randn('seed',0); 
        %更换的理由见笔记:matlab:rand('seed',sd)-伪随机数
end

9、深度神经网络所用冲激函数-Softmax(x)

function y = Softmax(x)
  ex = exp(x);
  y  = ex / sum(ex);
end
%激活函数softmax不仅考虑输入输入的加权和,还考虑其他输入节点的输入。
%详细公式见笔记-第4章-4.2-多元分类

10、实验现象

图像含义见绘图函数-PlotFeatures.

在此仅列出-深度神经网络训练函数MnistConv的训练结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


11、一些说明:

1、导入导出图像路径的函数,本文并未列出。

2、完整工程文件,详见参考书,本文仅供学习参考。

3、参考书源代码下载地址:Apress网站.

//水平有限,能者见笑,大家见谅。

发布了18 篇原创文章 · 获赞 73 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43499622/article/details/103556642