Logistic 回归、梯度下降及向量化

深度学习学习笔记 - Week 1 & 2

ZingLix July 18, 2018

神经网络概述

神经网络的目标与一个普通的函数相同,即给定输入,期望得到一个处理后的结果,只不过有些时候输入输出间的关系十分复杂,而神经网络可以通过学习的方式得到输入输出之间的关系。

上图即为一个神经网络,分为输入层、隐藏层和输出层,其中隐藏层就是神经网络的关键所在。其中每个圆圈代表一个“神经元”,而箭头则代表这些数据影响着所指的神经元,并一层层最终影响结果。

Logistic 回归

概述

在许多场景下,我们通常只要判断一个东西是或不是,比如判断一张图中是否有人,这种只有两种结果(0 与 1)的称之为 二分分类

Logistic 回归是一种用于针对二分分类问题的学习方法,在给定输入 x 的情况下,输出为真的概率 y^=P(y=1|x) ,其中 xnx 维输入向量,nx 为特征数量。

为了达到这一目标,引入另一个nx维向量w称为 权重 ,向量中每一个值都是输入的 x 中对应值的权重。另外还引入一个实数 b 称为 阈值 。Logistic 回归计算的就是 wTx+b ,然而这一函数的问题在于其可以计算出任意值,而 y 作为一个概率必定落在 [0,1] 中,所以还另引入一个函数 σ(z)=11+ez

从上图可以看出对于任意值都可以将其映射到 [0,1] 中,且 σ(0)=0.5

综上,Logistic 回归通过训练 wb,然后通过下面这个公式得到结果。

y^=σ(wTx+b)

成本函数

为了定量表示当前训练出的数据与测试,引入 损失函数 这一概念。

对于给定的测试集 (x(1),y(1)),,(x(m),y(m)),其中 x(i) 代表第 i 个数据。显然我们希望计算出的 y^(i) 与测试数据 y(i) 相同,或者说差距尽可能地小。对于 Logistic 回归,损失函数可以为

L(y^(i),y(i))=(y(i)log(y^(i)))+(1y(i))log(1y^(i))

由于 y 取值只有 0 与 1 ,所以只有如下两种情况

  • y=0 时,L(y^(i),y(i))=log(1y^(i)),此时 y^ 越接近 0L 越小。
  • y=1 时,L(y^(i),y(i))=log(y^(i)),此时 y^ 越接近 1L 越小。

损失函数并不唯一,但在这里用该函数作为损失函数可以使得其只有一个最小值,所以只有一个全局最优解,而非多个局部最优解,使得寻找最优解更为方便。

损失函数作用于一组数据,为了能够描述整个数据集引入 成本函数

J(w,b)=1mi=1mL(y^(i),y(i))

即所有数据损失函数结果的平均值。我们的目标就是找到使得成本函数最小的那一组 (w,b)

梯度下降法

下图为损失函数与权重之间的关系,我们目标是找到成本函数最低时候那个权重。

根据微积分的知识,沿着切线方向下降最快,因此有

w=wαdJ(w)dw

其中 α 称之为 学习速率。通过这一式子,无论当前点在目标左侧还是右侧,导数正负都能控制其往目标点移动。而且当离目标点较远时倒数较大,所以每次移动较多,越接近时导数越小,移动的也较小。

这是二维的一个例子,对于更多维的将其中导数换为相应变量的偏导数即可,如 Logistic 回归中有

w=wαJ(w)w,b=bαJ(b)b

计算图

前向传播

考虑 J=3(a+bc) 这一式子,可以根据计算顺序得到下面这幅图

给定输入后,从左往右便可以计算出 J,这样的计算方式称之为 正向传播

反向传播

反向传播同样用的是这幅图,只是方向从右往左,希望找到的是 J 变化的时候其他的变量是如何影响它的。

简单的说就是计算导数,想要找到 v 如何影响 J,只需要计算 dJdv ,这样的一步称为反向步。

当想要找到 a 如何影响 J,可以先计算 a 如何影响 vv 如何影响 J,即 dJda=dJdvdvda,其实就是微积分中的链式法则。整个学习过程中,首先通过正向传播得到结果,与期望值不符则再用反向传播利用梯度下降反过来影响输入,不断反复达到学习的效果。

Logistic 回归中的应用

总结下 Logisitc 回归中的过程,有如下几个式子

  • z=wTx+b
  • y^=a=σ(z)
  • L(a,y)=(ylog(a)+(1y)log(1a))

从而可以得到如下的计算图。

在给定输入的时候能计算出 J,而我们的目标是找到 (w1,w2,b) 如何取值可以使得 J 最小。

为了找到 w1 如何影响 J ,需要运用反向传播。通过求导可以计算出

dLda=ya+1y1adLdz=dLdadadz=ay

又有 Lw1=x1dLdz ,所以梯度下降每次迭代 w1=w1αdw1w2,b 同理。

综上,可以得到 Logistic 回归的代码。

1
2
3
4
5
6
7
8
9
10
11
12
J = dw1 = dw2 = db = 0
for i = 1 to m
    // 正向传播
    z[i] = w^T * x[i] + b
    a[i] = sigma(z[i])
    J += L(a,y)
    // 反向传播
    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

向量化

向量化简而言之就是将我们之前所用到的各种 w1,x1 之类的放到一个向量中,这样子计算的时候可以用 numpy 中各种并行算法加速运行,例如

X=[x(1)x(m)],Y=[y(1),,y(m)]dz=[dz(1),dz(2),,dz(m)]w=[w1wn]

其中对于 X 中每个向量以列的方式存储。所以 Logistic 回归可以进一步优化为

1
2
3
4
5
6
7
8
z = np.dots(w.t, x) + b
a = sigma(z)
dz = a - y
dw = np.dots(x, dz.t) / m
db = np.sum(dz) / m

w = w - alpha * dw
b = b - alpha * db

这样就可以完成一次高效的学习,之后只需要不断重复这一过程就可以完成 Logistic 回归。