李鹏伟的技术博客

  • 首页

  • 分类

  • 归档

  • 关于

反向传播与梯度下降

发表于 2018-08-01 | 更新于 2018-08-11

反向传播

举个例子

BP 第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间连接的权重,激活函数我们默认为sigmoid函数。

1
2
3
4
其中,输入数据  i1=0.05,i2=0.10;
输出数据 o1=0.01,o2=0.99;
  初始权重 w1=0.15,w2=0.20,w3=0.25,w4=0.30;
w5=0.40,w6=0.45,w7=0.50,w8=0.55

目标:给出输入数据i1,i2(0.05和0.10),使输出尽可能与原始输出o1,o2(0.01和0.99)接近。

1.前向传播(输入层-隐含层)

计算神经元h1的输入加权和: $$ out_{h_{i}}=\sigma(w_{i}*i_{i} + w_{i}*i_{i} + b_{i}*1) $$ 则计算结果分别为: $$out_{h1}=0.593269 $$ $$out_{h2}=0.596884 $$

前向传播(隐含层-输出层)

同样的方法$$ out_{o_{j}}=\sigma(w_{j}*out_{h_{j1}} + w_{j}*out_{h_{j2}} + b_{j}*1) $$ 则计算结果为: $$out_{o1}=0.751365 $$ $$out_{o2}=0.772928 $$ 这样前向传播的过程就结束了,我们得到输出值为[0.751365, 0.772928],与实际值[0.01, 0.99]相差还很远,现在我们对误差进行反向传播,更新权值,重新计算输出。

2.反向传播

计算总误差(均方误差)

$$ E_{total} = \sum\frac{1}{2}(target-output)^{2} $$所以$$E_{total}=E_{o1}+E_{o2}=0.274811+0.023561 = 0.298371 $$

隐含层的权重更新

以权重$w_{5}$为例,如果我们想知道$w_{5}$对整体误差产生了多少影响,可以用整体误差对$w_{5}$求偏导求出(链式法则): $$\frac{\partial E_{ total}}{\partial w_{5}}=\frac{\partial E_{total}}{\partial out_{w_{5}}}*\frac{\partial out_{w_{5}}}{\partial w_{5}}$$ 接下来是复合函数求导,先对sigmoid求导,在对$w_{5}$求导。最终我们得到的结果是: $$\frac{\partial E_{ total}}{\partial w_{5}}=-(target_{o1}-out_{o1})out_{o1}(1-out_{o1})out_{h1}$$总结一下就是:误差激活函数梯度上一层的输出值,为了表示方便,我们用$\delta_{o1}$来表示输出层的误差,$$ \delta_{o1} = -(target_{o1}-out_{o1})*out_{o1}(1-out_{o1}) $$ $$ \frac{\partial E_{ total}}{\partial w_{5}}=\delta_{o1}out_{h1} $$ 最后我们来更新$w_{5}$的值:$$ w_{5}^{+} = w_{5} - \eta\frac{\partial E_{ total}}{\partial w_{5}}=0.4-0.010.082167=0.358916 $$这里$\eta=0.01$,表示学习率,同理,可以更新所有的$w$值。 GD 重复迭代次数可以使得总误差越来越接近真实值。

梯度下降

1.先做一道数学题

