神经网络中为了避免使用大量循环来遍历数据,采用矩阵的方式来组织数据。引入一些Notation。
1、二分分类
特征向量构造:
输入数据为彩色图片时,我们将计算机内存储的图片的3个通道的像素按层排成一列,如下图所示,得到 n x n x 3 维的特征向量。这便是输入矩阵的行数,有时也简化为n。
Notation:
- 单个样本
,其中
- 样本数m,样本1,2
...
- 训练样本数
,测试样本数
- 训练数据集 输入X,X为
维矩阵(有时样本会作为行向量堆叠)
- 训练数据集输出Y, Y为1 x m维矩阵
- Python中显示矩阵的维度:X.shape=(
,m), Y.shape=(1,m)
2、logistics回归
Sigmoid函数:
在线性回归中, 但在logistics回归中,我们希望输出一个0-1j间的概率值,因此
,其中
。函数形状如图
从图中可看出函数在z很大或者很小的时候函数的斜率会变小,这也就是为什么后面会在隐藏层中用ReLU等函数取代Sigmoid作为激活函数的原因。
logistics回归损失函数:
在logistics中,我们希望给出的m个样本 ,使每个样本预测值
与 真实值
尽可能相等。
误差函数:衡量预测的输出值与真实值的偏差。常见的平方损失函数在logistics回归中会导致出现多个局部最优解,因此在这里定义一种新的误差损失函数。
单个样本的误差损失函数 ,无论何时,我们总希望误差损失函数尽可能的小。为什么这个函数可以最为误差损失函数呢?
y=1时,损失函数第二项为0, 此时我们希望 尽可能很大,即
尽可能大,预测值趋向于真实值;
y=0时,损失函数第一项为0,此时我们希望尽可能大,即
尽可能小,预测值趋向于真实值。
因此这个函数可以作为误差损失函数。
成本函数:在求解模型参数w 和 b时需要衡量模型对整个数据集的误差。
Cost function
误差函数推导过程:
logistics回归可以理解为在给定x条件下y=1或y=0的概率。
如果 y=1, ; 如果y=0,因为y取值为1和0,故
以一个表达式将y=1和y=0的概率统一起来
对P(y|x)取对数得
预测正确的概率越大越好,即概率P(y|x)越大越好,我们在其前面加上负号得
此时变为Loss function越小越好。
对于m个样本来说,假设其服从独立同分布,使预测概率最大,即
对其取对数得Cost Function
3、梯度下降法
在优化参数 w 和 b 时,由于我们选择的损失函数是凸函数。假设 w 为实数,则成本函数与 w 和 b 的关系如下图,图中我们可知下方的红点为 成本函数最小值,此处的 w 和 b 为最佳参数。
梯度下降法:在求解参数(w,b)最优解时,当前位置看往那个方向走cost function可以最快的到达最小值,即每更新一次参数都需根据导数对参数进行更新,直到cost function小到一定程度时。
为了达到最小值,w 更新方式如下(其中 为学习速率,可控制下降速度):
Notation:
在代码中 ,
4、计算图
在神经网络中,我们首先根据每个输入求解最终预测的输出。求得最终预测输出与真实值的cost function后,为了求得每个变量对最终输出的影响,我们使用反向传播来求解输出对每个变量的导数。然后根据求得的导数使用梯度下降法对参数进行更新。思路如下图:
绿色是前向传播的过程,红色是反向传播也就是求解梯度的过程。此外,上图也有助于我们更直观的理解常用的链式求导法则。在代码中表示时:
, 即
, 对于中间变量也是同样的表示方法。
我们通过求偏导实现梯度下降:
其中几个重要的公式如下:
其中上面表示的是单个样本的Loss function。
上图为单个样本从输入得到其Loss function的过程,此处假设输入数据有两个特征值。
从Loss function向前求导过程:
然后根据求导结果更新参数:
这便是单个样本的一次梯度下降 。
m个样本时:
cost function
可以看出,对于m个样本时,需要求的导数其实就是上面对单个样本导数求平均。
在一般使用时,我们常将 w 及 b 初始化为0。若使用for循环来计算并更新梯度,过程如下:
可以发现使用for循环会使算法低效,同时深度学习处理的数据量很大,这会使算法速度很慢。因此使用向量化技术来摆脱for循环。
5、向量化
向量化的计算速度比for循环快很多,其原因是:CPU和GPU中有并行处理功能(SIMD,single instruction more data),使用np.dot这样的内置函数可以充分利用CPU和GPU的并行处理功能,从而大大加快计算速度。
正向传播向量化:
在计算 时,若w和x均为nx维向量,则单个样本向量化和非向量化计算方式如下:
非向量化: 向量化:
z=0 z=np.dot(w.T,x)+b
for i in range(nx)
z=z+w[i]*x[i]
z=z+b
m个样本非向量化
,
将输入的样本按列向量堆叠,由于w为nx维列向量,则
因此在Python中的代码为:
z = np.dot(W.T,X)+b
注意到b为实数,此处用到的Python的广播机制,即在计算时Python自动把b变为(1,m)维矩阵和前面的结果相加。
同理,
这里使用了Python中Sigmoid函数可以对数组每个元素求Sigmoid的特点。由此,之前需要m次for循环的代码变为几行代码,这便是Python向量化带来的优势。接下来我们来一步计算反向传播。
反向传播向量化:
非向量化方式需要使用两个for循环:内部循环为对多个特征值进行计算;外部for循环为对多个样本进行计算。
首先,我们来去掉内部的for循环:
非向量化 向量化 (w为nx维向量)
(X为
x 1维向量)
此时我们将内部for循环去掉了。接下来我们来看如何通过向量化来进行梯度下降的一步迭代。
去掉外部for循环:
由非向量化形式
得其向量化形式
在之前的操作中已经去掉一个for循环,但由于计算m个样本时仍需for循环遍历:
非向量化计算: 向量化计算:
for i=1:m
向量化的一次梯度下降过程如下:
6、Python代码需要注意的问题
Python中产生1 x 5或者5 x 1维数组时使用
a = np.random.randn(1,5)
a = np.random.randn(5,1)
为了避免出现bug,不要使用
a = np.random.randn(5)
a = np.random.randn(1)
这种方式。当不确数组维度时,可以使用assert语句来确保数组维度是你所需要的,语句如下:
assert(a.shape==(5,1))