2.神经网络基础

二分类问题(Binary Classification)

逻辑回归要解决的问题,什么是二分类问题?即目标问题的答案空间非此即彼,是离散的,这有点像我们平常做的判断题,非对即错。就像吴恩达老师提出的问题:训练一个分类器,对图片进行判断,是猫就输出1,否则输出0

逻辑回归(Logistic Regression)

给定$x$,求$\hat{y}=P(y=1|x)$(已知$x$,$y=1$的概率$P$,对实际值$y$的预测)

这是一个很好的线性回归模型,但是为了使$\hat{y}$落在[0,1]中,引入了sigmoid函数:

此时逻辑回归模型为:

sigmoid函数

sigmoid函数有很多优点:

  • 值域为(0,1)
  • 平滑、易于求导

逻辑回归的代价函数(Logistic Regression Cost Function)

为了训练模型习得参数$\omega$和$b$

给定m个训练样本$\left \{ (x^{(1)},y^{(1)}),…,(x^{(m)},y^{(m)}) \right \}$,使得$\hat{y} \approx y$,从而在训练集中找到参数$w$和$b$

损失函数(Loss function)

为了衡量算法的精确度,$L(\hat{y},y)$

怎么衡量?

预测值与实际值的距离(差值)越小,说明算法越精确。一般用$\hat{y}与y$的平方差或平方差的一半表示,但在逻辑回归中不这么做。为啥不这么做呢,是因为如果用平方差或平方差的一半表示距离,则梯度下降法一般不能找到全局最优解,所以在逻辑回归中提出另一个损失函数:

为啥使用这个函数呢?

因为$y=1$时,$L(\hat{y},y)=-log(\hat{y})$,为了使$L$尽可能小,则$\hat{y}$会无限大,又因为$\hat{y}\in [0,1]$,所以$\hat{y}\rightarrow 1$

同理$y=0$时,$L(\hat{y},y)=-log(1-\hat{y})$,为了使$L$尽可能小,则$\hat{y}$会无限小,又因为$\hat{y}\in [0,1]$,所以$\hat{y}\rightarrow 0$

代价函数(Cost Function)

损失函数针对单一训练样本,代价函数(成本函数)针对所有样本

在训练逻辑回归模型时候,我们需要找到合适的$\omega$和$b$,来让代价函数$J$的总代价降到最低。

梯度下降(Gradient Descent)

梯度下降(Gradient Descent)小结
梯度下降算法详解

通过梯度下降可以找到三维曲面上任一点到最小值的路径,梯度下降适用于凸函数,如果函数非凸,则会找到通向局部最优解的多条路径。

在二元函数中,梯度没有方向一说,此时梯度等价于导数。

有了代价函数$J(w, b)$,利用梯度下降就能在训练集中学习训练参数$w$和$b$:

在这里$\alpha$表示学习率,其实就是用来控制梯度下降时的步长。$\alpha$是一个超参数,通过人工标定,而不是计算得出,$\alpha$既不能太大也不能太小,太大可能会超过最优解;太小下降得会很慢、效率低,所以找到合适的学习率很关键。

逻辑回归中的梯度下降(Logistic Regression Gradient Descent)

链式法则

假设样本只有两个特征$x_{1}$和$x_{2}$,为了计算$z$,我们需要输入参数$w_{1}$、$w_{1}$和$b$,除此之外还有特征值和。因此的计算公式为:

只考虑单个样本的情况,单个样本的代价函数定义如下:

dQKch6.png

完成导数计算后,使用变量$dw_{1}$、$dw_{1}$和$db$就可以完成对单个样本参数$w_{1}$、$w_{1}$和$b$的更新:

m 个样本的梯度下降(Gradient Descent on m Examples)

