吴恩达神经网络和深度学习心得总结(一):神经网络基础和logistic回归

1.什么是神经网络和深度学习

神经网络是一种我们用于预估数据的数学模型。它就像是一个黑匣子,当我们输入一些参数的数值时,通过神经网络我们就可以得到另一些参数的预测值,从这一点来看,神经网络与我们学习自动控制原理和现代控制理论时所接触到的传递函数或是状态空间有一些类似,不同的是我们对于传递函数和状态空间的内部结构是知道的,而神经网络内部的结构我们不知道也不需要知道,从某种意义上讲,不需要知道神经网络内部的规则也正是它的优势所在。

下面我们看一个最简单的神经网络的例子。

假设我们现在手里有若干组数据,每组数据包含两个参数:房屋的面积和它的价格。现在我又有了一个房屋面积的数值,我想利用之前的数据来预测这个房屋的价格该怎么办?

如果我们学过线性回归,我们会知道,通过之前的若干组数据,我们可以将房屋价格与面积的对应关系拟合成如下图的修正线性函数。这里之所以要修正是因为房屋的价格不能出现负值。

有了这个对应函数,我们只要将房屋的面积带入,便可以得到其对应的价格。抽象出来就是,我们输入房屋的size(面积),经过一个对应函数的运算,得到这个房屋的price(价格)。中间的这个对应函数就是一个最简单的神经网络模型。

下面我们将这个问题稍微复杂化一些,我们知道房屋的价格不可能单单只由面积决定,现在我们不仅对房屋的面积做出调查,同时还对每个房屋的卧室数量,邮编和区域富裕程度作出调查,这时我们同样得到若干组数据,每一组包含五个参数,分别是房屋的size(面积),bedrooms(卧室数量),zip code(邮编),wealth(区域富裕程度)和price(价格)。我们可以通过这些数据找到价格与其他四个参数之间的大致关系,但我们同时也可以发现这四个参数之间并不是独立的,换句话说,他们是有关联的:面积和卧室数量可以一定程度上表征了房屋可以容纳的家庭成员数量,邮编可以表征到其他地区的距离,邮编和区域富裕程度一起,又可以表征周边学校的质量。这样一来我们可以先从输入的四个参数首先预估容纳的家庭成员数量,到其他地区的距离,周边学校的质量这三个参数,而后再由这三个参数进一步预估房屋的价格。

这样我们就得到了一个稍微复杂一些的神经网络模型,我们管size,bedrooms,zip code,wealth叫做输入层,管familily size,walkability,school quality叫做中间层,管price叫做输出层。我们将这种神经网络叫作多层神经网络。有了神经网络和输入层数据,我们便可以预测输出层的数据。

那么我们如何得到一个优良的神经网络模型呢?方法就是用许多现成的输入输出数据来训练神经网络,使神经网络模型的预估越来越准,直到达到我们的要求。深度学习就是一种训练神经网络的方法。深度学习神经网络一般来说具有多级隐层。所谓的训练就是指利用深度学习,逐渐优化我们的神经网络,使神经网络的各项参数最终达到最佳,这样我们搭建的神经网络才会具有较强的预测功能。下面我们具体来看看参数是如何经过训练达到最佳的。

2.logistic回归

logistic回归适用于二分分类的情况,所谓的二分分类就是预估结果只有两种,‘是’或者‘不是’,一般我们用1来表示‘是’,用0来表示‘不是’。下面我们来看一个例子:假如我给我的神经网络输入一张图片,我想要得出这张图片是否是猫这一结论,这是便可以用logistic回归来解决。

首先,我们虽然输入的是一张图片,但在电脑存储过程中是以三个矩阵来进行存储的,这三个矩阵分别对应着红,绿,蓝这三种颜色的数值。假设我们的像素是64 * 64的,那么将这张图片划分成64 * 64这么多个小格,提取每种颜色的数值,再将同一个颜色组成一个矩阵,那么便可以得到3个64 * 64的矩阵。

我们习惯性将这三个矩阵中的数值首尾相连,得到一个列向量x,这个列向量同样包含这个图片的所有特征。

