机器学习之五:神经网络、反向传播算法

一、逻辑回归的局限

在逻辑回归一节中,使用逻辑回归的多分类,实现了识别20*20的图片上的数字。

但所使用的是一个一阶的模型,并没有使用多项式,为什么?

可以设想一下,在原有400个特征的数据样本中,增加二次、三次、四次多项式,会是什么情形?

很显然,训练样本的特征数量将会拔高多个数量级,而且,更重要的,要在一个式子中拟合这么多的特征,其难度是非常大的,可能无法收敛到一个比较理想的状态。

也就是说,逻辑回归没法提供很复杂的模型。

因为其本质上是一个线性的分类器,擅长解决的是线性可分的问题。

那么非线性可分问题,要怎么解决?

解决思路

如果有一种方法,将非线性可分问题先进行特征提取,变为接近线性可分,那么再应用一次逻辑回归,是否就能解决非线性问题了?

这便是神经网络的思想。

二、神经网络

1、结构

神经网络的结构,如下图所示

上面是一个最简单的模型,分为三层:输入层、隐藏层、输出层。

其中,隐藏层可以是多层结构,通过扩展隐藏层的结构,可以构建更得杂的模型,例如下面的模型:

每一层的输出,皆是下一层的输出,层层连接而成,形成一个网络。

网络中的节点,称为神经元。每个神经元,其实就是进行一次类似逻辑回归的运算(之所以说是"类似",是因为可以使用逻辑回归,也有别的算法代替,但可以使用逻逻回归来理解它的运算机理)。

根据上面前言中的分析,显然,隐藏层是进行特征的提取,而输出层,其实就是进行逻辑回归。

为何说隐藏层是进行特征提取?

为方便理解,这里假设所有神经元执行逻辑回归。

一次逻辑回归,可以将平面一分为二。神经网络中,执行的是 N 多个逻辑回归,那么可以将平面切割为 N 多个区域,这些区域最后由输出层进行综合后做为结果。

如果只关注输出层,那么这些前面切割出来的区域,其实可以当作是一种特征,是一种更高级的特征,由原始样本提取出来的。这就是特征的提取。

2、计算原理

2.1 前向传播,计算输出

下面求解当一个样本从输入层输入时,如何得到最终结果。

假设每个神经元,都执行逻辑回归的计算,则第 \(i\) 层网络的输出为:\[a^{(i)} = g(z^{(i)}) = g(\Theta^Ta^{(i-1)}) \tag{1}\]

以如下三层网络为例:

各层的输入输出如下:

Input layer:

\[
a^{(1)} = x
\]
Hidden layer:

\[
\begin{split}
z^{(2)} &= \Theta^{(1)}a^{(1)} \a^{(2)} &= g(z^{(2)})
\end{split}
\]
Output layer:

\[
\begin{split}
z^{(3)} &= \Theta^{(2)}a^{(2)} \a^{(3)} &= g(z^{(2)})
\end{split}
\]

即整个网络的最终结果为:

\[
h_\theta(x) = a^{(3)}
\]

上述流程:以上一层的输出,作为下一层的输入,一层一层叠加运算后,得到最终的输出,这个计算方法,称为“前向传播”

2.2 反向传播,求theta矩阵

训练算法的目的是“求取使得误差函数最小化的参数矩阵”,用梯度下降法处理最小化误差,需要计算误差函数J、以及J对theta的偏导数。

2.2.1 误差函数J

\[
J(\Theta) = -\frac{1}{m} \sum_{i=1}^{m}\sum_{k=1}^{K}[y_k^{(i)}log(h_\Theta(x^{(i)}))_k + (1-y_k^{(i)})log(1-h_\theta(x^{(i)}))_k] + \frac{\lambda}{2m}\sum_{l=1}^{L-1}\sum_{i=1}^{S_l}\sum_{j=1}^{S_l+1}(\Theta_{ji}^{(l)})^2 \tag{2}
\]