利用上节推导的公式应用于m个样本,重新回忆代价函数:

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
J = 0; dw1 = 0; dw2 = 0; b = 0;
for i = 1 to m:
z(i) = wx(i) + b;
a(i) = sigmoid(z(i));
J += -[y(i) * log(a(i)) + (1 - y(i)) * log(1 - a(i));
dz(i) = a(i) - y(i);
dw1 += x1(i) * dz(i);
dw2 += x2(i) * dz(i);
db += dz(i);
J /= m; dw1 /= m; dw2 /= m; db /= m;
w = w - alpha * dw;
b = b - alpha * db;

for循环在深度学习领域中不建议使用,因为数据集很大,循环遍历效率很低,下一节提出了向量化的概念,可以提高程序的运行效率。

向量化(Vectorization)

大规模的深度学习使用了GPU或者图像处理单元实现,GPU更加擅长SIMD计算

避免使用for循环,尽量使用Numpy内建函数,提高程序运行效率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np
from time import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

tic = time()
c = np.dot(a,b)
toc = time()

print(c)
print("Vectorization : " + str(1000*(toc - tic)) + "ms")

tic = time()
c = 0
for i in range(1000000):
c += a[i]*b[i]
toc = time()

print(c)
print("For Loop : " + str(1000*(toc - tic)) + "ms")

运行结果:

1
2
3
4
250070.50127872356
Vectorization : 5.739450454711914ms
250070.50127871914
For Loop : 735.069751739502ms

向量化的效率是for循环的150倍!

使用向量化可以将上一节的伪代码进行优化:

dlcqsO.png

向量化逻辑回归(Vectorizing Logistic Regression)

大写字母表示向量,小写字母表示元素。

转换为python代码:

1
2
Z = np.dot(w.T, X) + b //python广播,可以将一个实数自动转换为一维矩阵,累加到之前的矩阵中
A = sigmoid(Z)

这是逻辑回归向前传播的过程。

向量化logistic回归的梯度输出(Vectorizing Logistic Regression’s Gradient)





综上所述,优化后的逻辑回归为:

(选修)logistic 损失函数的解释(Explanation of logistic regression cost function)

查看第二节逻辑回归(Logistic Regression)重新回忆一下逻辑回归研究的问题:给定$x$,求$\hat{y}=P(y|x)$,分析以下两个条件概率:

上述的两个条件概率公式可以合并成如下公式:

对上式求对数:

为什么要求对数呢?答:降低复杂度,方便计算。

而上式就是损失函数的负数:$-L(\hat{y}, y)$。为什么有个负号呢?原因是当你训练学习算法时需要算法输出值的概率是最大的(以最大的概率预测这个值),然而在逻辑回归中我们需要最小化损失函数,因此最小化损失函数与最大化条件概率的对数$\log (p(y \mid x))$关联起来了,因此这就是单个训练样本的损失函数表达式。


对于整个训练集中标签的概率,假设所有的训练样本服从同一分布且相互独立,也即独立同分布的,所有这些样本的联合概率就是每个样本概率的乘积:

如果你想做最大似然估计,需要寻找一组参数,使得给定样本的观测值概率最大,但令这个概率最大化等价于令其对数最大化,在等式两边取对数:

最大似然估计:已知结果,反推参数

上式就是逻辑回归的代价函数:

对上式进行适当缩放,加入常数因子:

  1. (1)式中,由于训练模型时,目标是让成本函数最小化,所以不直接使用最大似然概率,要去掉负号
  2. (2)式中,为了方便,可以对代价函数进行适当缩放,在前面加一个额外常数因子$\frac{1}{m}$

错题总结

第 15 题

考虑以下两个随机数组ab:(D)

1
2
3
a = np.random.randn(4, 3) # a.shape = (4, 3)
b = np.random.randn(3, 2) # b.shape = (3, 2)
c = a * b

c的维度是什么?

A.c.shape = (4, 3)

B.c.shape = (3, 3)

C.c.shape = (4, 2)

D.计算不成立因为这两个矩阵维度不匹配

第 18 题

请考虑以下代码段:(B)

1
2
3
4
5
# a.shape = (3,4)
# b.shape = (4,1)
for i in range(3):
for j in range(4):
c[i][j] = a[i][j] + b[j]

如何将之矢量化?

A.c = a + d

B.c = a +b.T

C.c = a.T + b.T

D.c = a.T + b

第 19 题

请考虑以下代码段:(A)

1
2
3
a = np.random.randn(3, 3)
b = np.random.randn(3, 1)
c = a * b

c的维度是什么?

A.这会触发广播机制,b会被复制3次变成(33),而\操作是元素乘法,所以c.shape = (3, 3)

B.这会触发广播机制,b会被复制3次变成(33),而\操作是矩阵乘法,所以c.shape = (3, 3)

C.这个操作将一个3x3矩阵乘以一个3x1的向量,所以c.shape = (3, 1)

D.这个操作会报错,因为你不能用*对这两个矩阵进行操作,你应该用np.dot(a, b)