如何通过编程去实现一个逻辑回归?

 
事实上,在你实现一个神经网络的过程中,编程技巧是非常重要的。
例如,当你的训练集有m个样本的时候,一种最普通的方式是使用一个循环来遍历所有的样本。
然而,在学习完本节的课程后,你将会学到一些更优雅且高效的方法。
此外,在本节课中,我们还将会讲解神经网络的训练过程中为什么会用到前向传播和反向传播,以及前向传播与反向传播表示的含义。
为了使本节内容更加容易理解,我们将以逻辑回归为例,来讲解之前的知识点。
相信即使你之前对逻辑回归有一定的了解,你也能从本课程中学到一些不一样的知识。
下面就开始本节课的学习吧!
 

问题描述

逻辑回归是一个用于二分类的算法。
现在我们来看这样一个二分类的问题:给你一副图片,你需要判断这副图片中的内容是不是猫。如果是猫的话,输出为1,否则输出为0。
我们用x表示输入图像,用y表示输出的标签。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
对于上面这副图像,我们需要用一个三个矩阵来表示该图像。三个矩阵分别对应着R、G、B图像。
假设我们输入图像的大小为64*64,那么我们的整个输入图像的存储大小为3*64*64。
为了将整个图像作为一个输入向量,我们需要对该图像进行转换,转换最终的结果将会得到一个长度为64*64*3=12288的向量。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
此时,我们认为我们输入向量的长度为12288。记作nx=12288。

目前,我们需要设计的一个二分类器就是接收一个长度为12288的特征向量x,并得到一个预测结果y(可以是0或者1)。

 

数学符号


现在,让我们来梳理一下本课程会涉及到的一些数学符号。

一对训练Case我们记作是(x, y),其中x表示的输入特征向量,y表示的是输出标签。

训练集的规模使用小写字母m来表示。

即(x1, y1)表示第一对训练用例,(x2, y2)表示第二对训练用例...(xm, ym)表示第m对训练用例。

此外,我们用大写的X表示整个训练集。

其中,x1,x2,xm分别表示X的第1列、第二列和第m列。且每个x的长度为nx。即X的大小为nx*m。在Python代码中:
  1. X.shape = (nx, m)
接下来,我们讨论一下输出。为了与输入一致,我们同样需要定义一个大写字母Y。
其中,Y是由y1,y2...ym组成。即Y的大小为1*m。即
  1. Y.shape = (1, m)
接下来,我们将用这些符号在辅助讲解逻辑回归算法。
 

逻辑回归

接下来,我们将详细学习逻辑回归算法。
逻辑回归可以用于监督学习且输出为0或者1的二分类问题。
给定一个表示一副图像的特征向量x,需要判断出该图像的内容是否是一只猫,这就是一个典型的二分类问题。
我们希望通过逻辑回归算法得到一个预测值,称之为^y,即对y的估计。
更加严谨的说:^y是在给定输入x后,y输出值等于1的概率。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
正如我们上一小节所说,x是一个nx维的向量。
此时,我们逻辑回归中需要估计的参数w也是一个nx维的向量,此外还包含一个标量b。
对于一个定给的输入x,以及参数w和b,我们就可以计算^y了。
首先,我们可以假设通过以下公式进行计算:
^y = wTx+b
然而, 实验发现,这种线性关系用于二分类问题效果并不理想。
主要原因是我们假设^y表示y=1的概率,那么^y的值应该介于0到1之间。
而通过简单的线性关系,很难保证^y在0到1之间。
因此,我们用wTx+b的值作为sigmod函数的参数,此时,函数的输出结果可以保证始终在0到1之间。如下图所示:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
其中,横轴z表示wTx+b,纵轴则表示^y。
从上图可以看出,当z很大是,输出结果趋近于1;
当z是一个很小时,输出结果趋近于0;
当z为0时,输出结果为0.5。
正好满足我们对^y的预期,函数的输出结果可以保证始终在0到1之间。
总结如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming) 

逻辑回归代价函数