其中 \(K\) 为输出层的单元数,即类别数。在计算误差的时候,需要将每一类都计算进去。后面的正则项是整个神经网络中所有的参数 \(\Theta\) 的值之和。

2.2.2 J对theta偏导数

这里先给结果,后面再做推导:

\[
\frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta) = \frac{1}{m}\sum_{t=1}^{m}\delta_i^{(t)(l+1)}a_j^{(t)(l)} + \frac{\lambda}{m}\sum_{l=1}^{L-1}\sum_{i=1}^{S_l}\sum_{j=1}^{S_l+1}(\Theta_{ji}^{(l)}) \tag{3}
\]

其中

\[
\begin{cases}
\delta^{(L)} &=& a^{(L)}-y \\\delta^{(l)} &=& \delta^{(l+1)}*(\Theta^{(l+1)})^T*g'(z^{(l)}) \\\delta^{(0)} &=& 0
\\end{cases}
\tag{4}
\]

上述公式描述的内容

第 \(l\) 层的误差,可以通过第 \(l+1\) 层的误差计算出来,而最后一层的误差,就是系统通过前向传播计算出的值与样本 \(Y\) 值的差。
也就是说,从输出层开始,各层误差能通过一层一层反向迭代的方式得到,确定误差之后,偏导数便也随之计算出来,进而可进行模型的调整。这就是,“反向传播算法”

而反向传播的内容,其实是误差。

  • 关于误差的直观理解:

输出层的误差,即为系统的总误差;

中间层的误差,即为每一层对总误差的贡献值(所以,\(\theta\) 矩阵,在前向传播中,是特征权重,而在反向传播中,就是误差权重);

而输入层,其输出即为原始数据,即无误差。

2.2.3 反向传播算法的推导过程

(1) 第一部分,推导偏导数

上面给出了反向传播的结论,以下进行推导。

矩阵形式计算第 \(l\) 层的偏导数:

\[
\begin{split}
\frac{\partial J(\Theta)}{\partial\Theta^{(l)}} &= \frac{\partial J(\Theta)}{\partial z^{(l+1)}} * \frac{\partial z^{(l+1)}}{\partial \Theta^{(l)}}
\\&= \frac{\partial J(\Theta)}{\partial z^{(l+1)}} * \frac{\partial (\Theta^{(l)}*a^{(l)})}{\partial \Theta^{(l)}}
\\&= \frac{\partial J(\Theta)}{\partial z^{(l+1)}} * a^{(l)}
\end{split}
\tag{5}
\]

令 \[\delta^{(l)} = \frac{\partial J(\Theta)}{\partial z^{(l)}} \tag{6}\]

则有

\[
\begin{split}
\frac{\partial J(\Theta)}{\partial\Theta^{(l)}} &=& \frac{\partial J(\Theta)}{\partial z^{(l+1)}} * a^{(l)}
\\&=& \delta^{(l+1)} * a^{(l)}
\\end{split}
\tag{7}
\]

(2) 第二部分,推导误差delta

上面推导过程中,有这个式子:

\[
\delta^{(l)} = \frac{\partial J(\Theta)}{\partial z^{(l)}}
\]

表示了什么意思?下面分别从输出层、及中间层来推导、解释这个式子。

  • 输出层

因误差函数如下(这里省略掉正则项)

\[
J(\Theta) = -\frac{1}{m} \sum_{i=1}^{m}\sum_{k=1}^{K}[y_k^{(i)}log(h_\Theta(x^{(i)}))_k + (1-y_k^{(i)})log(1-h_\theta(x^{(i)}))_k]
\]

此式表达的是总误差,那么,对于输出层的每个神经元的误差,可用矩阵表示为:

\[
C = - [ylog(h_\Theta(x)) + (1-y)log(1-h_\theta(x))]
\tag{8}
\]

故输出层的误差为:

