神经网络基础篇:详解逻辑回归 & m个样本梯度下降
逻辑回归中的梯度下降
本篇讲解怎样通过计算偏导数来实现逻辑回归的梯度下降算法。它的关键点是几个重要公式,其作用是用来实现逻辑回归中梯度下降算法。但是在本博客中,将使用计算图对梯度下降算法进行计算。必须要承认的是,使用计算图来计算逻辑回归的梯度下降算法有点大材小用了。但是,认为以这个例子作为开始来讲解,可以使更好的理解背后的思想。从而在讨论神经网络时,可以更深刻而全面地理解神经网络。接下来让开始学习逻辑回归的梯度下降算法。
假设样本只有两个特征\({{x}_{1}}\)和\({{x}_{2}}\),为了计算\(z\),需要输入参数\({{w}_{1}}\)、\({{w}_{2}}\) 和\(b\),除此之外还有特征值\({{x}_{1}}\)和\({{x}_{2}}\)。因此\(z\)的计算公式为:
\(z={{w}_{1}}{{x}_{1}}+{{w}_{2}}{{x}_{2}}+b\)
回想一下逻辑回归的公式定义如下:
\(\hat{y}=a=\sigma (z)\)
其中\(z={{w}^{T}}x+b\)
\(\sigma \left( z \right)=\frac{1}{1+{{e}^{-z}}}\)
损失函数:
\(L( {{{\hat{y}}}^{(i)}},{{y}^{(i)}})=-{{y}^{(i)}}\log {{\hat{y}}^{(i)}}-(1-{{y}^{(i)}})\log (1-{{\hat{y}}^{(i)}})\)
代价函数:
\(J\left( w,b \right)=\frac{1}{m}\sum\nolimits_{i}^{m}{L( {{{\hat{y}}}^{(i)}},{{y}^{(i)}})}\)
假设现在只考虑单个样本的情况,单个样本的代价函数定义如下:
\(L(a,y)=-(y\log (a)+(1-y)\log (1-a))\)
其中\(a\)是逻辑回归的输出,\(y\)是样本的标签值。现在让画出表示这个计算的计算图。
这里先复习下梯度下降法,\(w\)和\(b\)的修正量可以表达如下:
\(w:=w-a \frac{\partial J(w,b)}{\partial w}\),\(b:=b-a\frac{\partial J(w,b)}{\partial b}\)
如图:在这个公式的外侧画上长方形。然后计算:
\(\hat{y}=a=\sigma(z)\)
也就是计算图的下一步。最后计算损失函数\(L(a,y)\)。
有了计算图,就不需要再写出公式了。因此,为了使得逻辑回归中最小化代价函数\(L(a,y)\),需要做的仅仅是修改参数\(w\)和\(b\)的值。前面已经讲解了如何在单个训练样本上计算代价函数的前向步骤。现在让来讨论通过反向计算出导数。
因为想要计算出的代价函数\(L(a,y)\)的导数,首先需要反向计算出代价函数\(L(a,y)\)关于\(a\)的导数,在编写代码时,只需要用\(da\) 来表示\(\frac{dL(a,y)}{da}\) 。
通过微积分得到:
\(\frac{dL(a,y)}{da}=-y/a+(1-y)/(1-a)\)
如果非常熟悉微积分,建议主动推导前面介绍的代价函数的求导公式,使用微积分直接求出\(L(a,y)\)关于变量\(a\)的导数。如果不太了解微积分,也不用太担心。现在已经计算出\(da\),也就是最终输出结果的导数。
现在可以再反向一步,在编写Python代码时,只需要用\(dz\)来表示代价函数\(L\)关于\(z\) 的导数\(\frac{dL}{dz}\),也可以写成\(\frac{dL(a,y)}{dz}\),这两种写法都是正确的。
\(\frac{dL}{dz}=a-y\) 。
因为\(\frac{dL(a,y)}{dz}=\frac{dL}{dz}=(\frac{dL}{da})\cdot (\frac{da}{dz})\),
并且\(\frac{da}{dz}=a\cdot (1-a)\),
而 \(\frac{dL}{da}=(-\frac{y}{a}+\frac{(1-y)}{(1-a)})\),因此将这两项相乘,得到:
\({dz} = \frac{{dL}(a,y)}{{dz}} = \frac{{dL}}{{dz}} = \left( \frac{{dL}}{{da}} \right) \cdot \left(\frac{{da}}{{dz}} \right) = ( - \frac{y}{a} + \frac{(1 - y)}{(1 - a)})\cdot a(1 - a) = a - y\)
博客中为了简化推导过程,假设\({{n}_{x}}\) 这个推导的过程就是之前提到过的链式法则。如果对微积分熟悉,放心地去推导整个求导过程,如果不熟悉微积分,只需要知道\(dz=(a-y)\)已经计算好了。
现在进行最后一步反向推导,也就是计算\(w\)和\(b\)变化对代价函数\(L\)的影响,特别地,可以用:
\(d{{w}_{1}}=\frac{1}{m}\sum\limits_{i}^{m}{x_{1}^{(i)}}({{a}^{(i)}}-{{y}^{(i)}})\)
\(d{{w}_{2}}=\frac{1}{m}\sum\limits_{i}^{m}{x_{2}^{(i)}}({{a}^{(i)}}-{{y}^{(i)}})\)
\(db=\frac{1}{m}\sum\limits_{i}^{m}{({{a}^{(i)}}-{{y}^{(i)}})}\)
博客中,
\(d{{w}_{1}}\) 表示\(\frac{\partial L}{\partial {{w}_{1}}}={{x}_{1}}\cdot dz\),
\(d{{w}_{\text{2}}}\) 表示\(\frac{\partial L}{\partial {{w}_{2}}}={{x}_{2}}\cdot dz\),
\(db=dz\)。
因此,关于单个样本的梯度下降算法,所需要做的就是如下的事情:
使用公式\(dz=(a-y)\)计算\(dz\),
使用\(d{{w}_{1}}={{x}_{1}}\cdot dz\) 计算\(d{{w}_{1}}\), \(d{{w}_{2}}={{x}_{2}}\cdot dz\)计算\(d{{w}_{2}}\),
\(db=dz\) 来计算\(db\),
然后:
更新\({{w}_{1}}={{w}_{1}}-a d{{w}_{1}}\),
更新\({{w}_{2}}={{w}_{2}}-a d{{w}_{2}}\),
更新\(b=b-\alpha db\)。
这就是关于单个样本实例的梯度下降算法中参数更新一次的步骤。
现在已经知道了怎样计算导数,并且实现针对单个训练样本的逻辑回归的梯度下降算法。但是,训练逻辑回归模型不仅仅只有一个训练样本,而是有\(m\)个训练样本的整个训练集。因此在下面讲解中,将这些思想应用到整个训练样本集中,而不仅仅只是单个样本上。
m个样本的梯度下降
在之前的博客中,已经看到如何计算导数,以及应用梯度下降在逻辑回归的一个训练样本上。现在想要把它应用在\(m\)个训练样本上。
首先,让时刻记住有关于损失函数\(J(w,b)\)的定义。
\(J(w,b)=\frac{1}{m}\sum\limits_{i=1}^{m}{L({{a}^{(i)}},{{y}^{(i)}})}\)
当的算法输出关于样本\(y\)的\({{a}^{(i)}}\),\({{a}^{(i)}}\)是训练样本的预测值,即:\(\sigma ( {{z}^{(i)}})=\sigma( {{w}^{T}}{{x}^{\left( i \right)}}+b)\)。
所以在前面是对于任意单个训练样本,如何计算微分当只有一个训练样本。因此\(d{{w}_{1}}\),\(d{{w}_{\text{2}}}\)和\(db\) 添上上标\(i\)表示求得的相应的值。如果面对的是之前的那种情况,但只使用了一个训练样本\(({{x}^{(i)}},{{y}^{(i)}})\)。
现在知道带有求和的全局代价函数,实际上是1到\(m\)项各个损失的平均。 所以它表明全局代价函数对\({{w}_{1}}\)的微分,对\({{w}_{1}}\)的微分也同样是各项损失对\({{w}_{1}}\)微分的平均。
但之前已经演示了如何计算这项,即之前是如何对单个训练样本进行计算。所以真正需要做的是计算这些微分,如在之前的训练样本上做的。并且求平均,这会给全局梯度值,能够把它直接应用到梯度下降算法中。
所以这里有很多细节,但让把这些装进一个具体的算法。同时需要一起应用的就是逻辑回归和梯度下降。
初始化\(J=0,d{{w}_{1}}=0,d{{w}_{2}}=0,db=0\)
代码流程:
J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
z(i) = wx(i)+b;
a(i) = sigmoid(z(i));
J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
dz(i) = a(i)-y(i);
dw1 += x1(i)dz(i);
dw2 += x2(i)dz(i);
db += dz(i);
J/= m;
dw1/= m;
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db
这里只应用了一步梯度下降。因此需要重复以上内容很多次,以应用多次梯度下降。看起来这些细节似乎很复杂,但目前不要担心太多。希望明白,当继续尝试并应用这些在编程作业里,所有这些会变的更加清楚。
但这种计算中有两个缺点,也就是说应用此方法在逻辑回归上需要编写两个for循环。第一个for循环是一个小循环遍历\(m\)个训练样本,第二个for循环是一个遍历所有特征的for循环。这个例子中只有2个特征,所以\(n\)等于2并且\({{n}_{x}}\) 等于2。 但如果有更多特征,开始编写的因此\(d{{w}_{1}}\),\(d{{w}_{2}}\),有相似的计算从\(d{{w}_{3}}\)一直下去到\(d{{w}_{n}}\)。所以看来需要一个for循环遍历所有\(n\)个特征。
当应用深度学习算法,会发现在代码中显式地使用for循环使的算法很低效,同时在深度学习领域会有越来越大的数据集。所以能够应用的算法且没有显式的for循环会是重要的,并且会帮助适用于更大的数据集。所以这里有一些叫做向量化技术,它可以允许的代码摆脱这些显式的for循环。
想在先于深度学习的时代,也就是深度学习兴起之前,向量化是很棒的。可以使有时候加速的运算,但有时候也未必能够。但是在深度学习时代向量化,摆脱for循环已经变得相当重要。因为越来越多地训练非常大的数据集,因此真的需要的代码变得非常高效。所以在接下来的几个博客中,会谈到向量化,以及如何应用向量化而连一个for循环都不使用。所以学习了这些,希望有关于如何应用逻辑回归,或是用于逻辑回归的梯度下降,事情会变得更加清晰。当进行编程练习,但在真正做编程练习之前让先谈谈向量化。然后可以应用全部这些东西,应用一个梯度下降的迭代而不使用任何for循环。
神经网络基础篇:详解逻辑回归 & m个样本梯度下降的更多相关文章
- JavaScript基础篇详解
全部的数据类型: 基本数据类型: undefined Number Boolean null String 复杂数据类型: object ①Undefined: >>>声明但未初始化 ...
- 走向DBA[MSSQL篇] 详解游标
原文:走向DBA[MSSQL篇] 详解游标 前篇回顾:上一篇虫子介绍了一些不常用的数据过滤方式,本篇详细介绍下游标. 概念 简单点说游标的作用就是存储一个结果集,并根据语法将这个结果集的数据逐条处理. ...
- RabbitMQ基础知识详解
什么是MQ? MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中 ...
- Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...
- Cisco路由技术基础知识详解
第一部分 请写出568A的线序(接触网络第一天就应该会的,只要你掐过,想都能想出来) .网卡MAC地址长度是( )个二进制位(16进制与2进制的换算关系,只是换种方式问,不用你拿笔去算) A.12 ...
- RabbitMQ,Apache的ActiveMQ,阿里RocketMQ,Kafka,ZeroMQ,MetaMQ,Redis也可实现消息队列,RabbitMQ的应用场景以及基本原理介绍,RabbitMQ基础知识详解,RabbitMQ布曙
消息队列及常见消息队列介绍 2017-10-10 09:35操作系统/客户端/人脸识别 一.消息队列(MQ)概述 消息队列(Message Queue),是分布式系统中重要的组件,其通用的使用场景可以 ...
- Python基础知识详解 从入门到精通(七)类与对象
本篇主要是介绍python,内容可先看目录其他基础知识详解,欢迎查看本人的其他文章Python基础知识详解 从入门到精通(一)介绍Python基础知识详解 从入门到精通(二)基础Python基础知识详 ...
- I2C 基础原理详解
今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...
- PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
PHP函数篇详解十进制.二进制.八进制和十六进制转换函数说明 作者: 字体:[增加 减小] 类型:转载 中文字符编码研究系列第一期,PHP函数篇详解十进制.二进制.八进制和十六进制互相转换函数说明 ...
- python 3.x 爬虫基础---Urllib详解
python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 前言 爬虫也了解了一段时间了希望在半个月的时间内 ...
随机推荐
- [NSSCTF 2022 Spring Recruit]babyphp
打开靶机,先看了一遍代码,发现要拿到flag,就必须先满足三个条件,即分别为a,b,c 第一层:需要a满足条件 isset($_POST['a'])&&!preg_match('/[0 ...
- SaaS模式相较传统CRM系统有何优势?
SaaS模式的CRM客户管理系统相较于传统的CRM客户管理系统更加方便灵活,更加符合如今的市场环境.它解决了传统CRM系统投入大.维护难的难题,降低了中小企业导入CRM的门槛.下面详细说说SaaS模式 ...
- JAVA类的加载(3) ——类加载后能够有效运行
例1: 1 package classobject; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Invo ...
- [Python急救站课程]汇率转换程序
汇率转换程序 i = input("请输入金额用"¥"或"$"结束:") if i[-1] in ['¥']: C = (eval(i[0: ...
- 二、RHEL8操作系统安装
一.如何安装rhel的操作系统? 必要的前提条件:硬件(CPU.内存.硬盘--) + 安装介质(操作系统的安装文件) 会不会把自己的笔记本装成rhel的操作系统呢? 不会 使用虚拟机软 ...
- AcWing 168. 生日蛋糕
原题链接:AcWing 168. 生日蛋糕 设当前体积是\(v,h.r\)分别记录每层的高度和半径,由于整个蛋糕的上表面面积等于最大蛋糕的圆面积,所以枚举到最大一层的时候直接加上即可. 优化搜索顺序: ...
- Java笔记——数组静态初始化开始
一维数组: 静态初始化: 定义格式:(1)数据类型[] 数组名 = new 数组类型[] (2)数组类型[] 数组名 ={元素1,元素2,.....} 练习:数组元素逆序: public static ...
- 手把手教Electron+vue,打包vue项目,打包成桌面程序。
1.现如今前端框架数不胜数,尤其是angular.vue吸引一大批前端开发者,在这个高新技术快速崛起的时代,自然少不了各种框架的结合使用.接下来是介绍electron+vue的结合使用. 2.Elec ...
- 简易的git命令行入门教程
一.Git 全局设置 git config --global user.name "用户名" git config --global user.email "邮件地址@1 ...
- Go语言数组与切片学习总结
一.数组 数组的定义:相同类型的数据集合 go语言中数组的索引从0开始 没有赋值的数值型数组,默认值为0 数组一旦被创建,它的大小就是不可改变的 (1)声明数组与打印 var 变量名 [大小]变量类型 ...