在上一节中,我们已经了解了基本的逻辑回归模型。
为了能够训练得到参数w和b,我们需要定义一个误差函数。
对于一组训练集大小为m的场景而言,满足如下估计值如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
其中^y(i)表示第i个训练Case得到的估计结果。我们期望对于每一组训练样本而言,真实值与估计值尽可能的相等。
Ps:在本系列课程中,上角标也用圆括号()包围时,表示的是第几个训练样本。
接下来,我们继续讨论代价函数。
一种简单的想法是可以使用均方差,例如如下形式:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
然而,实际使用中,我们会发现一个问题,该误差函数是非凸的。
对于非凸函数,我们在求解最优解时,将带来很大的困难,因为此时梯度下降法找到的并不一定是全局最优解,而有可能是局部最优解。
在实际应用中,我们常用的一个误差函数如下:
神经网络编程基础(Basics Of Neural Network Programming)(这里少半边括号)
神经网络编程基础(Basics Of Neural Network Programming)
该误差函数是一个凸函数同时易于寻找最优解。
我们期望该误差函数的值越小越好。
为了更好的理解该误差函数,我们用两个极端的例子来了解该误差函数。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
当真实结果y等于1时,为了使误差函数的值越小,我们希望^y越大越好。
当真实结果y等于0时,为了使误差函数的值越小,我们希望^y越小越好。
此外,由于^y是sigmod函数的输出值,因此可以保证^y总是在0到1之间。
因此,直观上,我们可以发现该误差函数可以很好的反映出真实结果和预测结果的差异。
此外,在文本的最后,我们还将用一个小节额外补充一些选择该误差函数的内在原因。
对于一个单样本点而言,误差函数L(损失函数)的定义如之前所述。
而对于整体的训练集而言,用代价函数J来进行描述。
函数形式如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
从上式可以函数,代价函数的计算方式实际上是训练集中每个训练样本的损失函数的平均值。
因此,对于一个逻辑回归问题而言,我们就是期望寻找恰当的w和b,使得最终的J尽可能的小。
此时,我们可以把逻辑回归视作是一个非常小型的神经网络。

梯度下降法

在前面的内容中,我们已经讲解了逻辑回归模型、单样本的误差函数和整体的代价函数。
现在,我们将要学习的是如何利用梯度下降法去训练w和b参数。
下面,我们用一个例子来直观的了解一下什么是梯度下降法。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
如上图所示,我们假设w和b都是一个标量(Ps:实际中w是一个矢量),那么J可能取到的值是由w和b生成的曲面上的点。
J的最小值,也就是对应着该曲面的底点。
很容易观察到,上图是一个碗状的图形,因此是J是一个凸函数。
而对于下图,则是一个非凸函数,它有着很多的局部最小值。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
因此,我们之前的设计这样的代价函数主要是为了保证其为凸函数。
为了去找到一个最优值,我们首先需要给w和b一个初始值,例如图像上的一个红点。
Ps:对于逻辑回归和一切其他算法而言,一种常用的方式是将初始值设置为0。此外,还有一些算法可能会用到随机初始值的方法。
由于该函数是一个凸函数,因此无论你的初始值在什么位置,最终得到的结果都是非常近似的。
梯度下降法指的是在给定一个初始值后,始终沿着当前最陡峭的下降方向进行移动
在经过一系列迭代后,我们将会得到一个近似于最优解的点。
为了更简化的描述这一问题,我们假设代价函数J仅仅和w有关,即我们期望优化一个函数J(w)。
那么,w的优化过程如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
w通过不断的向最陡峭的方向移动(不断更新w),来不断的减小代价函数J。
其中,神经网络编程基础(Basics Of Neural Network Programming)表示的是学习速率(正数)。用于控制我们在每一次迭代的过程中移动的距离有多远。
此外,在这个公式中,我们提到的导数概念。
Ps:在后续的编程过程中,我们会用dw表示J对w对导数。
梯度表示的是一个点的斜率的概念。而斜率我们可以认为是高度除以宽度。
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
以上图为例,当w位于最优点右侧时,其随着宽度的增加,高度也在不断增加,因此斜率是正数,即dw>0。因此,在迭代过程中,w的值会不断减小(w:=w-adw)。
而当w位于最优点左侧时,其随着宽度的增加,高度确在不断减小,因此斜率是负数,即dw<0。因此,在迭代过程中,w的值会不断增加(w:=w-adw)。

