机器学习吴恩达作业题4——神经网络

1、神经网络

在上一个练习中,您实现了神经网络的前馈传播,并使用它来预测我们提供的权重手写数字。在本练习中,您将实现反向传播算法来学习神经网络的参数。

1.1可视化数据

复制ex4data1文件到D:\Machine Learning\ex4目录下,在当前目录下建立displayData.m文件,用来可视化数据。具体实现参照前一次作业的函数实现。

Octave中的操作:

  1. 加载数据集,给相应的变量赋值。
  2. 随机抽取100个个例,调用displayData.m进行相应的图形绘制。
    机器学习吴恩达作业题4——神经网络_第1张图片
    机器学习吴恩达作业题4——神经网络_第2张图片

1.2模型表示

我们已经为您提供了一套我们已经培训过的网络参数(Θ(1),Θ(2)),这些存储在ex4weights文件中,将该文件复制到当前目录下。

Octave中的操作:
将该数据集加载,将Theta1和Theta2矩阵上下结合成为一个新矩阵。
在这里插入图片描述

1.3、前向、后向传播求成本函数和梯度

先编写前向传播的成本函数,在当前目录下建立nnCostFunction文件,该函数中也实现了后向传播函数的相关算法,并返回相应的梯度:

function [J grad] = nnCostFunction(nn_params, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, ...
                                   X, y, lambda)
%返回grad 和J                                  
%第一个参数就是合并的矩阵,第二个参数值为400,第三个参数值为25,第四个参数值为10,最后一个代表λ                                  
Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...
                 hidden_layer_size, (input_layer_size + 1));
%将Theta1矩阵还原成20*401
Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...
                 num_labels, (hidden_layer_size + 1));
