一、逻辑回归的局限

在逻辑回归一节中,使用逻辑回归的多分类,实现了识别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 : mY(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

机器学习之五:神经网络、反向传播算法推导相关推荐

  1. 【机器学习笔记】神经网络反向传播算法 推导

    神经网络反向传播算法 推导 (一) 概念及基本思想 (二)信息的前向传播 (三)误差反向传播 (1)输出层的权重参数更新 (2)隐藏层的权重参数更新 (3)输出层与隐藏层的偏置参数更新 (4)反向传播 ...

  2. 吴恩达机器学习:神经网络 | 反向传播算法

    上一周我们学习了 神经网络 | 多分类问题.我们分别使用 逻辑回归 和 神经网络 来解决多分类问题,并了解到在特征数非常多的情况下,神经网络是更为有效的方法.这周的课程会给出训练 神经网络 所使用的 ...

  3. 神经网络反向传播算法推导

    反向传播是多数神经网络进行参数更新的基本方法,它的本质是巧妙利用了高数中的链式法则,下面对这一方法进行推导: (1)符号说明 :神经元的激活函数 :神经网络的权重向量 :神经网络的偏置向量 :某层的输 ...

  4. 收藏 | 人人都能看懂的LSTM介绍及反向传播算法推导

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者:陈楠 来源:知乎 链接:https://zhuanla ...

  5. 反向传播算法推导、激活函数、梯度消失与爆炸

    目录 反向传播算法 定义 推导过程 激活函数 定义 性质 常用的激活函数 Sigmoid Tanh ReLU softmax 梯度消失与梯度爆炸 起因 出现的原因 表现 解决方案 参考文档 反向传播算 ...

  6. 反向传播算法推导(交叉熵代价函数-吴恩达机器学习)

    0. 前言 第一次看吴恩达老师机器学习视频时, 在9.29.29.2节卡住.看到评论区别人解答(Arch725 的解答)发现有一些疏漏,而且缺少一些铺垫,所以进行了一些修改补充. 本文的反向传播算法的 ...

  7. BP神经网络(反向传播算法原理、推导过程、计算步骤)

    BP神经网络 1.反向传播算法的原理 2.反向传播算法参数学习的推导 3.反向传播算法参数更新案例 3.1 反向传播的具体计算步骤 3.1.1 计算输出层的误差 3.1.2 计算隐藏层误差 3.1.3 ...

  8. 卷积神经网络(CNN)反向传播算法推导

    作者丨南柯一梦宁沉沦@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/61898234 编辑丨极市平台 导读 在本篇文章中我们将从直观感受和数学公式两方面来介绍CNN反 ...

  9. 神经网络之误差反向传播算法推导

    原理 误差反向传播算法是通过误差函数计算实际输出值与期望输出值之间的误差,把误差从最后的输出层依次传播到之前各层,最后通过调整各层连接权重与偏置达到减小误差的目的.而权重和偏置的调整一般使用梯度下降法 ...

最新文章

  1. c语言相邻字符串字面量,C语言预处理#运算符的细节
  2. Android架构篇-4 架构模式MVVM
  3. Github标星57k+,热榜第一,用Python实现所有算法
  4. winform 外部组件发生异常
  5. IIS7.5部署ASP.NET失败
  6. 同一台服务器,mysql登录不了指定端口的问题
  7. 类似TH养车的电商系统设计思路
  8. WPSmushProv3.7.0图片上传压缩插件-WordPress图像优化插件
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的眼镜店仓库管理系统
  10. Android:ViewFlipper、幻灯片
  11. No module named ‘win32gui‘ 的解决方法(踩坑之旅)
  12. CSS3 Media Queries模板
  13. ubuntu 22.04安装微信QQ阿里旺旺等
  14. 为什么使用LINUX(有点长,没耐心别看)大家自己体会
  15. 计算机课英语谐音,各科老师“谐音梗”大集合,英语课现“脏话”,数学化身段子手...
  16. python自动获取邮件数据_Python 提取数据库(Postgresql)并邮件发送
  17. 基于1939协议的发动机控制程序:包括发动机转速油门控制,发动机常用转速、机油压力、水温、工作小时读取,spn故障码取,发动机启动转速保护
  18. MySQL 基操教程(五) SELECT 数据查看之大于、小于
  19. Telelogic Tau 第二代
  20. 立大志为什么得不了中志? 我们缺少了合理期望

热门文章

  1. 业务团队如何统一架构设计风格?
  2. 一文搞定 Docker 容器技术与常用命令
  3. java 转jsp_【转】JSP三种页面跳转方式
  4. 45岁码农用不到2年时间撸出100款扑克游戏
  5. sqlserver数据恢复(100%可用)
  6. 使用flush-logs命令重新生成MySQL的相关日志文件
  7. JAVA 中的数据结构
  8. 【读书】《非暴力沟通》
  9. ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo
  10. 基于CefGlue的桌面应用开发