用最速下降法求解无约束非线性规划问题,$$ minf(X)= x_{1}-x_{2}+2x_{1}^{2}+2x_{1}x_{2}+x_{2}^{2} $$,其中$X=(x_{1},x_{x2})^\mathrm{T}$,要求选取初始点$X^{1}=(0,0)^\mathrm{T}$,终止误差$\varepsilon=0.5$ 解:目标函数的梯度$\nabla f(x)=\begin{bmatrix} \frac{\partial f(x)}{\partial x_{1}} \ \frac{\partial f(x)}{\partial x_{2}} \end{bmatrix} = \begin{bmatrix} 1+4x_{1}+2x_{2} \ -1+2x_{1}+2x_{2} \end{bmatrix}$, $\nabla f(X^{1})=\begin{bmatrix} 1 \ -1 \end{bmatrix}$令搜索方向$d^{1}=-\nabla f(x^{1})$,再从$X^{1}$出发,沿着$d^{1}$方向作一维寻优,令步长变量为$\lambda$,最优步长为$\lambda_{1}$,则有$$ X^{1}+\lambda d^{1}= \begin{bmatrix} 0 \ 0 \end{bmatrix} + \lambda \begin{bmatrix} -1 \ 1 \end{bmatrix}=\begin{bmatrix} -\lambda \ \lambda \end{bmatrix}$$, 故有$f(x)=f(X^{1}+\lambda d^{1})=(-\lambda)-\lambda + 2(-\lambda)^2+2(-\lambda)\lambda + \lambda ^{2}=\lambda ^{2}-2\lambda=\varphi_{1}(\lambda)$,令$\varphi_{1}(\lambda)=0$可得,$\lambda_{1}=1$,则$X^{2}=X^{1}+\lambda_{1}d^{1}=\begin{bmatrix} -1 \ 1 \end{bmatrix}$,求出$X^{2}$之后,与上类似地,进行第二次迭代:$\nabla f(X^{2})= \begin{bmatrix} -1 \ 1 \end{bmatrix}$,令$d^{2}=-\nabla f(X^{2})$,令步长变量为$\lambda$,求出最优步长$\lambda_{2}$,固有$f(x)=f(X^{2}+\lambda d^{2})=0$,求得$\lambda_{2}=\frac{1}{5}$, 同理:$X^{3}=X^{2}+\lambda_{2}d^{2}=\begin{bmatrix} -0.8 \ 1.2 \end{bmatrix}$,此时$\nabla f(X^{3})=\begin{bmatrix} 0.2 \ -0.2 \end{bmatrix}$,此时所达到的精度$\begin{Vmatrix} \nabla f(X^{3}) \end{Vmatrix}\approx 0.2828$,故此题的最优解$X^{}=\begin{bmatrix} -1 \ 1.5 \end{bmatrix}$,$f(X^{})=-1.25$

从上述题目中可以总结梯度下降法的一般迭代步骤:
  • 先确定向下一步的步伐大小,我们称为Learning rate;
  • 任意给定一个初始值;
  • 确定一个向下的方向,并向下走预先规定的步伐,并更新初始值;
  • 当下降的高度小于某个定义的值,则停止下降;

更新初始值的方法:$\theta^{n+1}=\theta^{n}-\eta\nabla C(\theta^{n})$

2.梯度下降原理

导数的概念:$$ f'(x_{0})= \lim_{\Delta x \to 0}\frac{\Delta y}{\Delta x} = \lim_{\Delta x \to 0}\frac{f(x_{0}+\Delta x) - f(x_{0})}{\Delta x} $$,由公式可见,对点$x_{0}$的导数反应了函数在点$x_{0}$处的瞬时变化率,或者叫斜率,推广到多维函数中,就有了梯度的概念,梯度是一个向量组合,反映了多维图形中变化速率最快的方向。

补充(tensorflow中常用的优化算法API)

1
2
3
4
5
6
7
8
9
10
11
tf.train.Optimizer
tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer

1、 tf.train.GradientDescentOptimizer 这个优化器主要实现的是:梯度下降算法

1
2
3
4
5
__init__(
learning_rate,
use_locking=False,
name='GradientDescent'
)

2、 tf.train.MomentumOptimizer 实现动量梯度下降算法,可参考 简述动量Momentum梯度下降

1
2
3
4
5
6
7
__init__(
learning_rate,
momentum,
use_locking=False,
name='Momentum',
use_nesterov=False
)

3、tf.train.AdamOptimizer 实现 Adam优化算法(Adam 这个名字来源于 adaptive moment estimation,自适应矩估计。)可参考博客梯度优化算法Adam

1
2
3
4
5
6
7
8
__init__(
learning_rate=0.001,
beta1=0.9,
beta2=0.999,
epsilon=1e-08,
use_locking=False,
name='Adam'
)

机器学习之loss

发表于 2018-07-31 | 更新于 2018-08-03

交叉熵(cross entropy)是深度学习中常用的一个概念,一般用来求目标与预测值之间的差距。以前做一些分类问题的时候,没有过多的注意,直接调用现成的库,用起来也比较方便。最近发现自己对交叉熵的理解有些模糊,不够深入。

信息论

交叉熵是信息论中的一个概念,要想了解交叉熵的本质,需要先从最基本的概念讲起。

1.信息量