%将Theta1矩阵还原成10*26
m = size(X, 1);
J = 0;
Theta1_grad = zeros(size(Theta1));
Theta2_grad = zeros(size(Theta2));
delta_2 = zeros(hidden_layer_size, 1); 
%25*1    
delta_3 = zeros(num_labels, 1);   
%10*1          
delta_1_sum = zeros(size(Theta1));   
%25*1       
delta_2_sum = zeros(size(Theta2));          
%10*1
X = [ones(m,1) X];
%加上常数项
for i = 1: m,
H = sigmoid(Theta2 * [ones(1,1) ; sigmoid(Theta1 * X(i, :)')]);
%运用前向传播算法,算出一个计算后的y值,即第i行y值,这里共5000行
yi = zeros(num_labels, 1);
%10*1
yi(y(i)) = 1;
%原始标签(变量y中)是12,…,10,为了训练神经网络,我们需要将标签重新编码为只包含值01的向量。
%如果y(i)是数字5,那么对应的yi应该是一个10维向量,y5=1,其他元素等于0。
J_i = sum(log(H) .* ( -yi) - (1 - yi) .* log(1 - H));
J = J + J_i;
delta_3 = H - yi;
delta_2 = (Theta2(:,2:end)' * delta_3) .* sigmoidGradient(Theta1 * X(i, :)');
%δ矩阵
delta_1_sum = delta_1_sum + delta_2 * X(i, :);
delta_2_sum = delta_2_sum + delta_3 * [ones(1,1) ; sigmoid(Theta1 * X(i, :)')]';
%Theta2(:,2:end)'矩阵去掉了常数列,因此得到的只有25行,求得∆(l) 
end;
J = J / m;
%乘以系数m分之一,最终得到非正规化的成本函数值
Theta1_grad = delta_1_sum ./ m + lambda * Theta1 ./ m;
Theta1_grad(:,1) = delta_1_sum(:,1) ./ m;
Theta2_grad = delta_2_sum ./ m + lambda * Theta2 ./ m;
Theta2_grad(:,1) = delta_2_sum(:,1) ./ m;
%求得两个Theta矩阵对应的梯度矩阵
Theta1_i = Theta1(:,2:(input_layer_size + 1));
Theta1_i = Theta1_i .^ 2;
Theta2_i = Theta2(:,2:(hidden_layer_size + 1));
Theta2_i = Theta2_i .^ 2;
J = J + lambda / 2 / m * (sum(sum(Theta1_i)) + sum(sum(Theta2_i)));
%求得正规化的成本函数值
grad = [Theta1_grad(:) ; Theta2_grad(:)];
end
  1. yi = zeros(num_labels, 1); yi(y(i)) = 1; J_i = sum(log(H) .* ( -yi) - (1 - yi) .* log(1 - H)); J = J + J_i;是为了实现下图数学公式:
    在这里插入图片描述
    机器学习吴恩达作业题4——神经网络_第3张图片
  2. delta_3 = H - yi;
    delta_2 = (Theta2(:,2:end)’ * delta_3) .* sigmoidGradient(Theta1 * X(i, :)’);这两行代码是为了实现以下数学等式,第二行代码中Theta2(:,2:end)'矩阵去掉了常数列,因此得到的只有25行:
    在这里插入图片描述
    机器学习吴恩达作业题4——神经网络_第4张图片
    sigmoidGradient函数是对sigmoid函数求导的具体实现,在当前目录下建立sigmoidGradient.m文件和sigmoid.m,实现该功能:
function g = sigmoidGradient(z)
g = (1 ./ (exp(-z) + 1)) .* (1 - 1 ./ (exp(-z) + 1));
end
  1. 求得梯度矩阵:
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

  2. 求得正规化的成本函数值:
    机器学习吴恩达作业题4——神经网络_第5张图片
    Octave中的操作:
    设置λ值,调用nnCostFunction函数求出对应的梯度。
    机器学习吴恩达作业题4——神经网络_第6张图片

2、反向传播

2.1随机初始化

在当前目录下建立randInitializeWeights.m文件,以初始化Θ的权重:

function W = randInitializeWeights(L_in, L_out)
W = zeros(L_out, 1 + L_in);
epsilon_init=0.12;
W = rand(L_out, 1 + L_in) * 2 * epsilon_init - epsilon_init;
%随机初始一个尺寸为 L_out×1 + L_in 的参数矩阵,我们通常初始epsilon_init为正负之间的随机值
end

Octave中初始化Θ矩阵:
在这里插入图片描述

2.2坡度检查

机器学习吴恩达作业题4——神经网络_第7张图片
近似于该点处代价函数的导数:
在这里插入图片描述
在当前目录下建立checkNNGradients.m文件,完成坡度检查工作,主要根据相对差异的大小来判断检查nnCostFunction中反向传播算法是否正确。在该文件中需要调用debugInitializeWeights函数和computeNumericalGradient函数,首先完成这两个函数的实现。

在当前目录下建立debugInitializeWeights.m文件,它将创建一个小的神经网络和数据集,用于检查渐变。如果您的反向传播实现是正确的,您应该看到一个小于1e-9的相对差异:

function W = debugInitializeWeights(fan_out, fan_in)
%随机产生一个数据矩阵fan_out*fan_in
W = zeros(fan_out, 1 + fan_in);
W = reshape(sin(1:numel(W)), size(W)) / 10;
%矩阵元素值很小,值为sinx/10,numel(W)计算矩阵元素个数。
end

在当前目录下建立computeNumericalGradient.m文件,它主要用来实现上面的两个数学表达式,计算出公式产生的梯度;

function numgrad = computeNumericalGradient(J, theta)
%返回numel(theta)*1的矩阵,每一个元素对应相应Θ的相对差异的大小
numgrad = zeros(size(theta));
perturb = zeros(size(theta));
e = 1e-4;
for p = 1:numel(theta)
    perturb(p) = e;
    loss1 = J(theta - perturb);
    loss2 = J(theta + perturb);
    numgrad(p) = (loss2 - loss1) / (2*e);
    perturb(p) = 0;
end
end

checkNNGradients.m文件:

function checkNNGradients(lambda)
%参数就是λ
if ~exist('lambda', 'var') || isempty(lambda)
    lambda = 0;
end
%如果没有设置λ,就设置它为0
input_layer_size = 3;
hidden_layer_size = 5;
num_labels = 3;
m = 5;
Theta1 = debugInitializeWeights(hidden_layer_size, input_layer_size);
Theta2 = debugInitializeWeights(num_labels, hidden_layer_size);
X  = debugInitializeWeights(m, input_layer_size - 1);
%debugInitializeWeights主要作用就是随机产生一些数据来组成相应的矩阵,用于检查渐变
y  = 1 + mod(1:m, num_labels)';
nn_params = [Theta1(:) ; Theta2(:)];
costFunc = @(p) nnCostFunction(p, input_layer_size, hidden_layer_size, ...
                               num_labels, X, y, lambda);
[cost, grad] = costFunc(nn_params);
numgrad = computeNumericalGradient(costFunc, nn_params);
%产生数字梯度的矩阵,由公式计算出来的
disp([numgrad grad]);
%输出二者组合形成的矩阵,来看公式计算出来的梯度和nnCostFunction计算出来的梯度有什么不同
%应该是近乎等于
diff = norm(numgrad-grad)/norm(numgrad+grad);
end

Octave中的操作:
机器学习吴恩达作业题4——神经网络_第8张图片
可以看到用公式计算出的梯度与反向传播算法计算出的梯度基本一致,说明反向传播算法正确。

使用正则化的反向传播算法进行梯度检验:
机器学习吴恩达作业题4——神经网络_第9张图片

2.3使用fmincg学习(优化)参数

使用fmincg学习一个好的设置参数。如果您的实现是正确的,您应该看到报告的训练准确率约为95.3%(由于随机初始化,这可能会有大约1%的变化)。通过对神经网络进行多次迭代训练,可以获得更高的训练精度。我们鼓励您尝试训练神经网络进行更多迭代(例如,将MaxIter设置为400),并改变正则化参数λ。有了正确的学习设置,就有可能使神经网络完全适合训练集。

同时还可以可视化隐藏层:displayData(Theta1(:, 2:end));

由于用到预测函数,在当前目录下建立predict.m文件和fmincg.m文件

Octave中的操作:
机器学习吴恩达作业题4——神经网络_第10张图片
在这里插入图片描述
预测成功的概率为94.820%
机器学习吴恩达作业题4——神经网络_第11张图片
上图就是隐藏层的可视化。

你可能感兴趣的:(机器学习吴恩达(基础))