\[
\begin{split}
\delta^{(L)} &=& \frac{\partial J(\Theta)}{\partial z^{(L)}} = \frac{\partial C}{\partial z^{(L)}}
\\&=& \frac{\partial }{\partial z^{(L)}} [ylog(h_\Theta(x)) + (1-y)log(1-h_\theta(x))]
\\&=& -\frac{y}{g(z^{(L)})}g'(z^{(L)}) - \frac{1-y}{1-g(z^{(L)})}(-g'(z^{(L)}))
\\&=& \frac{g(z^{(L)})-y}{g(z^{(L)})(1-g(z^{(L)}))}(g'(z^{(L)}))
\\&=& g(z^{(L)})-y
\\&=& a^{(L)}-y
\end{split}
\tag{9}
\]

这个结果,有点意思了,表示出输层的 \(\delta\) 值,就是系统输出值与样本 \(Y\) 值的差。所以,我们称 \(\delta\) 为神经系统各层结构的各个神经元的误差。

  • 中间层误差推导

对于第 \(l\) 层

\[
\begin{split}
\delta^{(l)} &=& \frac{\partial J(\Theta)}{\partial z^{(l)}} \\&=& \frac{\partial J(\Theta)}{\partial z^{(l+1)}} * \frac{\partial z^{(l+1)}}{\partial z^{(l)}} \\&=& \delta^{(l+1)} * \frac{\partial [(\Theta^{(l+1)})^T*g(z^{(l)})]}{\partial z^{(l)}} \\&=& \delta^{(l+1)} * (\Theta^{(l+1)})^T*g'(z^{(l)}) \\end{split}
\tag{10}\]

即第 \(l\) 层的误差,能用第 \(l+1\) 层的误差计算得到,与先前所定的结论完全一致。

这就是反向传播的所有推导的内容。

三、程序实现

例子来源于,吴恩达的机器学习编程题。样本与逻辑回归中的多分类的数字识别相同。

1、计算损失函数、及梯度

function [J grad] = nnCostFunction(nn_params, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, ...
                                   X, y, lambda)
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));

% ------ 前向传播计算输出 ------

