前面两周讲的是一些logistic和向量化的内容,以及numpy的基本使用,在他之前的机器学习课程中已经讲过了,这里就不再赘述。Week3主要讲了如何搭建两层的神经网络。
神经网络的表示
这周的内容就围绕着这一张图来讲。
$$a_{j}^{[i]}$$
这就是每一层神经元的表达方式,上标中括号[],表示是第几层的神经元;下标表示这个是某一层的第几个神经元。
Input Layer:输入层,也用$a_{j}^{[0]}$,表示第0层
Hidden Layer:表示除了最后一层输出层以外的内部隐藏层
Output Layer:输出层,表示最后一层
而通常神经网络的层数一般不包括输入层。
$w^{[i]}$:每一层的参数$w$的维度是(该层神经元个数,前面一层神经元个数)
$b^{[i]}$:为(每一层的神经元个数,1)
计算单个数据的神经网络
由此得到,计算单个数据的神经网络只需要4步:
$$z^{[1]} = W^{[1]}a^{[0]} + b^{[1]}$$
$$a^{[1]} = \sigma(z^{[1]})$$
$$z^{[2]} = W^{[2]}a^{[1]} + b^{[2]}$$
$$a^{[2]} = \sigma(z^{[2]})$$
多数据的向量化表示
我们知道,多个数据的表示就是$x^{(i)}$,使用小括号的上标。神经元也是一样。
如$a^{[1] (i)}$表示第1层神经元的第i个样本。
那么如果有m个样本,一直做for循环来计算出这些神经元的值,实在是太慢了,所以跟logistic一样,可以直接用向量化来表示,这个时候用大写字母来表示。
$$Z^{[1]} = W^{[1]}A^{[0]} + b^{[1]}$$
$$A^{[1]} = \sigma(Z^{[1]})$$
$$Z^{[2]} = W^{[2]}A^{[1]} + b^{[2]}$$
$$A^{[2]} = \sigma(Z^{[2]})$$
这个时候,例如$A^{[1]}$是一个$(n,m)$的矩阵,m是样本数,每一列表示一个样本,n是该层的神经元个数。
从水平上看,矩阵 A代表了各个训练样本。竖直上看,A的不同索引对应不用的隐藏单元。
对矩阵Z和X也是类似,水平方向对应不同的样本,竖直方向上对应不同的输入特征,也就是神经网络输入层的各个节点。
激活函数
在此前都是用sigmoid作为激活函数的。但是激活函数不只有这一种,常用的有4种,分别是:sigmoid, tanh, ReLu, Leaky ReLu。
- sigmoid: $a = \frac{1}{1 + e^{-z}}$
- 导数:$a^{\prime} = a(1-a)$
- tanh: $a = \frac{e^z - e^{-z}}{e^z + e^{-z}}$
- 导数:$a^{\prime} = 1 - a^2$
- ReLu(修正线性单元): $a = max(0, z)$
- Leaky ReLu: $a = max(0.01z, z)$
tips:
- tanh函数在值域上处于-1和+1之间,所以均值更接近0,使用tanh比sigmoid更能够中心化数据,使得平均值接近0,而不是0.5。
- tanh在大多数场合都是优于sigmoid的。
- 但是sigmoid和tanh有共同的缺点就是z在特别大或者特别小的时候,梯度很小,收敛速度很慢。
- 而ReLu弥补了两者的不足,在$z > 0$时,梯度始终为1,提高了速度。
- Leaky ReLu保证了$z < 0$时,梯度不为0,但是实际上效果差不多。
结论:
- sigmoid:除了输出层是一个二分类问题的时候使用,不然基本不用
- tanh:几乎适用于任何场合
- ReLu:默认使用这个,如果不确定你要用哪个激活函数,那就选ReLu或者Leaky ReLu
为什么要使用非线性的激活函数
如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情况下你每一层输出都是上层输入的线性函数,很容易验证,无论你神经网络有多少层,输出都是输入的线性组合,与只有一个隐藏层效果相当,这种情况就是多层感知机(MLP)了。
正因为上面的原因,我们决定引入非线性函数作为激励函数,这样深层神经网络就有意义了(不再是输入的线性组合,可以逼近任意函数)。
梯度下降法公式
这里给出了浅层神经网络的梯度下降法公式。其中$g^{[1]’}(Z^{[1]})$表示你的激活函数的导数。
参数随机初始化
在神经网络中,如果将参数全部初始化为0 会导致一个问题,例如对于上面的神经网络的例子,如果将参数全部初始化为0,在每轮参数更新的时候,与输入单元相关的两个隐藏单元的结果将是相同的。
所以初始化时,W要随机初始化,b不存在对称性问题,所以可以设置为0
1 | W = np.random.rand((2,2))* 0.01 |
将W乘以0.01是为了让W初始化足够小,因为如果很大的话,Z就很大,用sigmoid或者tanh时,所得到的梯度就会很小,训练过程会变慢。
ReLU和Leaky ReLU作为激活函数时,不存在这种问题,因为在大于0的时候,梯度均为1。
好好做作业,才能有更深的体会!