之前介绍线性回归时说到,起预测作用的神经网络其实就是某种函数,我们仿照线性函数 y=kx+b 的形式,令 \tilde{y}=w^{T}*x+b , w是与x同长度的列向量,这样得到的就是一个数。确切的说应该是一个概率, \tilde{y}=P(y=1|x) ,即当输入为X向量时, \tilde{y}=1 的概率,这样当y估计贴近1时,我们认为判定结果贴近‘是猫’,y估计趋近于0,我们认为判定结果趋近‘不是猫’。由于y估计是一个概率,因此必须介于0和1之间,但这样定义的y估计不一定在0和1之间,于是我们想了个办法,重新定义y估计,令

\tilde{y}=\sigma(w^{T}x+b)

sigmoid函数的定义为

\sigma(z)=\frac{1}{1+e^{-z}}

sigmoid函数的图像如下:

由图像我们可以看到,经过sigmoid函数的处理,就可以将输出控制在0和1之间了。 也就是说,只要给我们一张图片,那我们就可以通过上述运算来确定它是猫的概率有多大,进而判定这张图片到底是不是一只猫。但是我们可以发现,在上述神经网络,或是函数运算中,向量 w 和数b都是未知的,我们只有通过大量的样本和结论来训练神经网络,才能找到合适的参数 w和b,那具体是怎么操作的呢?下面我们引入一些新的函数,通过这些新的函数,我们可以最终找到合适的参数 w和b,完成训练。

3.Loss function和cost function

loss function又叫损失函数,它表征了估计的准确性。我们定义损失函数 :L(\tilde{y},y)=-yln\tilde{y}-(1-y)ln(1-\tilde{y})

当y=1时, L=-lny ,若 \tilde{y}=1 ,则L=0,表示估计误差几乎不存在,估计准确;

若 \tilde{y}=0 ,则L=正无穷,表示估计误差非常大,估计不准确。

当y=0时, L=-ln(1-y) ,若 \tilde{y}=1 ,则L=正无穷,表示误差非常大,估计不准确;

若 \tilde{y}=0 ,则L=0,表示估计误差几乎不存在,估计准确。

由此可见,损失函数可以很好的表征单一样本下估计值 \tilde{y} 和真实值y(y=1或0)之间的误差。但我们知道,作为训练用的样本数据绝不可能只有一个,于是我们引入m个样本损失函数的算数平均值作为cost function,即成本函数,用符号J来表示,定义成本函数:

J(w,b)=\frac{1}{m}\sum_{i=1}^{m}{L(\tilde{y}^{(i)},y^{(i)})}

成本函数表征了训练集中所有预估的综合误差,J越小表示误差越小,预估越准,反之亦然。

4.梯度下降法

训练的目的是找到合适的参数w和d,那么判断w和d是否合适的标准是什么呢?这就用到了我们之前说的成本函数,由于成本函数表征了误差的大小,那么使成本函数最小的参数w和b便是我们要寻求的最优值。这样当下一个特征向量输入进来时,我们估计得才会最准。成本函数与参数w和b的大致图像如下所示:

我们可以看到,对应J最小值和w和d是唯一的,这时我们便可以取任意的初始值,而后采用迭代的手段找到最优解。即:

w:=w-\alpha\frac{dJ}{dw}

其中w:表示下一次的w取值, \alpha 为常数。从上式可以看出,只要J不是最小值,那么下一次的w取值便会让J向着最小点前进,直到 \frac{dJ}{dw}=0 时停止,此时J取到最小值。同理,我们也可以得出d的迭代公式:

b:=b-\alpha\frac{dJ}{db}

由此可见,只要求得J对w和b的导数,我们便可以进行迭代,从而完成训练。下面我们来介绍求得J对w和b的导数的具体方法。

5.正向传播与反向传播

所谓的正向传播指的就是用训练集数据x求得成本函数的过程,为了便于区分 \tilde{y} 和y,我们用符号a来代替 \tilde{y} ,我们总结一下正向传播的过程:

z^{(i)}=\sum_{j=1}^{n}{w_{j}x_{j}^{(i)}}+b

a^{(i)}=\sigma(z^{(i)})

L^{(i)}=-y^{(i)}lna^{(i)}-(1-y^{(i)})ln(1-a^{(i)})

J=\frac{1}{m}\sum_{i=1}^{m}{L^{(i)}}

其中j大于0小于等于n,n为向量x的长度;i大于0小于m,m为训练样本个数。