如果说概率P是对确定性的度量,那么信息就是对不确定性的度量 举个例子: 事件A:巴西队进入了2018世界杯决赛 事件B:中国对进入了2018世界杯决赛 凭直觉来说,事件B的信息量比事件A的信息量大,究其原因,是因为事件A发生的概率很大,事件B发生的概率很小。所以当越不可能发生的事件发生了,我们获取到的信息量就越大。那么信息量应该和事件发生的概率有关,信息量的大小和事件发生的概率成反比。具体的数学表示如下:

假设$X$是一个离散型随机变量,其取值集合为$\chi$,概率分布函数$ p(x)=P(X=x),x\epsilon\chi$,则定义事件$X=x_{0}$的信息量为: $$I(x_0)=-log(p(x_0))$$

2.熵

考虑另一个问题,对于某个事件,有$n$种可能性,每一种可能性都有一个概率$p(x_{i})$,这样就可以计算出某一种可能性的信息量

序号 事件 概率P 信息量
A 电脑正常 0.7 $-log(p(A))=0.36$
B 电脑死机 0.2 $-log(p(b))=1.61$
C 电脑爆炸 0.1 $-log(p(c))=2.30 $

现在有了信息量的定义,而熵用来表示所有信息量的期望,即: $$H(X)=-\sum_{i=1}^n p(x_i)log(p(x_i))$$ 其中$n$代表所有的n中可能性,所以上面的结果就是: $$\begin{eqnarray} H(X)&=&-[p(A)log(p(A))+p(B)log(p(B))+p(C))log(p(C))]\ &=&0.7\times 0.36+0.2\times 1.61+0.1\times 2.30\ &=&0.804 \end{eqnarray}$$

然而一些比较特殊的问题,比如投掷硬币只有两种可能,买彩票只有两种可能,我们称之为0-1分布问题,对于这类问题,熵的计算方法可以简化为如下计算: $$\begin{eqnarray} H(X)&=&-\sum_{i=1}^n p(x_i)log(p(x_i))\ &=&-p(x)log(p(x))-(1-p(x))log(1-p(x)) \end{eqnarray}$$

3.相对熵(KL散度)

相对熵又称KL散度,如果我们对于同一个随机变量 x 有两个单独的概率分布 P(x) 和 Q(x),我们可以使用 KL 散度(Kullback-Leibler (KL) divergence)来衡量这两个分布的差异。 如果用P来描述目标问题,而不是用Q来描述目标问题,得到的信息增量,<font color='red'>在机器学习中,P往往用来表示样本的真实分布,比如[1,0,0]表示当前样本属于第一类。Q用来表示模型所预测的分布,比如[0.7,0.2,0.1] </font>。 直观的理解就是如果用P来描述样本,那么就非常完美。而用Q来描述样本,虽然可以大致描述,但是不是那么的完美,信息量不足,需要额外的一些“信息增量”才能达到和P一样完美的描述。如果我们的Q通过反复训练,也能完美的描述样本,那么就不再需要额外的“信息增量”,Q等价于P。KL散度的计算公式: $$D_{KL}(p||q)=\sum_{i=1}^np(x_i)log(\frac{p(x_i)}{q(x_i)})$$ n为事件的所有可能性,$D_{KL}$的值越小,表示q分布和p分布越接近

4.交叉熵

对上式KL散度变形可以得到: $$\begin{eqnarray} D_{KL}(p||q) &=& \sum_{i=1}^np(x_i)log(p(x_i))-\sum_{i=1}^np(x_i)log(q(x_i))\ &=& -H(p(x))+[-\sum_{i=1}^np(x_i)log(q(x_i))] \end{eqnarray}$$

等式的前一部分正是p的熵,等式的后一部分,就是交叉熵: $$H(p,q)=-\sum_{i=1}^np(x_i)log(q(x_i))$$

在机器学习中,我们需要评估label和predict之间的差距,使用KL散度刚刚好,即:$D_{KL}(y||\hat{y})$,由于KL散度中的前一部分$-H(y)$不变,故在优化过程中,只需要关注交叉熵就可以了。

机器学习中交叉熵的应用

1.为什么要用交叉熵做loss函数?

在逻辑回归问题中,常常使用MSE(Mean Squared Error)作为loss函数,如: $$loss = \frac{1}{2m}\sum_{i=1}^m(y_i-\hat{y_i})^2$$

这里的m表示m个样本,loss为m个样本loss的均值。MSE在逻辑回归问题中比较好用,那么在分类问题中还是如此么?

2.交叉熵在单分类问题中的使用

