在机器学习中,如果想对非线性函数进行建模,深度前馈网络能够实现这一目标。

在深度学习中,使用一个简单函数的深度链来学习输入数据。

线性函数的输入函数:

\hat{y} = \theta^\top x

非线性函数的输入函数:

\hat{y} = f(\phi(x); \theta)

其中:

\phi(x) = h^{(m)}(\ldots(h^{(2)}(h^{(1)}(x))))

\phi 是输入数据 x 的学习表征,h(x) 是激活函数。

深度前馈网络

在深度前馈网络的每一层(Layer),使用一个简单的线性函数 W^{(l)} x^{(l-1)} 和后面的激活函数 h(x) 来表示网络结构。

网络的整体结构:

\hat{y} = f\!\left(W^{(M)} h\!\left(\ldots\!\left(W^{(2)} h\!\left(W^{(1)} h(x)\right)\right)\right)\right)

在每层中:

z^{(l)} = W^{(l)} x^{(l-1)}
x^{(l)} = h\!\left(z^{(l)}\right)
x^{(0)} = x

每一层都会使用一个简单的线性函数及一个权重矩阵 W

\mathbf{z} = \mathbf{W}\mathbf{x}
\begin{pmatrix} z_1 \\ z_2 \\ \vdots \\ z_J \end{pmatrix} = \begin{pmatrix} b_1 & w_{1,1} & \cdots & w_{1,N} \\ b_2 & w_{2,1} & \cdots & w_{2,N} \\ \vdots & \vdots & \cdots & \vdots \\ b_J & w_{J,1} & \cdots & w_{J,N} \end{pmatrix} \begin{pmatrix} 1 \\ x_1 \\ x_2 \\ \vdots \\ x_N \end{pmatrix}

隐藏单元的激活函数 Activation Functions

h(\cdot) 是激活函数。

ReLU

x_j = h(z_j) = \max(0, z_j)

Figure 1 ReLU

LReLU

x_j = h(z_j) = \begin{cases} a z_j & \text{if } z_j < 0 \\ z_j & \text{if } z_j \geq 0 \end{cases}

Figure 2 Leaky ReLU

Sigmoid

x_j = h(z_j) = \frac{1}{1 + \exp(-z_j)}

Figure 3 Sigmoid

Tangent (tanh)

x_j = h(z_j) = \tanh(z_j)

Figure 4 Tangent

输出单元

回归问题,是线性输出

\hat{y}_j = f\!\left(z_j^{(M)}\right) = w_j^{(M)\top} x^{(M-1)}

分类(class > 2)问题,是 Softmax 输出,Softmax 的输出用来预测各个分类的可能性:

\hat{y}_j = P(Y=j \mid x^{(M-1)}; w_j^{(M)}) = \frac{\exp(w_j^{(M)\top} x^{(M-1)})}{\sum_{k=1}^{K} \exp(w_k^{(M)\top} x^{(M-1)})}

深度前馈网络是一个具有非线性激活函数线性函数链,有一个专门用于任务的输出层,即回归或分类。

Figure 5 深度前馈网络结构


反向传播 Back Propagation

反向传播又被称为 BP,允许来自 loss function 的信息通过网络向后流动,以便计算梯度(Gradient)。实际上是loss 反向传播。该方法对网络中所有权重计算损失函数的梯度,用来更新权重以最小化 loss。

符号约定:全文统一使用 w_{ji}^{(l)} 表示从第 l-1 层神经元 i 到第 l 层神经元 j 的权重。前向传播为 z_j^{(l)} = \sum_i w_{ji}^{(l)} x_i^{(l-1)},反向传播为 \delta_j^{(l)} = \sum_k w_{kj}^{(l+1)} \delta_k^{(l+1)} h'(z_j^{(l)})

SGD

用下面的公式不断更新 w 的值:

w_{ji}^{(l)} \leftarrow w_{ji}^{(l)} - \epsilon \frac{\partial L_n}{\partial w_{ji}^{(l)}}

这里的 L_n 是一个 sample 的 Loss。

Figure 6 Back Propagation

对于深度前馈网络,\delta_j^{(l)} x_i^{(l-1)} 就是 \frac{\partial L_n}{\partial w_{ji}^{(l)}}

推导过程如下

首先回想起在每个单元,前馈输出 z^{(l)} = W^{(l)} x^{(l-1)}

根据链式法则:

\frac{\partial L_n}{\partial w_{ji}^{(l)}} = \frac{\partial L_n}{\partial z_j^{(l)}} \frac{\partial z_j^{(l)}}{\partial w_{ji}^{(l)}}
\frac{\partial L_n}{\partial z_j^{(l)}} = \delta_j^{(l)}
\frac{\partial z_j^{(l)}}{\partial w_{ji}^{(l)}} = x_i^{(l-1)}