% input layer
a1 = [ones(m, 1) X]; %add +1 to X;
% hidden layer
a2 = sigmoid(a1 * Theta1');
a2 = [ones(m, 1) a2];
% output layer
a3 = sigmoid(a2 * Theta2');

% ------ 样本的Y值 ------
% [1 0 0 0 0 0 0 0 0 0] -- the value is 1
% [0 1 0 0 0 0 0 0 0 0] -- the value is 2
Y = zeros(m,num_labels);
for i = 1 : m
    Y(i,y(i)) = 1;
end

% ------ 损失函数J ------
J = (sum(sum(-Y .* log(a3))) - sum(sum((1-Y) .* log(1-a3)))) / m ;
% remove theta0
t1 = Theta1(:,2:end);
t2 = Theta2(:,2:end);
regularize = lambda / 2 / m * (sum(sum(t1.^2)) + sum(sum(t2.^2)));
J = J + regularize;

% ------ 反向传播计算各层误差 ------
delta3 = a3 - Y;
delta2 = delta3 * Theta2 .* a2 .* (1 - a2);
delta2 = delta2(:,2:end);

% ------ 计算梯度 ------
Theta1_grad = ( delta2' * a1 + [zeros(size(t1,1),1) t1] * lambda) / m;
Theta2_grad = ( delta3' * a2 + [zeros(size(t2,1),1) t2] * lambda) / m;

% Unroll gradients
grad = [Theta1_grad(:) ; Theta2_grad(:)];

end

2、前向传播及计算delta中,需要用到sigmoid函数及其导数

2.1 sigmoid函数

function g = sigmoid(z)
g = 1.0 ./ (1.0 + exp(-z));
end

2.2 sigmoid函数的导数

function g = sigmoidGradient(z)
g = sigmoid(z) .* (1 - sigmoid(z));
end

3、训练过程

3.1、随机初始化theta参数矩阵

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(:)];

逻辑回归中,theta矩阵可以初始化为同一个值,如全0或全1。但神经网络中却不行。

原因在于:神经网络中,神经元是以全连接的形式组织起来的,即n-1层的任意一个节点,都与第n层所有节点相连接。

若是初始化时theta矩阵初始化为同一个值,同一个层的每一个神经元都进行相同的运算,多个神经元进行相同的运算,这对于数据的拟合没有任何用处,只是浪费资源,造成冗余。此为对称现象。

随机初始化参数的实现如下:

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.2、初始化参数

options = optimset('MaxIter', 100);

% 正则项参数
lambda = 1;

% 损失函数
costFunction = @(p) nnCostFunction(p, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, X, y, lambda);
% 梯度下降计算参数
[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));

4、预测

pred = predict(Theta1, Theta2, X);

fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);

可以看到,其预测结果,比逻辑回归准确率高接近3个点。

原因在于:神经网络所能构建的模型,比逻辑回归更为复杂,其对数据的拟合能力也更强。

predict函数,使用训练得到的参数矩阵,前向传播计算得到结果即为输出层,输出层表示一个输入样本经过经神网络计算之后,其可能属于各个分类的概率值。与逻辑回归类似,取最大值即为最终的结果。

function p = predict(Theta1, Theta2, X)

m = size(X, 1);
num_labels = size(Theta2, 1);

p = zeros(size(X, 1), 1);

h1 = sigmoid([ones(m, 1) X] * Theta1');
h2 = sigmoid([ones(m, 1) h1] * Theta2');
[dummy, p] = max(h2, [], 2);

end

原文地址:https://www.cnblogs.com/Fordestiny/p/8819978.html

时间: 2024-10-06 05:36:02

机器学习之五:神经网络、反向传播算法的相关文章

神经网络反向传播算法(4,5)

"反向传播"是最小化成本函数的神经网络术语,就像我们在logistic回归和线性回归中的梯度下降一样.我们的目标是计算: 也就是说,我们希望在θ中使用一组最优参数来最小化我们的成本函数j.在这一节中我们将看看我们用来计算J(Θ)的偏导数方程: 为此,我们使用下面的算法: 反向传播算法实现: 1.得到训练集 2.设置所有i,j,l(因此你最终有一个矩阵全零) 3.遍历训练样本t = 1到m: (1) (2)进行正向传播计算a(j)  j从1到m: (3)使用y(t),计算 其中L是我们的

神经网络训练中的Tricks之高效BP(反向传播算法)

神经网络训练中的Tricks之高效BP(反向传播算法) 神经网络训练中的Tricks之高效BP(反向传播算法) [email protected] http://blog.csdn.net/zouxy09 Tricks!这是一个让人听了充满神秘和好奇的词.对于我们这些所谓的尝试应用机器学习技术解决某些问题的人,更是如此.曾记得,我们绞尽脑汁,搓手顿足,大喊“为什么我跑的模型不work?”,“为什么我实现的效果那么差?”,“为什么我复现的结果没有他论文里面说的那么好?”.有人会和你说“你不懂调参!

机器学习之反向传播算法

Thoughts of Algorithms 博客园 首页 联系 订阅 管理 随笔 - 54  文章 - 1  评论 - 141 机器学习公开课笔记(5):神经网络(Neural Network)--学习 这一章可能是Andrew Ng讲得最不清楚的一章,为什么这么说呢?这一章主要讲后向传播(Backpropagration, BP)算法,Ng花了一大半的时间在讲如何计算误差项δδ,如何计算ΔΔ的矩阵,以及如何用Matlab去实现后向传播,然而最关键的问题--为什么要这么计算?前面计算的这些量到

DL4NLP——神经网络(一)前馈神经网络的BP反向传播算法步骤整理

这里把按[1]推导的BP算法(Backpropagation)步骤整理一下,备忘使用.[1] 中直接使用矩阵微分的记号进行推导,整个过程十分简洁.而且这种矩阵形式有一个非常大的优势就是对照其进行编程实现时非常方便. 但其实用标量计算推导也有一定的好处,比如可以清楚地知道某个权重是被谁所影响的. 记号约定: $L$:神经网络的层数.输入层不算. $n^l$:第 $l$ 层神经元的个数.偏置神经元不算在内. $W^{l}\in\mathbb R^{n^l\times n^{l-1}}$:第 $l-1

循环神经网络(RNN)模型与前向反向传播算法

在前面我们讲到了DNN,以及DNN的特例CNN的模型和前向反向传播算法,这些算法都是前向反馈的,模型的输出和模型本身没有关联关系.今天我们就讨论另一类输出和模型间有反馈的神经网络:循环神经网络(Recurrent Neural Networks ,以下简称RNN),它广泛的用于自然语言处理中的语音识别,手写书别以及机器翻译等领域. 1. RNN概述 在前面讲到的DNN和CNN中,训练样本的输入和输出是比较的确定的.但是有一类问题DNN和CNN不好解决,就是训练样本输入是连续的序列,且序列的长短不

深度学习基础--神经网络--BP反向传播算法

BP算法: 1.是一种有监督学习算法,常被用来训练多层感知机.  2.要求每个人工神经元(即节点)所使用的激励函数必须可微. (激励函数:单个神经元的输入与输出之间的函数关系叫做激励函数.) (假如不使用激励函数,神经网络中的每层都只是做简单的线性变换,多层输入叠加后也还是线性变换.因为线性模型的表达能力不够,激励函数可以引入非线性因素) 下面两幅图分别为:无激励函数的神经网络和激励函数的神经网络 如图所示,加入非线性激活函数后的差异:上图为用线性组合逼近平滑曲线来分割平面,下图为使用平滑的曲线

【神经网络和深度学习】笔记 - 第二章 反向传播算法

上一章中我们遗留了一个问题,就是在神经网络的学习过程中,在更新参数的时候,如何去计算损失函数关于参数的梯度.这一章,我们将会学到一种快速的计算梯度的算法:反向传播算法. 这一章相较于后面的章节涉及到的数学知识比较多,如果阅读上有点吃力的话也可以完全跳过这一章,把反向传播当成一个计算梯度的黑盒即可,但是学习这些数学知识可以帮助我们更深入的理解神经网络. 反向传播算法的核心目的是对于神经网络中的任何weight或bias计算损失函数$C$关于它们的偏导数$\frac{\partial C}{\par

《神经网络和深度学习》系列文章十六:反向传播算法代码

出处: Michael Nielsen的<Neural Network and Deep Learning>,点击末尾“阅读原文”即可查看英文原文. 本节译者:哈工大SCIR硕士生 李盛秋 声明:如需转载请联系[email protected],未经授权不得转载. 使用神经网络识别手写数字 反向传播算法是如何工作的 热身:一个基于矩阵的快速计算神经网络输出的方法 关于损失函数的两个假设 Hadamard积 反向传播背后的四个基本等式 四个基本等式的证明(选读) 反向传播算法 反向传播算法代码

《神经网络和深度学习》系列文章十五:反向传播算法

出处: Michael Nielsen的<Neural Network and Deep Learning>,点击末尾“阅读原文”即可查看英文原文. 本节译者:哈工大SCIR本科生 王宇轩 声明:如需转载请联系[email protected],未经授权不得转载. 使用神经网络识别手写数字 反向传播算法是如何工作的 热身:一个基于矩阵的快速计算神经网络输出的方法 关于损失函数的两个假设 Hadamard积 反向传播背后的四个基本等式 四个基本等式的证明(选读) 反向传播算法 反向传播算法代码