斯坦福机器学习Coursera课程:第四周作业--人工神经网络
根据课程内容,先简要说下神经网络的基本思想和步骤:
其实神经网络就像是logistic regression,只不过我们把logistic regression中的输入向量[x1~x3]变成了中间层的[a(2)1~a(2)3], 即
h(x)=g(θ(2)0a(2)0+θ(2)1a(2)1+θ(2)2a(2)2+θ(2)3a(2)3)
我们可以把a0,a1,a2,a3看成更为高级的特征值,也就是x0,x1,x2,x3的进化体,并且它们是由x与决定的,因为是梯度下降的,所以a是变化的,并且变得越来越厉害,所以这些更高级的特征值远比仅仅将x次方厉害,也能更好的预测新数据。这就是神经网络相比于逻辑回归和线性回归的优势。
从本质上讲,神经网络能够通过学习得出其自身的一系列特征。在普通的逻辑回归中,我们被限制为使用数据中的原始特征x1,x2,...,xn,我们虽然可以使用一些二项式项来组合这些特征,但是我们仍然受到这些原始特征的限制。在神经网络中,原始特征只是输入层,在我们上面三层的神经网络例子中,第三层也就是输出层做出的预测利用的是第二层的特征,而非输入层中的原始特征,我们可以认为第二层中的特征是神经网络通过学习后自己得出的一系列用于预测输出变量的新特征。
我们可以逐渐构造出越来越复杂的函数,也能得到更加厉害的特征值。这就是神经网络的厉害之处。
小结一下使用神经网络时的步骤:
网络结构:第一件要做的事是选择网络结构,即决定选择多少层以及决定每层分别有多少个单元。
第一层的单元数即我们训练集的特征数量。
最后一层的单元数是我们训练集的结果的类的数量。
如果隐藏层数大于1,确保每个隐藏层的单元个数相同,通常情况下隐藏层单元的个数越多越好。
我们真正要决定的是隐藏层的层数和每个中间层的单元数。
训练神经网络:
1.参数的随机初始化
2.利用正向传播方法计算所有的hθ(x)
3.编写计算代价函数J的代码
4.利用反向传播方法计算所有偏导数
5.利用数值检验方法检验这些偏导数
6.使用优化算法来最小化代价函数
本次作业相关的文件如下,[*]为需要实现的,列出完整文件以便结合上面步骤了解完整过程。
ex4.m - Octave/MATLAB script that steps you through the exercise
ex4data1.mat - Training set of hand-written digits
ex4weights.mat - Neural network parameters for exercise 4
submit.m - Submission script that sends your solutions to our servers
displayData.m - Function to help visualize the dataset
fmincg.m - Function minimization routine (similar to fminunc)
sigmoid.m - Sigmoid function
computeNumericalGradient.m - Numerically compute gradients
checkNNGradients.m - Function to help check your gradients
debugInitializeWeights.m - Function for initializing weights
predict.m - Neural network prediction function
[*] sigmoidGradient.m - Compute the gradient of the sigmoid function
[*] randInitializeWeights.m - Randomly initialize weights
[*] nnCostFunction.m - Neural network cost function
按照ex4.m中的执行顺序,边执行边补充实现。
要求:根据ex3data1.mat中的5000个训练样本,每个样本是20*20像素的手写数字图片(展开后为400维的向量),5000个样本即5000*401大小的矩阵(400+1,包含x0)。Y是5000*10的矩阵,数字为几刚对应角标倍数的数字为1其它为0。
nnCostFunction.m 里面包含的内容较多,分3个部分,根据要求,边实现边提交再增强再提交。包含前向传播和后向传播两块内容。
前100个样本如图:
1. 前向传播
参数矩阵第一层25x401,第二层10x26。
代价函数公式为(无正则化时)
% part 1:
%calculate h(x)
a1 = [ones(m, 1) X];
z2 = a1 * Theta1';
a2 = sigmoid(z2);
a2 = [ones(m, 1) a2];
z3 = a2 * Theta2';
h = sigmoid(z3);
%calculate yk
yk = zeros(m, num_labels);
for i = 1:m
yk(i, y(i)) = 1; %y is class vector 5000*10
end
%costFunction and 1st submission
J = (1/m)* sum(sum(((-yk) .* log(h) - (1 - yk) .* log(1 - h))));
带正则化的前向传播:
代价函数为:
%Regularized cost function,Theta1 and Theta2 are the weight matrices
Theta1_new=Theta1(:,2:size(Theta1,2));
Theta2_new=Theta2(:,2:size(Theta2,2));
J=J+lambda/2/m*(Theta1_new(:)'*Theta1_new(:)+Theta2_new(:)'*Theta2_new(:))
执行结果与预期相当:
Feedforward Using Neural Network ...
J = 0.28763
Cost at parameters (loaded from ex4weights): 0.287629
(this value should be about 0.287629)
Program paused. Press enter to continue.
Checking Cost Function (w/ Regularization) ...
J = 0.38377
Cost at parameters (loaded from ex4weights): 0.383770
(this value should be about 0.383770)
Program paused. Press enter to continue.
2. 后向传播
主要是计算代价函数的梯度,以便把每次正向传播的误差反馈给每层的参数并按照梯度给出的最优方向进行调整。
sigmoidGradient.m中实现sigmoid函数的梯度
g=sigmoid(z).*(1-sigmoid(z));
参数随机初始化:
因子的取值大小主要是为了确保参数保持小的变化以便学习更有效,类比先前回归中的学习因子alpha.
图中算子实现在randInitializaWeights.m中即可。
调用如下:
initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size);
initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels);
% Unroll parameters
initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];
input_layer_size, hidden_layer_size, num_labels 分别为400, 25, 10,计算后initial_nn_params维度为10285*1.
算法步骤:
% Part 2:
%step 1 and 2
for i=1:m
y_new=zeros(1,num_labels);
y_new(1,y(i))=1;
a1=[1;X(i,:)'];
a2=[1;sigmoid(Theta1*a1)];
a3=sigmoid(Theta2*a2);
det3=a3-y_new';
det2=Theta2'*det3.*sigmoidGradient([1;Theta1*a1]);
det2 = det2(2:end);
Theta1_grad=Theta1_grad+det2*a1';
Theta2_grad=Theta2_grad+det3*a2';
end
% Part 3
%step 3 and 4
Theta1_grad(:,1)=Theta1_grad(:,1)/m;
Theta1_grad(:,2:size(Theta1_grad,2))=Theta1_grad(:,2:size(Theta1_grad,2))/m+...
lambda*Theta1(:,2:size(Theta1,2))/m;
Theta2_grad(:,1)=Theta2_grad(:,1)/m;
Theta2_grad(:,2:size(Theta2_grad,2))=Theta2_grad(:,2:size(Theta2_grad,2))/m+...
lambda*Theta2(:,2:size(Theta2,2))/m;
The above two columns you get should be very similar.
(Left-Your Numerical Gradient, Right-Analytical Gradient)
If your backpropagation implementation is correct, then
the relative difference will be small (less than 1e-9).
Relative Difference: 2.21135e-011
J = 0.57605
Cost at (fixed) debugging parameters (w/ lambda = 3.000000): 0.576051
(for lambda = 3, this value should be about 0.576051)
训练模型50次,lambda=1时,输出如下,
Training Neural Network...
J = 12.928 1 | Cost: 3.311295e+000
J = 0.49045 49 | Cost: 5.008575e-001
Iteration 50 | Cost: 4.904534e-001
Program paused. Press enter to continue.
Visualizing Neural Network...
Program paused. Press enter to continue.
Training Set Accuracy: 95.520000
>>
试着修改迭代次数和lambda,如100和2 ,结果如下:代价函数虽然比迭代50次lambda=1时略大,但精度比前者高。
Iteration 100 | Cost: 5.305923e-001
Program paused. Press enter to continue.
Visualizing Neural Network...
Program paused. Press enter to continue.
Training Set Accuracy: 96.720000
值得说明的是,第9步中的可视化隐藏层,可以更直观地理解在其中起的作用。
方法为:除去0角标元素,隐藏层是400维的向量,它原本是20*20像素的图片,这里我们把它还原为20*20的图片,行数为25个即单元数25。