在实际代价函数中,J是关于w和b的函数。
所以实际上,每次的迭代过程如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)

利用梯度下降法解决逻辑回归问题

首先,我们回顾一下之前的内容:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
z, ^y以及L的定义如上所示。具体表示的含义我们也已经在上文讲到了。
假设w是长度为2的向量,即w=[w1, w2]2,那么变量之间的关系如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
在前向传播过程中,我们首先根据样本x1,x2和参数w以及b可以计算得到z。
接着,将z作为参数传递给sigmod函数可以得到a。
最终,根据a和真实结果可以得到单个样本的误差函数y。
接下来,我们讨论的是如何利用反向传播来计算dw和db。
首先,我们需要计算da:
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
接下来需要计算dz:其中sigmod函数如下:神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
其中:
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
即dz = a - y
最终,我们需要计算的是dw1, dw2和db,分别计算结果如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
当我们计算得到w和b的变化量后,即可计算w和b的迭代值了:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)

多训练样本时的梯度下降法

之前的内容中,我们已经学会了如何针对单个样本计算导数。
接下来,我们将学习代价函数J的导数的计算。
回顾一下之前代价函数J的计算公式:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
而对J求w1导数后,得到的结果如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
而其中:
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)

神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)
因此,对多个样本求导数则相当于对每个样本求导数后取其平均值。
具体实现过程如下:
Step1:初始化J=0,dw1=0,dw2=0,db=0。
Step2:遍历每一个迭代样本:
    Step2.1:根据w(i),x(i),b(i)计算z(i)
    Step2.2:根据z(i)计算a(i)
    Step2.3:根据y(i)和a(i)计算当前样本的误差
    Step2.4:计算dz(i)
    Step2.5:计算当前样本产生的dw1(i), dw2(i)和db(i)
Step3:根据所有样本的误差计算当前时刻的代价函数
Step4:根据所有样本的dw1(i), dw2(i)和db(i)计算最终的dw1,dw2和db。
Step5:更新一次w1,w2和b后返回Step2。
即伪代码如下:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)

神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
选择该代价函数的内在原因
在之前的课程中,我们选取了如下的代价函数:
神经网络编程基础(Basics Of Neural Network Programming)
在本文的最后,我们来分析一下为什么选择这样一个代价函数。
在之前的课程中,我们提到^y的定义如下:
 神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)神经网络编程基础(Basics Of Neural Network Programming)    神经网络编程基础(Basics Of Neural Network Programming)
 其中,^y可以认为是给定一个x后,输出y等于1的概率。即
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
分析以下两种情况:
1. 当y=1时,P(y|x) = P(y=1|x) = ^y。
2. 当y=0时,P(y|x) = 1 - P(y=1|x)=1 - ^y。
为了满足以上两种情况,人们提出了如下一个概率函数:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
当y=1和y=0两种情况下,都满足我们之前提到的条件。
对P(y|x)取对数后,可以得到如下结果:
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
神经网络编程基础(Basics Of Neural Network Programming)
而在优化的过程中,我们希望不断的最大化P(y|x)。
其中,对数函数log为单调递增,因此,最大化P(y|x)等价于最大化其对数,也就相当于最小化L。

Python Basics with Numpy作业点击打开链接

Logistic Regression with a Neural Network作业点击打开链接



相关文章:

  • 2021-04-02
  • 2021-08-28
  • 2021-06-18
  • 2021-08-11
  • 2021-09-13
  • 2022-01-06
  • 2021-09-19
  • 2021-09-28
猜你喜欢
  • 2022-01-14
  • 2021-10-11
  • 2021-04-10
  • 2022-01-13
  • 2021-05-08
  • 2022-01-17
  • 2021-10-05
相关资源
相似解决方案