机器学习算法实现——神经网络
Ng课学习笔记,只对其中我认为有难度或者很“beautiful”的地方进行了记录。
(1)多分类问题
无论是线性classifier还是神经网络,一组样例的结果y(i)的表示形式是一个长度为k的向量(vector),k为最终类别的种类数。之所以进行这种形式转换是基于我们对最终预测结果的计算方法,即对于每一个类别,利用OneVsAll算法,计算该组样例为1的概率。
all_theta = zeros(num_labels, n + 1); options = optimset('GradObj', 'on', 'MaxIter', 50); for k = 1:num_labels initial_theta = zeros(n+1,1); theta=fmincg(@(t)(lrCostFunction(t,X,(y==k),lambda)),initial_theta,options); all_theta(k,:)=theta'; end
即对于多酚类问题,我们不再单一的使用“一组”theta,而是使用“多组”theta,一组特定的theta能用来预测某组样例是该特定类别(class)的概率。
在理解了OneVsAll之后,我们便不难理解为什么要把样例的结果y和我们的预测值output layer的值扩展为一个长度为k的向量了。具体的扩展代码如下,非常的优美!
Y = eye(num_labels)(y,:);
一开始没有看懂,后来想了一会儿明白了。等式的右边由两项构成,第一项是eye(num_labels),你可以给它看成一个矩阵,即A = eye(num_labels),然后右边的形式就容易理解了——A(y,:),即分别依次挑选出矩阵A中的“第y行”然后层层叠加起来形成一个新的行数不变、列数为k的0-1矩阵。即permutation!
(2)Cost Function
这个没什么好讲解的,就是照着公式在matlab/octave中正确的表示出来就行:
a1 = [ones(size(X,1),1) X]; z2 = a1*Theta1'; a2 = [ones(size(X,1),1) sigmoid(z2)]; z3 = a2*Theta2'; a3 = sigmoid(z3); for i=1:m J += - ( Y(i,:) * log(a3(i,:)') + (1-Y(i,:)) * log(1-a3(i,:)') ) /m; end
reg = lambda/(2*m)*(sumsq(Theta1(:,2:end)(:)) + sumsq(Theta2(:,2:end)(:)));
J += reg;
(3)BP算法
具体讲解:http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95 这是我在网上找到的讲的比较清晰的一篇了, 基本的公式推导都有,如果有条件的话可以结合周志华老师的西瓜书相关章节辅助一下,效果更佳。此处只给出BP算法的matlab实现
Delta1 = zeros(size(Theta1)); Delta2 = zeros(size(Theta2)); for i = 1:m delta3 = a3(i,:)-Y(i,:); delta3 = delta3'; delta2 = Theta2(:,2:end)'*delta3 .* sigmoidGradient(z2(i,:))'; %对于特定的一组样例来说,误差函数关于某一层参数theta的导数是基于本层的预测值和下一层相对应的残差的乘积 %(1)Accumulating the gradient for this example using the following formula. Delta2 += delta3*a2(i,:); Delta1 += delta2*a1(i,:); end %(2)Obtain the (unregularized) gradient for the neural network cost function by dividing the %accumulated gradients by 1/m. Theta2_grad = Delta2/m; Theta1_grad = Delta1/m; Theta2_grad(:,2:end) = Delta2(:,2:end)/m + lambda/m*Theta2(:,2:end); Theta1_grad(:,2:end) = Delta1(:,2:end)/m + lambda/m*Theta1(:,2:end);
值得注意的是Ng的课将每个neuron的阀值给合并到theta当中的去了,名之bias term。因此在计算矩阵的过程中要格外注意多一列少一列的小细节,很容易出错。