第一部分 神经网络
题目介绍:使用反向传播实现手写数字识别
数据集与上一次作业相同
1.数据可视化
与上一次作业相同
2.神经网络模型
这里的内容也与上一次作业相同。
3.前馈和损失函数
神经网络的损失函数公式:
h_θ(x)就是模型中的输出,手写数字分为十类所以K=10,原本的标签维度是(5000,1),需要转化为(5000,10)才能够参与运算,若标签是n,则将第n行置1,其余行置0。
%将y转化为10*5000的矩阵
ylabel = zeros(num_labels, m);
for i = 1:m
ylabel(y(i), i) = 1; %原本的标签是1到10,转化后用第y(i)行置1表示
end
由于需要得到网络模型的输出,所以还是要先完成前向传播。
% 计算假设函数
a1 = [ones(m, 1) X]; % 5000*401
z2 = a1 * Theta1';
a2 = sigmoid(z2);
a2 = [ones(m, 1) a2]; % 5000*26
z3 = a2 * Theta2';
a3 = sigmoid(z3);
h = a3; % 5000*10
4.正则化损失函数
公式:
虽然这里的网络模型只有三层,但是我们编写的代码应该满足与任何层数的神经网络,此外,虽然θ_1和θ_2都已经给出,但代码也应该满足任何大小的theta。
J = 1 / m * sum( sum( -ylabel'.* log(h) - (1-ylabel').*log(1-h) ));
% 对X添加一列
X = [ones(m,1) X];
%正则化,注意theta1(1)和theta(0)不参与正则化
reg = lambda / (2*m) * (sum(sum(Theta1(:,2:end).^2)) + sum(sum(Theta2(:,2:end).^2)))
J = J + reg
第二部分 反向传播
实现反向传播计算神经网络损失函数的梯度。再使用fmincg函数优化参数θ。
1.sigmoid函数的梯度:
g = sigmoid(z) .* (1 - sigmoid(z));
2.随机初始化
训练神经网络时,随机初始化参数是很重要的,一种随机出花策略是在一定范围内随机选择θ的值。
epsilon_init = 0.12;
W = rand(L_out, 1 + L_in) * 2 * epsilon_init - epsilon_init;
3.反向传播
我们需要计算激活项(我们计算的每一层的输出)与真实值的误差δ。
1.利用前向传播得到a1,z2,a2,z3.a3
2.对于输出层:
3.对于隐藏层(第二层):
4.计算梯度,注意δ_0不参与运算
5.获得神经网络损失函数的梯度
6.梯度检查
展开θ:
代码已给出,但是看不太懂。。。
7.正则化神经网络
为梯度添加正则化项
θ的第一列(偏置项)不参与正则化。
delta_3 = a3 - ylabel'; % 5000*10
delta_2 = delta_3 * Theta2; % 5000*26
delta_2 = delta_2(:,2:end); % 5000*25
delta_2 = delta_2 .* sigmoidGradient(z2); %5000*25
%计算梯度
Delta_1 = zeros(size(Theta1));
Delta_2 = zeros(size(Theta2));
Delta_1 = Delta_1 + delta_2' * a1; % 26*401
Delta_2 = Delta_2 + delta_3' * a2; % 10*26
%正则化
Theta1_grad = 1/m * Delta_1 + lambda/m * Theta1;
Theta2_grad = 1/m * Delta_2 + lambda/m * Theta2;
% 第0项,也就是第一列元素不需要正则化,这里把第一列还原
Theta1_grad(:,1) -= lambda/m * Theta1(:,1);
Theta2_grad(:,1) -= lambda/m * Theta2(:,1);