基于多层神经网络的手写数字图像识别问题(MATLAB实现)

版权声明:欢迎转载 https://blog.csdn.net/suntengnb/article/details/83820484

问题描述:
给出若干5×5的图像,作为训练样本。要求训练一个输入层含25个神经元,隐含层含50个神经元,输出层含5个神经元的神经网络,其中隐含层的激活函数为Sigmoid,输出层的激活函数为Softmax,代价函数采用均方误差函数
主函数代码:

% bp.m
clc
clear
run('data_bp.m');% 载入样本
M = 5;% 样本个数
D = 25;% 输入层的神经元个数
Q = 50;% 隐含层的神经元个数
L = 5;% 输出层的神经元个数
% 随机初始化各参数
v = 2 * rand(D,Q) - 1;% 输入层到隐含层的权值为v(v_ih,25×50)
w = 2 * rand(Q,L) - 1;% % 隐含层到输出层的权值为w(w_hj,50×5)
gamma = 2 * rand(Q,1) - 1;% 隐含层的阈值为gamma(gamma_h,50×1)
theta = 2 * rand(L,1) - 1;% 输出层的阈值为theta(theta_j,5,1)
eta = 0.1;% 学习率,默认为0.1
for epoch = 1 : 20000% 迭代10000次
    for k = 1 : M% 第k个样本
        xk = x(:,k);% 输入层神经元接收到的输入,列向量
        y_real = y(:,k);% 当前样本的真实标记,列向量
        alpha = (xk' * v)';% 隐含层神经元接收到的输入,Q×1列向量
        b = sigmoid(alpha - gamma);% 隐含层神经元的输出,列向量
        beta = (b' * w)';% 输出层神经元接收到的输入,L×1列向量
        y_pred = softmax(beta - theta);% 输出层神经元的输出,列向量
        Err = sum((y_real - y_pred).^2) / 2;% 均方误差
        run('up_date.m');
    end
end
save('parameters.mat','w','v','theta','gamma');% 保存参数
Err
% bp_test.m
clc
clear
close all
run('data_bp_test.m');% 载入样本
M = 5;% 样本个数
D = 25;% 输入层的神经元个数
Q = 50;% 隐含层的神经元个数
L = 5;% 输出层的神经元个数
% 载入训练所得参数
load('parameters.mat');
for k = 1 : M% 第k个样本
    xk = x_test(:,k);% 输入层神经元接收到的输入,列向量
    alpha = (xk' * v)';% 隐含层神经元接收到的输入,Q×1列向量
    b = sigmoid(alpha - gamma);% 隐含层神经元的输出,列向量
    beta = (b' * w)';% 输出层神经元接收到的输入,L×1列向量
    y_pred = softmax(beta - theta)% 输出层神经元的输出,列向量
    [val,id] = max(y_pred);% 下标id即为预测的数字
    Str = ['第',num2str(k),'个样本的预测结果为数字:',num2str(id)];
    disp(Str);
end

辅助函数:

% data_bp.m
t = [0,1,1,0,0;
     0,0,1,0,0;
     0,0,1,0,0;
     0,0,1,0,0;
     0,1,1,1,0];
t(:,:,2) = [1,1,1,1,0;
            0,0,0,0,1;
            0,1,1,1,0;
            1,0,0,0,0;
            1,1,1,1,1];
t(:,:,3) = [1,1,1,1,0;
            0,0,0,0,1;
            0,1,1,1,0;
            0,0,0,0,1;
            1,1,1,1,0];
t(:,:,4) = [0,0,0,1,0;
            0,0,1,1,0;
            0,1,0,1,0;
            1,1,1,1,1;
            0,0,0,1,0];
t(:,:,5) = [1,1,1,1,1;
            1,0,0,0,0;
            1,1,1,1,0;
            0,0,0,0,1;
            1,1,1,1,0];
% for i = 1 : 5
%     figure;
%     imshow(~t(:,:,i));
% end
x = [];
for i = 1 : 5
    x = [x,reshape(t(:,:,i),25,1)];% 将5×5矩阵展成列向量,第k个样本的属性向量为x(:,k);
end
clear t i
y = eye(5);% 标签,第k个样本的标签为y(:,k),列向量
%data_bp_test.m
clc
clear
close all
run('data_bp_test.m');% 载入样本
M = 5;% 样本个数
D = 25;% 输入层的神经元个数
Q = 50;% 隐含层的神经元个数
L = 5;% 输出层的神经元个数
% 载入训练所得参数
load('parameters.mat');
for k = 1 : M% 第k个样本
    xk = x_test(:,k);% 输入层神经元接收到的输入,列向量
    alpha = (xk' * v)';% 隐含层神经元接收到的输入,Q×1列向量
    b = sigmoid(alpha - gamma);% 隐含层神经元的输出,列向量
    beta = (b' * w)';% 输出层神经元接收到的输入,L×1列向量
    y_pred = softmax(beta - theta)% 输出层神经元的输出,列向量
    [val,id] = max(y_pred);% 下标即为预测的数字
    Str = ['第',num2str(k),'个样本的预测结果为数字:',num2str(id)];
    disp(Str);
end
%sigmoid.m
function ret = sigmoid(x)
    ret = 1 ./ (1 + exp(-x));
end
%softmax.m
function ret = softmax(v)
    v = v / sum(exp(v));
    ret = v;
end
%g.m
function ret = g(y,yhat)
    ret = yhat * (1 - yhat) * (y - yhat);% 公式(5.10)
end
%e.m
function ret = e(b,h,L,w,y_real,y_pred)
    tot = 0;
    for j = 1 : L
        tot = tot + w(h,j) * g(y_real(j),y_pred(j));
    end
    ret = b(h) * (1 - b(h)) * tot;% 公式(5.15)
end
up_date.m
% 误差 逆 传播
% 计算各delta
delta_w = zeros(Q,L);% 
for h = 1 : Q
    for j = 1 : L
        delta_w(h,j) = eta * g(y_real(j),y_pred(j)) * b(h);% 公式(5.11)
    end
end
delta_theta = zeros(L,1);
for j = 1 : L
    delta_theta(j) = -eta * g(y_real(j),y_pred(j));% 公式(5.12)
end
delta_v = zeros(D,Q);
for i = 1 : D
    for h = 1 : Q
        delta_v(i,h) = eta * e(b,h,L,w,y_real,y_pred) * xk(i);% 公式(5.13)
    end
end
delta_gamma = zeros(Q,1);
for h = 1 : Q
    delta_gamma = -eta * e(b,h,L,w,y_real,y_pred);% 公式(5.14)
end
% 同步更新
w = w + delta_w;
theta = theta + delta_theta;
v = v + delta_v;
gamma = gamma + delta_gamma;

说明:
以上代码参考西瓜书5.2节实现
迭代10000次,对比发现使用softmax函数作为输出层激活函数的效果不如使用sigmoid函数好

猜你喜欢

转载自blog.csdn.net/suntengnb/article/details/83820484