Neural Networks:Learning

神经网络:学习(Neural Networks:Learning)

代价函数

标记方法

  • 训练样本 m
  • 输入 X
  • 输出信号 y
  • 神经网络层数 L
  • 每层的神经元个数 $S_I$
  • 输出单元个数 $S_L$

    分类

  • 二类分类
  • K类分类

公式

逻辑回归中,只有一个输出,在神经网络中,有很多输出,$h_\theta{(x)}$是一个维度为K的向量

思想:观察算法预测的结果与真实的情况误差,与之前唯一不同的是,选取可能性最高的预测结果与实际数据比较。

正则化:排除了每一层$\theta_0​$后,每一层的$\theta​$矩阵的和

反向传播算法(Backpropagation Algorithm)

定义

首先计算最后一层的误差,然后一层一层反向求出各层的误差,直到第二层。

标记

  • 网络层数 $l$
  • 计算层激活单元下标,下一层第j个输入变量下标 $j$
  • 受到权重矩阵第i行影响的下一层中误差单元下标 $i$
  • 误差 $\delta$
  • 误差矩阵(第$l$层的第i个激活单元受到第$j$个参数影响导致的误差) $\Delta_{ij}^{(l)}$

    示例

假设网络有四层

$g’(z^{(3)})$是$S$型函数的导数

有了所有误差的表达式后,就可以计算代价函数的偏导数了。

不做正则化处理(求导公式待证明)

算法表示

结果:

权重在Octave的处理

如果要使用fminnuc这样的优化算法来求解权重矩阵,需要将矩阵展开为向量,再利用算法来求出最优解后再转换为矩阵。

1
2
3
4
5
thetaVec = [Theta1(:) ; Theta2(:) ; Theta3(:)]
...optimization using functions like fminuc...
Theta1 = reshape(thetaVec(1:110), 10, 11);
Theta2 = reshape(thetaVec(111:220), 10, 11);
Theta1 = reshape(thetaVec(221:231), 1, 11);

直观理解(Intuition)

如果考虑简单的没有正则化的二分类问题,代价函数为:

直观地看,$\delta_j^{(l)}$是输入$a_j^{(l)}$的误差,正规的说,$\delta$就是代价函数的导数。

在这幅图中,要计算$\delta_2^{(2)}$,

其实这就是$\Theta^{(2)}$的第三列乘$\delta^{(3)}$

梯度检验

Numerical Gradient Checking

当$\theta$是一个向量时,我们则需要对偏导数进行检验。因为代价函数的偏导数检验只针对一个参数的改变进行检验,下面是一个只针对 进行检验的示例:

根据上面的算法,计算出的偏导数存储在矩阵$D_{ij}^{(l)}$ 中。检验时,我们要将该矩阵展开成为向量,同时我们也将$\theta$ 矩阵展开为向量,我们针对每一个$\theta$ 都计算一个近似的梯度值,将这些值存储于一个近似梯度矩阵中,最终将得出的这个矩阵同 $D_{ij}^{(l)}$进行比较。

随机初始化

如果全部参数一致,那么每个节点的值都是一样,这个神经网络每层实际只有一个单元。
我们通常初始参数为正负ε之间的随机值,假设我们要随机初始一个尺寸为10×11 的参数矩阵,代码如下:

1
Theta1 = rand(10, 11) * (2*eps) – eps

综合起来:训练步骤

选择网络结构

  • 第一层为训练集特征数量
  • 最后一层为结果类数量
  • 如果隐藏层大于一,确保每个隐藏层单元个数相同,通常隐藏层单元越多越好

    训练神经网络

  • 参数随机初始化
  • 正向传播算法计算所有$h_\theta(X)$
  • 计算代价函数J
  • 反向传播算法计算所有偏导数
  • 数值检验方法检验偏导数
  • 使用优化算法优化代价函数

作业回顾

一个三层的网络,输入层单元input_layer_size个,隐藏层单元hidden_layer_size个,分类结果num_labels个。X为m条训练数据,y是标签。

参数初始化

1
2
3
initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size);
initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels);
initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];

正向传播算法

1
2
3
4
5
6
7
8
9
10
11
X = [ones(m, 1) X];
ylabel = zeros(num_labels, m);
for i=1:m
ylabel(y(i), i) = 1;
end

z2 = X*Theta1';
z2 = [ones(m, 1) z2];
a2 = sigmoid(X*Theta1');
a2 = [ones(m, 1) a2];
a3 = sigmoid(a2*Theta2');

计算代价函数

1
2
3
4
5
for i=1:m
J = J - log(a3(i, :))*ylabel(:, i) - (log(1 - a3(i, :)) * (1 - ylabel(:, i)));
end
J = J/m;
J = J + lambda / (2*m) * ( sum(sum(Theta1(:,2:end).^2))+sum(sum(Theta2(:,2:end).^2)) );

反向传播算法

1
2
3
4
5
6
7
8
9
10
11
12
13
Delta1 = zeros(size(Theta1));
Delta2 = zeros(size(Theta2));
for t=1:m,
delta_3 = a3(t,:)' - ylabel(:,t);
delta_2 = Theta2'*delta_3.*(sigmoidGradient(z2(t,:)'));
Delta1 = Delta1 + delta_2(2:end) * X(t, :);
Delta2 = Delta2 + delta_3 * a2(t, :);
end

Theta1_grad = Delta1 / m;
Theta1_grad(:, 2:end) = Theta1_grad(:, 2:end) + lambda/m*Theta1(:, 2:end);
Theta2_grad = Delta2 / m;
Theta2_grad(:, 2:end) = Theta2_grad(:, 2:end) + lambda/m*Theta2(:, 2:end);

数值检验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[cost, grad] = costFunc(nn_params);
numgrad = computeNumericalGradient(costFunc, nn_params);

function numgrad = computeNumericalGradient(J, theta)
numgrad = zeros(size(theta));
perturb = zeros(size(theta));
e = 1e-4;
for p = 1:numel(theta)
% Set perturbation vector
perturb(p) = e;
loss1 = J(theta - perturb);
loss2 = J(theta + perturb);
% Compute Numerical Gradient
numgrad(p) = (loss2 - loss1) / (2*e);
perturb(p) = 0;
end
end
diff = norm(numgrad-grad)/norm(numgrad+grad);

优化算法

1
2
3
4
5
6
[nn_params, cost] = fmincg(costFunction, initial_nn_params, options);
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));