0%

【CS230-DL】02 神经网络编程基础

前面我们了解了什么是深度学习,万丈高楼平地起,我们先来学习一些基础知识


更新历史

  • 2019.10.12: 完成初稿

二分类 Binary Classification

二分类的定义非常简单,就是要么是 1,要么是 0。我们在训练一个分类器的时候,不会用 for 循环,而是直接把训练数据拼接成 X 和 Y 两个矩阵,这样可以加快计算。

逻辑回归 Logistic Regression

对于二分类的问题,最常用的方法就是逻辑回归,它可以给出 0 到 1 之间的概率值,帮助我们做判断,具体的形式如下:

为了强调其重要性,我再打一次公式本身:

我们要做的就是通过训练数据,得到最佳的 w 和 b,接下来会说明如何得到这俩参数值。

代价函数 Cost Function

要了解代价函数,我们先要看看损失函数 Loss Function,简单粗暴一点理解,就是通过寻找损失函数的极值,我们可以找到最优的参数值 w 和 b。公式为:

这里 y 是真实的值,$\hat{y}$ 是我们预测的值,这样一个损失函数的意思就是当 y 为 0 的时候 $\hat{y}$ 要尽量接近 0;当 y 为 1 的时候 $\hat{y}$ 要尽量接近 1。为什么是这样,大家可以把 y = 0 或 1 带入到上面的公式中,就可以明白。

现在我们有了损失函数,对应的代价函数就是对 m 个样本的损失函数求和再除以 m,也就是求一个平均数,公式为

梯度下降 Gradient Descent

我们来梳理一下,首先我们有逻辑回归的函数:

为了求这个逻辑回归中的参数,我们需要最小化它的代价函数:

那么如果做这个最小化的操作,就需要梯度下降法。梯度下降法不是万能的,需要代价函数是一个凸函数。列举几个关键词:凸优化、拉格朗日乘子法、KKT 条件(这里不展开说明,感兴趣的同学可以自行探索)

假设代价函数只有一个参数 w,那么我们要做的就是不断进行下面的操作:

这里 $\alpha$ 表示学习率,后面的部分是 J(w) 对 w 的求导,符号是 d,如果参数是 w 和 b 两个,那么就是对 w 求偏导数,符号为 $\partial$。

导数 Derivatives

微积分相关内容大家可以搜索“微积分总结”,我就不再重复一次了。核心要点其实是俩:

  1. 导数就是斜率,只是有些是二维空间的,有些是高维空间的,代表某个点变化的趋势,我们可以利用这些趋势当做方向
  2. 大部分常用的函数对应的导数网上都可以查到

计算图 Computation Graph

简单理解,就是把一个函数的计算,分步骤用图的方式表示出来,比如我要计算 J(a,b,c) 的值,可以这样算:

注:蓝线是计算 J 值的过程,红线是计算导数的过程,这俩就是前向传播和后向传播。

计算图求导 Derivatives with a Computation Graph

这一部分就是重点了,这里我们要记得的关键是:链式法则。接下来简单讲解下:

上图是和上一节一样的计算图,根据链式法则,我们来计算下面几个公式:

$\frac{dJ}{dv}$ 比较简单,直接求导可以得到结果为 3,同理我们可以得到 $\frac{dv}{du}=1$ 和 $\frac{dv}{da}=1$。于是我们可以得到

假设我们在编码,我们可以记为 dv = 3

假设我们在编码,我们可以记为 du = 3

假设我们在编码,我们可以记为 da = 3

最后我们来看看 $\frac{dJ}{db}$ 的计算,$\frac{dJ}{du}$ 前面我们记录了为 du = 3,所以关键在于 $\frac{du}{db}$,求导可得 $\frac{du}{db} = c= 2$,所以

假设我们在编码,我们可以记为 db = 6,同理我们可以得到 dc = 3*3 = 9

简单来说,就是一层一层倒着算,就可以得到对应的导数

逻辑回归梯度下降 Logistic Regression Gradient Descent

这一节我们把前面所学的各个要点组合起来:

结论就是在编码中

  • dz = a - y
  • dw1 = x1 * dz
  • dw2 = x2 * dz
  • db = dz

更新的时候

  • w1 = w1 - a * dw1
  • w2 = w2 - a * dw2
  • b = b - a * db

实际训练时,我们可能一批批来进行训练,那么 m 个样本梯度下降(Gradient Descent on m Examples)就很有必要了解

简单来说就是求出这 m 个样本的梯度,然后求平均,最后更新 w 和 b 的值。

向量化 Vectorization

想要代码里不带 for,向量化不能错过!简单来说,向量化就是利用矩阵的能力,快速进行大量计算,这里我们用 Numpy 来做一个测试,具体的代码参考 1_vectorization_camparison.py

运行一下,结果是

1
2
3
4
5
6
7
8
❯ python 1_vectorization_camparison.py
Show an Array
[1 2 3 4]
Create two Arrays with 1000000 dimension
Vectorication Version
Result 249883.4846426414 Time: 1.3508796691894531ms
For Version
Result 249883.48464262878 Time: 382.00998306274414ms

可以看到结果在小数点后 7 位都是一致的,但是向量化的版本比用 for 循环,快了 380 多倍!

逻辑回归向量化 Vectorizing Logistic Regression

利用好矩阵乘法,我们把要计算的内容放到对应矩阵中,就可以极大提高效果:

对应的 numpy 语句为 Z = np.dot(w.T, X) + b,注意,这里对于 b 这个变量,python 会通过广播(broadcasting) 操作扩展为 1*m 的行向量。

逻辑回归梯度向量化 Vectorizing Logistic Regression’s Gradient

经过一波公式代换,我们可以得到下面一组公式:

上面五个公式我们实现了前向和后向传播,即对所有训练样本实现了预测和求导。

然后我们用上面两个公式梯度下降更新参数

广播 Broadcasting

广播的机制可以用下图来总结,具体的还是需要大家自己体验一下:

编写 Python 代码的技巧

  • np.random.randn(5) = 一个 shape 为 (5,) 的结果,不是行向量,也不是列向量,称为一位数组,我们尽量不要这样用
  • np.random.randn(5,1) = 一个 shape 为 (5,1) 的列向量 column vector(一个 5 行 1 列向量
  • np.random.randn(1,5) = 一个 shape 为 (1,5) 的行向量 row vector(一个 5 列 1 行向量
  • 如果不确定一个向量的维度,就先放到 assert 语句中
  • 如果你得到了一个一维数组,使用 reshape 方法转成行向量或列向量