浅层神经网络

1. 神经网络概览

在之前的学习中,关于逻辑回归问题的流程图计算方式可以看作是一个简单的神经网络,给定输入变量xx,能够得到输出$$y,类似的,神经网络的表示可以如下如所示:
浅层神经网络

x1,x2,x3x_1,x_2,x_3这些特征称之为输入层(input layer),中间的一层称之为隐藏层(hidden layer),最后的一层称之为输出层(output layer),在监督学习训练中,只能够看到输入层的数据和输出层的结果,而中间隐藏层的数据是不可见的。

以上神经网络中,令a[0]=Xa^{[0]} = X,表示输入层(第0层)的输入向量,而令a1[1],a2[1],a3[1],a4[1]a^{[1]}_1,a^{[1]}_2,a^{[1]}_3,a^{[1]}_4表示隐藏层的四个单元,并且隐藏层是一个4×1的列向量。用a[2]a^[2]表示输出层的单元,并且a[2]]=y^a^{[2]]}= \hat{y}

2. 神经网络的输出计算

如上图所示的神经网络,其计算过程可以由下图表示:
浅层神经网络

如上所示,神经网络的输入有3个特征,ww是一个4×3的矩阵,
输入xx是一个3×13×1的列向量,而bb是一个4×1的列向量,所以,根据公式z=wTx+bz = w^Tx+bzz也是一个4×1的列向量,如下图所示:
浅层神经网络

3.多个样本的向量化

根据已经规定好的符号,多个样本的神经网络实现方式可以有以下伪代码所示:
浅层神经网络

对于多个样本,输入变量xx可以视之为一个n×m的矩阵,nn代表的是输入变量的特征数,mm代表的是输入的样本数。
假设有三个样本,则其计算方式可以如下表示,,为了简化计算,令b=0b = 0,则有:
z[1](1)=w[1]x(1)z^{[1](1)} = w^{[1]}x^{(1)}
z[1](2)=w[1]x(2)z^{[1](2)} = w^{[1]}x^{(2)}
z[1](3)=w[1]x(3)z^{[1](3)} = w^{[1]}x^{(3)}

根据之前所述,w[1]w^{[1]}是一个矩阵,xx是一个列向量,而w[1]xw^{[1]}*x也会得到一个列向量,根据样本数目,将所得到的列向量组合成一个新的矩阵Z[1]Z^{[1]},整个计算过程,可以由下图所示:

浅层神经网络
对于2层神经网络,向量化得实现公式,如下所示:
浅层神经网络

4. **函数

神经网络中,隐藏层和输出层需要选择**函数,在逻辑回归中,选择的**函数是 sigmoidsigmoid**函数,除了此**函数外,还有一些可供选择的**函数。

除了sigmoidsigmoid函数,还可以选择双曲正切函数,正切函数的表达式如下所示:

KaTeX parse error: \tag works only in display equations

函数图像,如下所示,事实上可以看成是sigmoidsigmoid函数的一个平移变化得到的
浅层神经网络

事实上,在隐藏层中使用tanhtanh函数,输出层使用sigmoidsigmoid函数是一个更好的选择,因为其输出值的范围是(-1,1)之间,其平均值更有可能是0,具有数据中心化的作用。

对于tanhtanh函数和sigmoidsigmoid函数而言,当zz的值较大或者较小的时候,函数的斜率几乎为0,会导致收敛速度过慢,为此,特意引入线性修正单元,称之为Relu单元,正如以下函数图像所示,可以明显的看出该函数不可微,通常其表达式可以写成
KaTeX parse error: \tag works only in display equations

浅层神经网络
除了以上一种线性修正单元外,还有另外一种线性修正单元,其函数表示为KaTeX parse error: \tag works only in display equations
被称之为带泄漏**函数(Leaky ReLu),此种**函数保证了当z=0z = 0时,其导数是一个常数,而不是0,其图像如下所示:
浅层神经网络

对二元分类问题(0,1)的**函数选择,有以下经验:

  • 在输出层选择sigmoidsigmoid作为**函数,而在其他层选择ReLu,即线性**单元。

