神经网络的学习
一、理论基础
1. 代价函数
假设神经网络的训练样本有𝑚个,每个包含一组输入𝑥和一组输出信号𝑦,𝐿表示神经网络层数,𝑆𝐼表示每层的 neuron 个数(𝑆𝑙表示输出层神经元个数),𝑆𝐿代表最后一层中处理单元的个数。
将神经网络的分类定义为两种情况:二类分类和多类分类
regularized logistic regression cost function:
在神经网络中,我们可以有很多输出变量,我们的ℎ𝜃(𝑥)是一个维度为𝐾的向量,并且我们训练集中的因变量也是同样维度的一个向量,因此代价函数会比逻辑回归更加复杂,为:
2. 反向传播算法
梯度下降可以应对带有明确求导函数的情况,或者说可以应对那些可以求出误差的情况,比如逻辑回归(Logistic Regression),我们可以把它看做没有隐层的网络;但对于多隐层的神经网络,输出层可以直接求出误差来更新参数,但其中隐层的误差是不存在的,因此不能对它直接应用梯度下降,而是先将误差反向传播至隐层,然后再应用梯度下降,其中将误差从末层往前传递的过程需要链式法则(Chain Rule)的帮助,因此反向传播算法可以说是梯度下降在链式法则中的应用。
为了计算代价函数的偏导数
我们需要采用一种反向传播算法,也就是,首先计算最后一层的误差,然后再一层一层反向求出各层的误差,直到倒数第二层。“反向传播”是用于最小化成本函数的神经网络术语,就像我们在Logistic和线性回归中进行梯度下降一样。
前向传播算法:
a(1)是第一层的激活值在这里实现了将前向传播向量化,使得可以计算神经网络结构里的每一个神经元的激活值。
从最后一层的误差开始计算,误差是激活单元的预测值ak(4)与实际值y(k)之间的误差𝛿,(𝑘 = 1:𝑘)。
用𝛿来表示误差,则:
注:没有𝛿(1),因为第一层是输入变量,不存在误差。
假设𝜆 = 0,即我们不做任何正则化处理时有:
𝑙 代表目前所计算的是第几层。
𝑗 代表目前计算层中的激活单元的下标,也将是下一层的第𝑗个输入变量的下标。
𝑖 代表下一层中误差单元的下标,是受到权重矩阵中第𝑖行影响的下一层中的误差单元的下标。
3. 展开参数
解释:theta和D都是10×11的矩阵,可以使用命令thetaVec=[Theta1(😃;Theta2(😃;Theta3(😃];将矩阵转换成一个很长的向量,其中Theta1(:)表示取Theta1中的所有元素,最后可以用reshape函数将一行向量转换成原来的矩阵。
4.梯度检验
对一个较为复杂的模型(例如神经网络)使用梯度下降算法时,可能会存在一些不容易察觉的错误,即虽然代价看上去在不断减小,但最终的结果可能并不是最优解。为了避免这样的问题,我们采取一种叫做梯度的数值检验(Numerical Gradient Checking)方法。这种方法的思想是通过估计梯度值来检验我们计算的导数值是否真的是我们要求的。
对于实数θ:
对于θ为向量参数的情况:
实现代码:
数值上的梯度检验实现步骤:
1.通过反向传播来计算DVec,展开D(1),D(2)···
2.实现数值上的梯度检验,计算出gradApprox(梯度近似)
3.确保gradApprox≈DVec
4.在使用代码进行学习或训练网络之前,重要的是要关掉梯度检验,因为梯度检验代码程序很大,运行的很慢 。
数值上的梯度检验可以验证反向传播算法是否正确。
5.随机初始化
任何优化算法都需要一些初始的参数。到目前为止我们都是初始所有参数为 0,这样的初始方法对于逻辑回归来说是可行的,但是对于神经网络来说是不可行的。如果我们令所有的初始参数都为 0,这将意味着我们第二层的所有激活单元都会有相同的值。
初始化为0的情况:
通常初始参数为正负之间的随机值:
训练神经网络需要实现的步骤:
1.构建一个神经网络,随机初始化权重,通常将权重初始化很小的值,接近0
2.执行前向传播算法,计算出对应的值
3.通过代码计算出代价函数J(θ)
4.执行反向传播算法计算出偏导数项,用for循环完成
5.使用梯度检验检查计算得到的偏导项,将反向传播算法得到的偏导项与数值检验得到的结果进行比较,然后停用梯度检验
6.使用优化算法,比如梯度下降等,和反向传播算法相结合计算偏导项的值
二、编程作业
1.sigmoidGradient.m(Compute the gradient of the sigmoid function):implement the sigmoid gradient function
The gradient for the sigmoid function can be computed as:
function g = sigmoidGradient(z)
g = zeros(size(z));
%g = SIGMOIDGRADIENT(z)
g=sigmoid(z).*(1-sigmoid(z));
end
2.randInitializeWeights.m (Randomly initialize weights)
ex4文档中已给出代码:
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;
end
3. nnCostFunction.m(Neural network cost function):part1: Feedforward the neural network and return the cost in the variable
J.
part2: Implement the backpropagation algorithm to compute the gradients Theta1_grad and Theta2_grad.
Part3: Implement regularization with the cost function and gradients.
the cost function for the neural network (without regularization):
反向传播(Backpropagation)
function [J grad] = nnCostFunction(nn_params, ...
input_layer_size, ...
hidden_layer_size, ...
num_labels, ...
X, y, lambda)
% for our 2 layer neural network
%用reshape函数将向量转换成矩阵
Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...
hidden_layer_size, (input_layer_size + 1));
Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...
num_labels, (hidden_layer_size + 1));
% Setup some useful variables
m = size(X, 1);
% You need to return the following variables correctly
J = 0;
Theta1_grad = zeros(size(Theta1));
Theta2_grad = zeros(size(Theta2));
%part1,实现前向传播算法,题目告诉只有3层,输入,隐藏,输出
X = [ones(m,1) X]; % a1加一列偏置项,值全为1
z2 = X * Theta1';
a2 = sigmoid(z2); % 计算a2
a2 = [ones(m,1) a2]; % a2添加一列偏置项,值全为1
z3 = a2 * Theta2';
a3 = sigmoid(z3); % 计算a3
%计算代价J
yk=zeros(m,num_labels);%5000×10的初始值
for i=1:m
yk(i,y(i))=1;%得到修改后用于公式中的0/1矩阵
end
%神经网络的代价函数公式(未正则化时)
J=(-1/m)*sum(sum(yk.*log(a3)+(1-yk).*log(1-a3)));
%正则项reg
regularization=(lambda/(2*m))*(sum(sum(Theta1(:,2:end).^2))+sum(sum(Theta2(:,2:end).^2)));
J=J+regularization;
%%%
%part2 实现反向传播算法
%Delta表示大写的Δ,delta表示小写的δ
for t=1:m
a1=X(t,:);
a1=a1';
z2=Theta1*a1;
a2=[1;sigmoid(z2)];
z3=Theta2*a2;
a3=sigmoid(z3);
y=yk(t,:);
delta3=a3-y';
delta2=Theta2(:,2:end)'*delta3.*sigmoidGradient(z2);
%%%
Theta1_grad=Theta1_grad+delta2*a1';
Theta2_grad=Theta2_grad+delta3*a2';
end
Theta1_grad=Theta1_grad./m;
Theta2_grad=Theta2_grad./m;
%正则化
Theta1(:,1)=0;
Theta2(:,1)=0;
Theta1_grad=Theta1_grad+lambda/m*Theta1;
Theta2_grad=Theta2_grad+lambda/m*Theta2;
% Unroll gradients
grad = [Theta1_grad(:) ; Theta2_grad(:)];
end