由上面两个公式可以得到:

\frac{\partial L_n}{\partial w_{ji}^{(l)}} = \delta_j^{(l)} x_i^{(l-1)}

根据上面的公式,SGD 可以更新:

w_{ji}^{(l)} \leftarrow w_{ji}^{(l)} - \epsilon \, \delta_j^{(l)} x_i^{(l-1)}

现在只要求出 \delta_j^{(l)} 就可以得到 BP 的完整表达式:

\delta_j^{(l)} = \frac{\partial L_n}{\partial z_j^{(l)}}

对隐藏层,由链式法则递推:

\delta_j^{(l)} = \sum_k w_{kj}^{(l+1)} \delta_k^{(l+1)} h'\!\left(z_j^{(l)}\right)

推导如下。第 l+1 层的前馈计算为 z_k^{(l+1)} = \sum_j w_{kj}^{(l+1)} x_j^{(l)},其中 x_j^{(l)} = h(z_j^{(l)}),因此:

\frac{\partial z_k^{(l+1)}}{\partial z_j^{(l)}} = w_{kj}^{(l+1)} h'\!\left(z_j^{(l)}\right)

代入链式法则即得上式。

反向传播算法

  1. 正向传播,估计 \forall l

    z_j^{(l)} = \sum_i w_{ji}^{(l)} x_i^{(l-1)}
    x_j^{(l)} = h\!\left(z_j^{(l)}\right)
  2. 初始化 \delta^{(M)}

    \delta_j^{(M)} = \frac{\partial L_n}{\partial \hat{y}_j} f'\!\left(z_j^{(M)}\right)

    具体形式取决于输出层与损失函数的组合:

    • MSE 回归 + 线性输出\delta_j^{(M)} = \hat{y}_j - y_j
    • Softmax + 交叉熵\delta_j^{(M)} = \hat{y}_j - y_j,其中 y_j 为 one-hot 标签
    • Sigmoid + 二元交叉熵\delta_j^{(M)} = \hat{y}_j - y_j

    后两种情形形式与 MSE 相同,但推导前提不同,不能混用损失函数。

  3. 反向传播,每层都计算一次:

    \delta_j^{(l)} = \sum_k w_{kj}^{(l+1)} \delta_k^{(l+1)} h'\!\left(z_j^{(l)}\right)
  4. 梯度

    \frac{\partial L_n}{\partial w_{ji}^{(l)}} = \delta_j^{(l)} x_i^{(l-1)}

    假设 \frac{\partial L_n}{\partial w_{ji}^{(l)}}G,接下来在每层,w 会更新:

    w^{(l)} = w^{(l)} - \epsilon G
maxIter = m;
for epoch = 1:maxEpochs % loop over number of epochs
    loss = [];
    for iter = 1:m % loop over all data samples
        %% 1. forward propagation
        net(1).x = x(r(iter)); % extract random input
        for l = 2:M % loop over each layer
            net(l).z = net(l).W*[1; net(l-1).x]; % weight & bias
            net(l).x = max(net(l).z,0); % ReLU activation
        end
        net(M).yhat = net(M).z; % output activation
        %% 2. initialise delta
        net(M).delta = (net(M).yhat-y(r(iter)));
        %% 3. backpropagation through all network layers
        for l = M:-1:3
            net(l-1).delta = net(l).W(:,2:end)'*net(l).delta.*(1.*(net(l-1).z>0));
        end
        %% 4. define loss function gradient
        for l = 2:1:M
            net(l).grad = [net(l).delta net(l).delta*net(l-1).x']; % additional layers
        end
        %% update parameters using SGD
        for l = 2:M
            G = net(l).grad; % error gradient matrix
            net(l).W = net(l).W - epsilon.*G; % SGD update rule
        end
        %% plot results: evaluate and plot loss
        for i = 1:m % forward propagate all data
            net(1).x = x(i); % extract data input sample
            for l = 2:M % loop over network layers
                net(l).z=net(l).W*[1;net(l-1).x]; % weight and bias
                net(l).x=max(net(l).z,0); % ReLU activation
            end
            net(M).yhat=net(M).z; % output
            Yhat(i) = net(M).yhat; % store output
        end
        loss(iter) = sum((Yhat - y).^2); % evaluate loss
        figure(101);subplot(1,2,1); cla; plot(loss); xlabel('Iteration'); ylabel('Loss');
        title(['(a) Loss (Epoch: ' num2str(epoch) ')']); xlim([0 maxIter]);
        subplot(1,2,2); cla; plot(x,y,'.'); hold on; plot(x,Yhat);
        xlabel('x'); ylabel('y'); title('(b) Model Fit'); drawnow;
    end
end