这里的单分类是指,每一张图像样本只能有一个类别,比如只能是狗或者只能是猫。交叉熵在单分类问题上的标配方法是: $$loss=-\sum_{i=1}^{n}y_ilog(\hat{y_i})$$

这个式子为计算一张样本的loss,n表示有n中类别,每个样本只属于其中一种,举例说明:

* 猫 狗 兔
Label 0 1 0
Pred 0.3 0.6 0.1

那么loss为: $$\begin{eqnarray} loss&=&-(0\times log(0.3)+1\times log(0.6)+0\times log(0.1)\ &=&-log(0.6) \end{eqnarray}$$

对应一个batch的loss就是: $$loss=-\frac{1}{m}\sum_{j=1}^m\sum_{i=1}^{n}y_{ji}log(\hat{y_{ji}})$$

m为当前batch的样本数

3.交叉熵在多分类问题中的使用

这里的多类别是指,每一张图像样本可以由多个类别,比如同时包含一只猫和一只狗,和单分类问题的标签不同,多分类的标签是n-hot的。比如一张图里面既有猫,又有狗,那么具体看例子:

* 猫 狗 兔
Label 1 1 0
Pred 0.8 0.7 0.1

值得注意的是,这里的Pred不再是通过softmax计算的了,这里采用的是sigmoid激活函数,将每一个节点的输出归一化到0-1之间。所有Pred值的和也不再是1,换句话说,就是每一个Label都是独立分布的,相互之间没有影响。所以交叉熵在这里是单独对每一个节点进行计算,每一个节点只有两种可能值,所以是一个二项分布。对于这种只有两个结果0,1的分布,熵的计算可以进行简化,同样的,交叉熵的计算也可以简化,即: $$loss =-ylog(\hat{y})-(1-y)log(1-\hat{y})$$ 注意,上面式子只是针对一个节点的计算公式,这一点要和单分类的loss区分开来,例子中可以计算为: $$ \begin{eqnarray} loss_猫 &=&-1\times log(0.8)-(1-1)log(1-0.8)=-log(0.8)\ loss_狗 &=&-1\times log(0.7)-(1-1)log(1-0.7)=-log(0.7)\ loss_兔 &=&-0\times log(0.1)-(1-0)log(1-0.1)=-log(0.9) \end{eqnarray} $$ 单张样本的loss即为$loss = loss_猫+loss_狗+loss_兔$ 每一个batch的loss就是: $$loss =\sum_{j=1}^{m}\sum_{i=1}^{n}-y_{ji}log(\hat{y_{ji}})-(1-y_{ji})log(1-\hat{y_{ji}})$$ 式中m为当前batch的样本数量,n为类别数。

补充(sigmoid与softmax)

1. 作用

sigmoid是一个激活函数,输入数据进行完线性变换后,都要进行一个非线性变换,原理就是计算sigmoid函数值,常用的激活函数还有tanh,relu等,sigmoid函数公式为:$f(x) =\frac{1}{1+e^{-x}}$,作用时将数值归一化到0-1之间。

tensorflow中的接口示例如下:

1
2
3
4
5
6
7
import tensorflow as tf
import numpy as np
sess = tf.InteractiveSession()
y = np.array([1.,2.,3.,4.])
sigmoid = tf.nn.sigmoid(y).eval()
print(sigmoid)
# [0.73105858 0.88079708 0.95257413 0.98201379]

softmax是网络结构输出层的一层,计算输出层的值。主要用于神经网络最后一层,作为输出层进行多分类,是Logistic二分类的推广。在Logistic回归中,loss函数是sigmoid交叉熵,所以loss公式为: $$H(X)=-p(x)log(p(x))-(1-p(x))log(1-p(x))$$

其中$p(x)$为$f(x) =\frac{1}{1+e^{-\theta^{\mathrm{T}}x}}$。 在softmax回归中,我们解决的事多分类问题,它的本质就是将一个K维的任意实数向量压缩(映射)成另一个K维的实数向量,其实向量中的每个元素取值都介于(0,1)之间,softmax函数形式如下: $$S_{i}=\frac{e^{V_{i}}}{\sum_{j}e^{V_{j}}}$$

也就是说,是该元素的指数与所有元数指数的比值,这个定义非常直观,还有很多优点。

  • 计算与标注样本的差距

在神经网络的计算当中,我们经常需要计算按照神经网络的正向传播计算的分数S1,和按照正确标注计算的分数S2,之间的差距,计算Loss,才能应用反向传播。Loss定义为交叉熵: $$loss=-\sum_{i=1}^{n}y_{ji}log(\hat{y_{ji}})$$

其中$\hat{y}$就是softmax计算结果,这样的话,它占的比重越大,这个样本的Loss也就越小,这种定义符合我们的要求

  • 计算上非常的方便

我们对分类的Loss进行改进的时候,我们要通过梯度下降,每次优化一个step大小的梯度,我们应用链式法则对loss进行求导,最后的形式非常简单,过程如下,我们重新定义loss,a为拟合值,是关于参数输出$z_{i}$的函数,y为真实标签,则: $$C = -\sum_{i}y_{i}log{a_{i}}$$

我们的目标是,求loss对于$z_{i}$的梯度:$\frac{\partial C}{\partial z_i}$,根据链式法则: $$\frac{\partial C}{\partial z_i} = \frac{\partial C}{\partial a_j} \frac{\partial a_j}{\partial z_i}$$

有个人可能有疑问了,这里为什么是aj而不是ai,这里要看一下softmax的公式了,因为softmax公式的特性,它的分母包含了所有神经元的输出,所以,对于不等于i的其他输出里面,也包含着$z_{i}$,所有的a都要纳入到计算范围中,并且后面的计算可以看到需要分为i=j和i≠j两种情况求导。 下面我们一个一个推: $$\frac{\partial C}{\partial a_j} = \frac{\partial (-\sum_j{y_j \log {a_j}})}{\partial a_j} = -\sum_j{y_j \frac{1}{a_j} }$$

第二个稍微复杂一点:(除法的导数公式${\frac{u}{v}=\frac{u^{'}v-uv^{'}}{v^{2}} }$)

  • 如果 $i=j$:

$$\frac{\partial a_i}{\partial z_i} = \frac{\partial ( \frac{e^{z_i}}{\sum_k{e^{z_k}}})} {\partial z_i}= \frac{\sum_k{e^{z_k}e^{z_i} - (e^{z_i})^2}}{(\sum_k{e^{z_k} })^2 } = ( \frac{e^{z_i}}{\sum_k{e^{z_k}}})(1 - \frac{e^{z_i}}{\sum_k{e^{z_k}}}) = a_i(1-a_i)$$

  • 如果 $i \neq j$:

$$\frac{\partial a_j}{\partial z_i} = \frac{\partial ( \frac{e^{z_j}}{\sum_k{e^{z_k}}})} {\partial z_i} = -e^{z_j}(\frac{1}{\sum_k{e^{z_k}}})^2e^{z_i} = -a_ia_j$$

ok,所有我们把上面的组合连起来: $$\frac{\partial C}{\partial z_i} = (-\sum_j{y_j \frac{1}{a_j} })\frac{\partial a_j}{\partial z_i} = - \frac{y_i}{a_i}a_i(1-a_i) + \sum_{j\neq i} \frac{y_j}{a_j}a_ia_j = -y_i + y_ia_i + \sum_{j\neq i}y_ja_i = -y_i + a_i\sum_jy_j$$ 最后的结果看起来简单了很多,最后针对分类问题,我们给定的$y_{i}$只会是0或者1,因此,对于分类问题,这个梯度等于: $$\frac{\partial C}{\partial z_i} = a_i - y_i$$

举个例子,通过若干层的计算,最后得到的某个训练样本的向量的分数是*[ 1, 5, 3 ],那么概率分别就是[ 0.015, 0.866, 0.117],如果这个样本正确的分类是第二个的话,那么计算出来的偏导就是[0.015,0.866−1,0.117]=[0.015,−0.134,0.117]*,!然后再根据这个进行back propagation就可以了。

tensorflow中关于softmax的使用:

1
2
3
4
5
6
7
8
9
10
11
import tensorflow as tf
import numpy as np
sess = tf.InteractiveSession()
y = np.array([1.,2.,3.,4.])
np.exp(y) / np.sum(np.exp(y))
# array([0.0320586 , 0.08714432, 0.23688282, 0.64391426])
softmax = tf.nn.softmax(y).eval()
print(softmax)
# [0.0320586 0.08714432 0.23688282 0.64391426]
tf.argmax(softmax, axis=0).eval()
# 3

1…3456

李鹏伟

AI

12 日志
1 分类
11 标签
© 2018 李鹏伟
由 Hexo 强力驱动 v3.7.1
|
主题 — NexT.Muse v6.3.0