神经网络的计算过程分为两步:
- 前向传播(forward propagation):计算预测值(和代价函数)
- 后向传播(backward propagation):计算导数(链式法则),更新参数
下面以逻辑回归为例,说明该计算过程。
二分类(binary classification)
- 例如,一张图片中是否有猫,二分类的结果就是0(没有)或者1(有)。
- 二分类的目的是训练一个分类器,以图片的特征向量作为输入,输出则是判断有猫或者没有。一般图片都是用RGB三通道表示,所以片的特征向量可以是三个通道的像素值组成的向量。
符号约定
- x x :一个维的向量,表示输入数据,维度是 (nx,1) ( n x , 1 )
- y y :表示输出结果,二分类中的取值是
- y^ y ^ :表示预测值
- (x(i),y(i)) ( x ( i ) , y ( i ) ) :表示第 i i 组数据,默认是训练数据
- :表示训练数据集,维度是 (nx,m) ( n x , m ) , m m 是样本数
- :表示训练数据集对应的输出值集合,维度是 (1,m) ( 1 , m )
逻辑回归(logistic regression)
- 逻辑回归是一个用于二分类的算法。按照上述符号约定,逻辑回归可以表述为:
Given x x ,want = P(y=1|x) P ( y = 1 | x ) = σ σ ( wTx+b w T x + b ) - 上述线性组合计算出得取值范围太大,使用sigmoid函数( σ σ )可以把值约束在[0, 1]之内。sigmoid函数的波形如下:
逻辑回归的代价函数(cost function)
- 损失函数(Loss function),也就是误差函数。逻辑回归中使用以下函数:
L(y,y^)=−ylog(y^)−(1−y)log(1−y^)
L
(
y
,
y
^
)
=
−
y
l
o
g
(
y
^
)
−
(
1
−
y
)
l
o
g
(
1
−
y
^
)
- 如果 y=0 y = 0 , L(y,y^)=−log(1−y^) L ( y , y ^ ) = − l o g ( 1 − y ^ ) 。 y^ y ^ 接近0,损失函数才会接近0。
- 如果 y=1 y = 1 , L(y,y^)=−log(y^) L ( y , y ^ ) = − l o g ( y ^ ) 。 y^ y ^ 接近1,损失函数才会接近0。
- 代价函数就是m个样本的损失函数求和取均值, J(w,b)=1m∑mi=0L(y(i),y^(i))=1m∑mi=0(−y(i)log(y^(i))−(1−y(i))log(1−y^(i))) J ( w , b ) = 1 m ∑ i = 0 m L ( y ( i ) , y ^ ( i ) ) = 1 m ∑ i = 0 m ( − y ( i ) l o g ( y ^ ( i ) ) − ( 1 − y ( i ) ) l o g ( 1 − y ^ ( i ) ) )
- 损失函数只适用于像这样的单个训练样本,而代价函数是参数的总代价,所以在训练逻辑回归模型时候,我们需要找到合适的 w w 和,来让代价函数 J J 的总代价降到最低。
梯度下降法(Gradient descent)
- 梯度下降法的思路很简单:沿着梯度下降的方向更新参数,直至收敛到最小点。
以代价函数为例:
b=b−α∂J(w,b)∂b b = b − α ∂ J ( w , b ) ∂ b其中, α α 是学习速率,控制梯度下降的速率。
- 符号约定: d[var]=d[FinalOutputVar]d[var] d [ v a r ] = d [ F i n a l O u t p u t V a r ] d [ v a r ] , d[var] d [ v a r ] 表示最终的输出FinalOutputVar(通常是代价函数)对变量var的导数
计算图(Computation Graph)
- 计算图可以辅助正向传播和反向传播的计算。
- 以函数
J=3(a+bc)
J
=
3
(
a
+
b
c
)
为例,计算图如下,顺着蓝色箭头可以计算出正向传播的输出。反之,顺着橙色箭头,可以计算反向传播。
- 假设 a=5,b=3,c=2 a = 5 , b = 3 , c = 2
- 正向传播: u=6,v=11,J=33 u = 6 , v = 11 , J = 33
- 反向传播(求导的链式法则): dv=3,du=1∗dv=3,da=1∗dv=3,db=c∗du=6,dc=b∗du=9 d v = 3 , d u = 1 ∗ d v = 3 , d a = 1 ∗ d v = 3 , d b = c ∗ d u = 6 , d c = b ∗ d u = 9
逻辑回归中的梯度下降
- 回顾一下逻辑回归的计算过程,暂时只考虑一个样本的情况:
z=wTx+b z = w T x + b
a=y^=σ(z) a = y ^ = σ ( z )
L(a,y)=−ylog(a)−(1−y)log(1−a) L ( a , y ) = − y l o g ( a ) − ( 1 − y ) l o g ( 1 − a ) - 假设输入只有2个特征, x x 和只有两个元素,逻辑回归的计算图如下:
- 计算反向传播的过程:
da=dL(a,y)da=−ya+1−y1−a d a = d L ( a , y ) d a = − y a + 1 − y 1 − a
dz=dL(a,y)dz=dL(a,y)dadadz=(−ya+1−y1−a)∗(a(1−a))=a−y d z = d L ( a , y ) d z = d L ( a , y ) d a d a d z = ( − y a + 1 − y 1 − a ) ∗ ( a ( 1 − a ) ) = a − y
dw1=∂L(a,y)∂w1=x1∗dz=x1∗(a−y) d w 1 = ∂ L ( a , y ) ∂ w 1 = x 1 ∗ d z = x 1 ∗ ( a − y )
dw2=∂L(a,y)∂w2=x2∗dz=x2∗(a−y) d w 2 = ∂ L ( a , y ) ∂ w 2 = x 2 ∗ d z = x 2 ∗ ( a − y )
db=dz=a−y d b = d z = a − y - 更新参数:
w1=w1−α∗dw1=α∗x1∗(a−y) w 1 = w 1 − α ∗ d w 1 = α ∗ x 1 ∗ ( a − y )
w2=w1−α∗dw2=α∗x2∗(a−y) w 2 = w 1 − α ∗ d w 2 = α ∗ x 2 ∗ ( a − y )
b=w1−α∗db=α∗(a−y) b = w 1 − α ∗ d b = α ∗ ( a − y ) - 扩展到m个样本的逻辑回归:
J(w,b)=1m∑mi=0L(a(i),y(i)) J ( w , b ) = 1 m ∑ i = 0 m L ( a ( i ) , y ( i ) )
a(i)=y(i)^=σ(z(i)) a ( i ) = y ( i ) ^ = σ ( z ( i ) )
z(i)=wTx(i)+b z ( i ) = w T x ( i ) + b
dw1=∂J(w,b)∂w1=1m∑mi=0∂L(a(i),y(i))∂w1=1m∑mi=0x(i)1∗(a(i)−y(i)) d w 1 = ∂ J ( w , b ) ∂ w 1 = 1 m ∑ i = 0 m ∂ L ( a ( i ) , y ( i ) ) ∂ w 1 = 1 m ∑ i = 0 m x 1 ( i ) ∗ ( a ( i ) − y ( i ) )
dw2=∂J(w,b)∂w2=1m∑mi=0∂L(a(i),y(i))∂w2=1m∑mi=0x(i)2∗(a(i)−y(i)) d w 2 = ∂ J ( w , b ) ∂ w 2 = 1 m ∑ i = 0 m ∂ L ( a ( i ) , y ( i ) ) ∂ w 2 = 1 m ∑ i = 0 m x 2 ( i ) ∗ ( a ( i ) − y ( i ) )
db=∂J(w,b)∂b=1m∑mi=0∂L(a(i),y(i))∂b=1m∑mi=0(a(i)−y(i)) d b = ∂ J ( w , b ) ∂ b = 1 m ∑ i = 0 m ∂ L ( a ( i ) , y ( i ) ) ∂ b = 1 m ∑ i = 0 m ( a ( i ) − y ( i ) ) - 上述过程可以用一下算法实现:
J=0;dw1=0,dw2=0;db=0 J = 0 ; d w 1 = 0 , d w 2 = 0 ; d b = 0
For i=1 to m F o r i = 1 t o m
z(i)=wTx(i)+b z ( i ) = w T x ( i ) + b
a(i)=σ(z(i)) a ( i ) = σ ( z ( i ) )
J+=−y(i)log(a(i))−(1−y(i))log(1−a(i)) J + = − y ( i ) l o g ( a ( i ) ) − ( 1 − y ( i ) ) l o g ( 1 − a ( i ) )
dz(i)=a(i)−y(i) d z ( i ) = a ( i ) − y ( i )
dw1+=x(i)1dz(i) d w 1 + = x 1 ( i ) d z ( i )
dw2+=x(i)2dz(i) d w 2 + = x 2 ( i ) d z ( i )
db+=dz(i) d b + = d z ( i )
J=Jm J = J m
dw1=dw1m;dw2=dw2m;db=dbm d w 1 = d w 1 m ; d w 2 = d w 2 m ; d b = d b m
w1=w1−αdw1 w 1 = w 1 − α d w 1
w2=w2−αdw2 w 2 = w 2 − α d w 2
b=b−αdb b = b − α d b - 上述算法只考虑了两个特征,事实上很容易扩展到 nx n x 个特征,在此不做赘述。
- 上述算法在计算的时候会出现多个循环: nx n x 个特征、 m m 个样本、以及若干次的迭代,这会导致算法计算耗时太长,性能堪忧,通常用向量化来减少循环。
向量化
- python中的numpy提供了很高效的矩阵运算操作,所谓的向量化就是把循环操作转换为矩阵运算,提高计算效率。
- 下面的例子比较了循环运算和numpy中矩阵运算的性能。
import numpy as np
import time
a = np.random.rand(1000000)
b = np.random.rand(1000000)
tic = time.time()
c = np.dot(a, b)
toc = time.time()
print(c)
print("Vectorized version: " + str(1000*(toc-tic)) + " ms")
c = 0
tic = time.time()
for i in range(1000000):
c += a[i]*b[i]
toc = time.time()
print(c)
print("for loop: " + str(1000*(toc-tic)) + " ms")
249937.82455119357
Vectorized version: 1.0001659393310547 ms
249937.82455119127
for loop: 479.9354076385498 ms
逻辑回归的向量化
- 对于各样本的逻辑回归,把
m
m
个样本横向扩展为一个矩阵:
Z=[z(1),z(2),...,z(m)]=wTX+b=np.dot(w.T,X)+b Z = [ z ( 1 ) , z ( 2 ) , . . . , z ( m ) ] = w T X + b = n p . d o t ( w . T , X ) + b
A=[a(1),a(2),...,a(m)]=σ(Z) A = [ a ( 1 ) , a ( 2 ) , . . . , a ( m ) ] = σ ( Z ) - 这样,一次逻辑回归的向量化形式可以表示为:
Z=wTX+b=np.dot(w.T,X)+b Z = w T X + b = n p . d o t ( w . T , X ) + b
A=σ(Z) A = σ ( Z )
dZ=A−Y d Z = A − Y
dw=1m∗X∗dZT d w = 1 m ∗ X ∗ d Z T
db=1m∗np.sum(dZ) d b = 1 m ∗ n p . s u m ( d Z )
w=w−α∗dw w = w − α ∗ d w
b=b−α∗db b = b − α ∗ d b