**函数在神经网络中的应用是十分必要的,如果没有**函数,那么输出只不过是输入的线性组合,而且隐藏层也无法发挥其作用,不如直接去掉整个隐藏层。

5. **函数的导数

神经网络反向传播算法的计算过程,需要计算**函数的导数。

对于上述**函数,其导数计算分别如下所示:

  • sigmoidsigmoid函数,有:
    g(z)=g(z)(1g(z))(4)g^{'}(z) = g(z)*(1-g(z))\tag{4}

  • tanhtanh函数,其导数为
    g(z)=1tanh2(z)(5)g^{'}(z) = 1-tanh^{2}(z)\tag{5}

  • 线性修正单元(ReLu)的**函数,有:
    g(z)={1,ifz00,ifz<0(6)g^{'}(z)=\begin{cases} 1,\quad if \quad z\ge 0\\ 0, \quad if \quad z<0 \end{cases}\tag{6}

  • 带泄漏的线性修正单元(leaky - ReLu)的**函数,有:
    g(z)={1,ifz00.01,ifz<0(7)g^{'}(z)=\begin{cases} 1,\quad \quad if \quad z\ge 0\\ 0.01, \quad if \quad z<0 \end{cases}\tag{7}

6. 神经网络的梯度下降

在上一周的课程中,已经推导过了神经网络的反向传播算法,以一个双层的神经网络为例,其梯度下降的推导过程如下所示:
在前向传播过程中,先计算z[1]z^{[1]}a[1]a^{[1]},再计算z[2]z^{[2]}a[2]a^{[2]},最后得到损失函数。

其反向传播算法,正好与前向传播算法想反,整个计算过程,以双层神经网络为例,如下公式所示:

dZ[2]=A[2]Y(8)dZ^{[2]} = A^{[2]} -Y\tag{8}
dW[2]=1mdZ[2]A[1]T(9)dW^{[2]} = \frac{1}{m}dZ^{[2]}A^{[1]T}\tag{9}
db[2]=1mnp.sum(dZ[2],axis=1,keepdims=True)(10)db^{[2]} = \frac{1}{m}np.sum(dZ^{[2]},axis= 1,keepdims= True)\tag{10}
dZ[1]=W[2]TdZ[2]g[1](Z[1])(11)dZ^{[1]} = W^{[2]T}dZ^{[2]} * g[1]^{'}(Z^{[1]})\tag{11}
dW[1]1mdZ[1]xT(12)dW^{[1]} \frac{1}{m}dZ^{[1]}x^T\tag{12}
db[1]=1mnp.sum(dZ[1],axis=1,keepdims=True)(13)db^{[1]} = \frac{1}{m}np.sum(dZ^{[1]},axis=1,keepdims = True)\tag{13}

7. 随机初始化

神经网络开始计算之前,需要初始化参数,逻辑回归中,将参数初始化为0,而在其他神经网络中,这一做法通常不可取。

就以以下神经网络为例,有两个输入特征,当我们将初始化参数wwbb全部设置为0时,a1[1]=a2[1]a^{[1]}_1 = a^{[1]}_2,并且dz1[1]=dz2[1]dz^{[1]}_1 = dz^{[1]}_2,这意味着你的神经网络在中两个隐藏层是对称的,都在计算同样的函数,造成了冗余,这种情况通常称之为 symmetry breaking problem.
浅层神经网络

对神经网络中的初始化参数ww的取值,通常可以采用随机初始化参数,如上所述的神经网络,在python中,通常可以如下所示(生成高斯分布,并乘以0.01):
w[1]=np.random.randn((2,2))0.01w^{[1]} = np.random.randn((2,2)) * 0.01
b[1]=np.zeros((2,1))b^{[1]} = np.zeros((2,1))
w[2]=np.random.randn((1,2))0.01w^{[2]} = np.random.randn((1,2))*0.01
b[2]=0b^{[2]} = 0

生成的每个权重乘以0.01的原因是,如果**函数是sigmoid(z)sigmoid(z)函数或者tanh(z)tanh(z)函数,避免造成国道的zz值,使得函数值进入饱和区,收敛速度太慢。