反向传播是指我们求得 \frac{dJ}{dw_{j}} 和 \frac{dJ}{db} 的过程,由于求导遵循链式法则,所以我们一般从后向前进行求导,故称反向传播:

\frac{dJ}{dL^{(i)}}=\frac{1}{m}

\frac{dL^{(i)}}{da^{(i)}}=-\frac{y^{(i)}}{a^{(i)}}+\frac{1-y^{(i)}}{1-a^{(i)}}

\frac{da^{(i)}}{dz^{(i)}}=a^{(i)}(1-a^{(i)})

\frac{dz^{(i)}}{dw_{j}}=x_{j}^{(i)}

\frac{dz^{(i)}}{db}=1

有了上述式子,我们便可以计算需要的 \frac{dJ}{dw_{j}} 和 \frac{dJ}{db} 了,下面我们看具体的计算过程

\frac{dJ}{dw_{j}}=\frac{1}{m}\sum_{i=1}^{m}{\frac{dL^{(i)}}{da^{(i)}}*\frac{da^{(i)}}{dz^{(i)}}*\frac{dz^{(i)}}{dw_{j}}}

\frac{dJ}{db}=\frac{1}{m}\sum_{i=1}^{m}{\frac{dL^{(i)}}{da^{(i)}}*\frac{da^{(i)}}{dz^{(i)}}*\frac{dz^{(i)}}{db}}

带入计算可得:

\frac{dJ}{dw_{j}}=\frac{1}{m}\sum_{i=1}^{m}{(a^{(i)}-y^{(i)})x_{j}^{(i)}}

\frac{dJ}{db}=\frac{1}{m}\sum_{i=1}^{m}{(a^{(i)}-y^{(i)})}

这样我们便可以进行先定一个初始值,而后迭代运算,完成训练。

6.编程实现

由上述思路,我们尝试进行编程实现,在编程语言中,由于求导的分子均为dJ,故我们对其进行省略,比如用dw代替dJ/dw。

首先进行初始值和循环设定:

For j=1 to n;

For i=1 to m;

J=0, dw_{j}=0 ,db=0;

然后是正向传播:

z^{(i)}=w^{T}x^{(i)}+b ;

a^{(i)}=\sigma(z^{(i)}) ;

L^{(i)}=-y^{(i)}lna^{(i)}-(1-y^{(i)})ln(1-a^{(i)})

J+=L^{(i)} ;

J/=m ;

然后是反向传播:

dw_{j}+=(a^{(i)}-y^{(i)})x_{j}^{(i)} ;

db+=a^{(i)}-y^{(i)} ;

dw_{j}/=m ;

db/=m ;

最后是用梯度下降法进行迭代:

w_{j}:=w_{j}-\alpha*dw_{j} ;

b:=b-\alpha*db 。

7.向量化

上面所说的程序运行其实是有缺点的,在编程过程中由于for循环会大大降低程序运行效率,所以我们尽可能减少使用for循环,于是我们想到了向量化的办法。 所谓向量化,其实就是利用矩阵运算来代替循环。我们采用将单个样本的各个函数分别集成矩阵的方式来简化步骤,首先,我们要将各个函数集成为矩阵:

W=[w_{1},w_{2}...w_{m}]

X=[x^{(1)},x^{(2)}...x^{(m)}]

B=[b,b...b]

Z=[z^{(1)},z^{(2)}...z^{(m)}]

A=[a^{(1)},a^{(2)}...a^{(m)}]

Y=[y^{(1)},y^{(2)}...y^{(m)}]

dW=[dw_{1},dw_{2}...dw_{m}]^{T}

接下来进行正向传播:

Z=W^{T}X+B

A=\sigma(Z)

然后是反向传播:

dW=\frac{1}{m}X(A-Y)^{T}

db=\frac{1}{m}||A-Y||

最后进行梯度下降迭代:

W:=W-\alpha*dW

b:=b-\alpha*db

8.向量化后的编程实现:

根据以上思路,我们可以得到简化后编程实现:

import numpy as np

Z=np.dot(W,X)+b

A=\sigma(Z)

dW=\frac{1}{m}X(A-Y)^{T}

db=\frac{1}{m}np.sum(A-Y)

W:=W-\alpha*dW

b:=b-\alpha*db

至此我们便得到一个用python实现的logistic回归。

展开阅读全文

没有更多推荐了,返回首页