上一周的内容其实已经把神经网络的主要计算思想讲完了,本周主要是用上周的思想计算浅层神经网络的参数。
神经网络的表示
- 神经网络的结构可以分为:输入层、隐藏层、输出层,其中隐藏层可以有很多层,本周介绍的网络只包含1层隐藏层,如下图:
- 神经网络计算层数的时候不算输入层,因此上面的网络是一个2层的神经网络。
- 符号约定
- 上标 [i] [ i ] 的参数表示与第 i i 层相关的参数
- 表示激活的意思,用来表示每一层的参数,例如 a[0] a [ 0 ] 表示输入特征
计算神经网络的输出
- 参见上图,网络中的每一个神经元都可以分为两个计算过程
- z=wTx+b z = w T x + b
- a=σ(z) a = σ ( z ) (正确来说, σ σ 表示激活函数,不一定是sigmoid。如上图,隐藏层使用 tanh t a n h 作为激活函数,输出层使用了 σ σ )
只考虑单个样本,上述神经网络可以表述如下:
a[0]=x=[x1,x2]T a [ 0 ] = x = [ x 1 , x 2 ] T
z[1]1=w[1]T1a[0]+b[1]1 z 1 [ 1 ] = w 1 [ 1 ] T a [ 0 ] + b 1 [ 1 ] , a[1]1=tanh(z[1]1) a 1 [ 1 ] = t a n h ( z 1 [ 1 ] )
z[1]2=w[1]T2a[0]+b[1]2 z 2 [ 1 ] = w 2 [ 1 ] T a [ 0 ] + b 2 [ 1 ] , a[1]2=tanh(z[1]2) a 2 [ 1 ] = t a n h ( z 2 [ 1 ] )
z[1]3=w[1]T3a[0]+b[1]3 z 3 [ 1 ] = w 3 [ 1 ] T a [ 0 ] + b 3 [ 1 ] , a[1]3=tanh(z[1]3) a 3 [ 1 ] = t a n h ( z 3 [ 1 ] )
z[1]4=w[1]T4a[0]+b[1]4 z 4 [ 1 ] = w 4 [ 1 ] T a [ 0 ] + b 4 [ 1 ] , a[1]4=tanh(z[1]4) a 4 [ 1 ] = t a n h ( z 4 [ 1 ] )
z[2]=w[2]Ta[1]+b[2] z [ 2 ] = w [ 2 ] T a [ 1 ] + b [ 2 ] , a[2]=σ(z[2]) a [ 2 ] = σ ( z [ 2 ] )向量化表示如下:
z[1]=⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢..w[1]1....w[1]2....w[1]3....w[1]4..⎤⎦⎥⎥⎥⎥⎥⎥[a[0]1a[0]2]+⎡⎣⎢⎢⎢⎢⎢⎢b[1]1b[1]2b[1]3b[1]4⎤⎦⎥⎥⎥⎥⎥⎥ z [ 1 ] = [ z 1 [ 1 ] z 2 [ 1 ] z 3 [ 1 ] z 4 [ 1 ] ] = [ . . w 1 [ 1 ] . . . . w 2 [ 1 ] . . . . w 3 [ 1 ] . . . . w 4 [ 1 ] . . ] [ a 1 [ 0 ] a 2 [ 0 ] ] + [ b 1 [ 1 ] b 2 [ 1 ] b 3 [ 1 ] b 4 [ 1 ] ] = W[1]a[0]+b[1] W [ 1 ] a [ 0 ] + b [ 1 ] ,
a[1]=tanh(z[1]) a [ 1 ] = t a n h ( z [ 1 ] )z[2]=W[2]a[1]+b[2] z [ 2 ] = W [ 2 ] a [ 1 ] + b [ 2 ] , a[2]=σ(z[2]) a [ 2 ] = σ ( z [ 2 ] )
维度:
- W[1] W [ 1 ] 的维度是 4∗2 4 ∗ 2 ,第1层节点数 ∗ ∗ 输入特征数;的维度是 4∗1 4 ∗ 1 ,第一层节点数 ∗ ∗ 1。
- 的维度是 1∗4 1 ∗ 4 ,第二层节点数 ∗ ∗ 第一层节点数;的维度是 1∗1 1 ∗ 1 ,第二层节点数 ∗ ∗ 1。
多个样本的向量化
扩展到m个样本:
z[1](i)=W[1]a[0](i)+b[1] z [ 1 ] ( i ) = W [ 1 ] a [ 0 ] ( i ) + b [ 1 ]
a[1](i)=tanh(z[1](i)) a [ 1 ] ( i ) = t a n h ( z [ 1 ] ( i ) )
z[2](i)=W[2]a[1](i)+b[2] z [ 2 ] ( i ) = W [ 2 ] a [ 1 ] ( i ) + b [ 2 ]
a[2](i)=σ(z[2](i)) a [ 2 ] ( i ) = σ ( z [ 2 ] ( i ) )向量化后的结果:
A[0]=X=[a[0](0) a[0](1) ... a[0](m)] A [ 0 ] = X = [ a [ 0 ] ( 0 ) a [ 0 ] ( 1 ) . . . a [ 0 ] ( m ) ]
Z[1]=[z[1](0) z[1](1) ... z[1](m)]=W[1]A[0]+b[1] Z [ 1 ] = [ z [ 1 ] ( 0 ) z [ 1 ] ( 1 ) . . . z [ 1 ] ( m ) ] = W [ 1 ] A [ 0 ] + b [ 1 ]
A[1]=tanh(Z[1]) A [ 1 ] = t a n h ( Z [ 1 ] )
Z[2]=W[2]A[1]+b[2] Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ]
A[2]=σ(Z[2]) A [ 2 ] = σ ( Z [ 2 ] )多个样本向量化的核心是:把特征按照列向量堆叠起来。
激活函数
常用的激活函数:
- sigmoid: σ(x)=11+e−x σ ( x ) = 1 1 + e − x
- tanh(x)=ex−e−xex+e−x t a n h ( x ) = e x − e − x e x + e − x
- ReLU: y=max(0,x) y = m a x ( 0 , x )
- leaky ReLU: max(0.01x,x) m a x ( 0.01 x , x ) ,其中的0.01是一个可调的参数,下面代码中为了特征明显,该系数选取了0.1
优缺点:
- ReLU、leaky ReLU的实现简单(if…else语句),sigmoid和tanh都需要做浮点运算。因此前者的学习速度更快;
- sigmoid和tanh在正负饱和区的梯度趋近0,造成梯度弥散现象;ReLU、leaky ReLU的导数是常数,不会有梯度弥散现象。
- Relu 进入负半区的时候,梯度为 0,神经元此时不会训练,会产生所谓的稀疏性,而 Leaky ReLu 不会有这问题
总结:
- sigmoid:一般只有在二分类问题的输出层使用
- tanh:几乎适用于所有场合
- ReLU和leaky ReLU:最常用的默认函数。
为什么需要非线性激活函数
- 如果没有非线性激活函数,整个神经网络的输出就是输入的线性组合。
- 隐藏层绝大部分场景使用非线性激活函数(特殊场景通常与压缩有关),输出层可能使用线性激活函数。
常用激活函数的导数:
- dσ(x)dx=σ(x)(1−σ(x)) d σ ( x ) d x = σ ( x ) ( 1 − σ ( x ) )
- dtanh(x)dx=1−(tanh(x))2 d t a n h ( x ) d x = 1 − ( t a n h ( x ) ) 2
- g(x)=max(0,x) g ( x ) = m a x ( 0 , x ) , dg(x)dx=⎧⎩⎨⎪⎪10undefined if x>0if x<0if x=0 d g ( x ) d x = { 1 i f x > 0 0 i f x < 0 u n d e f i n e d i f x = 0 ,通常 x=0 x = 0 时,导数设置为0或者1。
- g(x)=max(0.01x,x) g ( x ) = m a x ( 0.01 x , x ) , dg(x)dx=⎧⎩⎨⎪⎪10.01undefined if x>0if x<0if x=0 d g ( x ) d x = { 1 i f x > 0 0.01 i f x < 0 u n d e f i n e d i f x = 0 ,通常 x=0 x = 0 时,导数设置为0.01或者1。
import numpy as np import matplotlib.pyplot as plt def relu(x): return np.maximum(0, x) def leaky_relu(x): return np.maximum(0.1*x, x) def sigmoid(x): return 1.0 / (1.0 + np.exp(-x)) def tanh(x): return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x)) x = np.linspace(-10.0, 10.0, 2001, endpoint=True) y_relu = relu(x) y_leaky_relu = leaky_relu(x) y_sigmoid = sigmoid(x) y_tanh = tanh(x) fig = plt.figure() ax1 = fig.add_subplot(221) ax1.plot(x, y_relu) ax2 = fig.add_subplot(222) ax2.plot(x, y_leaky_relu) ax3 = fig.add_subplot(223) ax3.plot(x, y_sigmoid) ax4 = fig.add_subplot(224) ax4.plot(x, y_tanh)
神经网络的梯度下降
代价函数: J(W[1],b[1],W[2],b[2])=1m∑mi=0L(y(i),a[2](i)) J ( W [ 1 ] , b [ 1 ] , W [ 2 ] , b [ 2 ] ) = 1 m ∑ i = 0 m L ( y ( i ) , a [ 2 ] ( i ) )
反向传播:
dZ[2]=A[2]−Y d Z [ 2 ] = A [ 2 ] − Y
dW[2]=1mdZ[2]A[1]T d W [ 2 ] = 1 m d Z [ 2 ] A [ 1 ] T
db[2]=1mnp.sum(dZ[2],axis=1,keepdims=true) d b [ 2 ] = 1 m n p . s u m ( d Z [ 2 ] , a x i s = 1 , k e e p d i m s = t r u e )
dZ[1]=W[2]TdZ[2]∗dtanh(z)dz(Z[1]) d Z [ 1 ] = W [ 2 ] T d Z [ 2 ] ∗ d t a n h ( z ) d z ( Z [ 1 ] )
dW[1]=1mdZ[1]A[0]T d W [ 1 ] = 1 m d Z [ 1 ] A [ 0 ] T
db[1]=1mnp.sum(dZ[1],axis=1,keepdims=true) d b [ 1 ] = 1 m n p . s u m ( d Z [ 1 ] , a x i s = 1 , k e e p d i m s = t r u e )