玩命加载中...
## 一、全批量梯度下降法
全批量梯度下降(full-batch gradient descent)是梯度下降法在机器学习中的直接应用。
下文我们都将以**[练习赛“问答网站问题、回答数量预测”中的数据集](http://sofasofa.io/competition.php?id=4#c2)**为例。
先载入数据集`train.csv`。
```python
import pandas as pd
train = pd.read_csv('train.csv')
```
这个问题是一个回归问题,自变量为`id`,预测目标为`questions`和`answers`。我们可以分开预测`questions`和`answers`。以`questions`为例,我们建立如下的最小二乘线性回归模型
$$y=\beta_0+\beta_1x,$$
其中$y$表示问题数(`questions`),$x$表示变量`id`,$\beta=({\beta}_0,\beta_1)$为回归系数。
最小二乘法的目标函数$L(\beta)$为
$$L(\beta)=\frac{1}{N}\sum\_{j=1}^N{(y\_j - \hat y\_j)^2} = \sum\_{j=1}^N \frac{1}{N}(\beta\_0+\beta\_1 x\_j - \hat y\_j)^2$$
其中$\hat y_j$为第$j$个样本的真实值,$y_j$是根据回归系数$\beta_0,\beta_1$得到的第$j$个样本的预测值。
为了下面计算的方便,我们可以先算出损失函数$L(\beta)$的梯度。
$$\nabla L = \left(\frac{\partial L}{\partial \beta\_0}, \frac{\partial L}{\partial \beta\_1}\right) =\left(\frac{2}{N}\sum\_{j=1}^N(\beta\_0+\beta\_1x\_j-\hat y\_j), \frac{2}{N}\sum\_{j=1}^Nx\_j(\beta\_0+\beta\_1x\_j-\hat y\_j)\right)$$
下面我们来回顾以下梯度下降法的步骤:
* (1)当$i=0$,自己设置初始点$\beta^0=(\beta\_0^0,\beta\_1^0)$,设置步长(也就是学习率)$\alpha$,设置迭代终止的误差忍耐度$tol$。
* (2)计算目标函数$L(\beta)$在点$(\beta\_0^i,\beta\_1^i)$上的梯度$\nabla L\_{\beta^i}$
* (3)计算$\beta^{i+1}$,公式如下
$$\beta^{i+1} = \beta^{i} - \alpha \nabla L\_{\beta^i}$$
* (4)计算梯度$\nabla L\_{\beta^{i+1}}$,如果梯度的二范数$\|\nabla L\_{\beta^{i+1}}\|_2$小于等于 $tol$,则迭代停止,最优解的取值为$\beta^{i+1}$;如果它大于$tol$,那么$i=i+1$,并返回第(3)步。
**接下来,我们按步骤用python来实现上面的算法。**
(1)设置初始点`beta = [1, 1]`,学习率`alpha = 0.2`。当然你可以选择不同的初始设置。对于`tol`,更切合实际的作法是设置对于损失函数的变动的阈值$tol_L$,这一点会在第(4)步中具体解释。
```python
beta = [1, 1]
alpha = 0.2
tol_L = 0.1
```
(2)计算目标函数$L(\beta)$在点$(\beta\_0^i,\beta\_1^i)$上的梯度$\nabla L\_{\beta^i}$
$$\nabla L = \left(\frac{\partial L}{\partial \beta\_0^i}, \frac{\partial L}{\partial \beta\_1^i}\right)=\left(\frac{2}{N}\sum\_{j=1}^N(\beta\_0^i+\beta\_1^ix\_j-\hat y\_j), \frac{2}{N}\sum\_{j=1}^Nx\_j(\beta\_0^i+\beta\_1^ix\_j-\hat y\_j)\right).$$
为了后面程序调用方便,我们可以把梯度写成函数`compute_grad(beta, x, y)`的形式。
```python
import numpy as np
def compute_grad(beta, x, y):
grad = [0, 0]
grad[0] = 2. * np.mean(beta[0] + beta[1] * x - y)
grad[1] = 2. * np.mean(x * (beta[0] + beta[1] * x - y))
return np.array(grad)
```
(3)计算$\beta^{i+1}$,公式如下
$$\beta^{i+1} = \beta^{i} - \alpha \nabla L_{\beta^i}$$
我们把这一步写成函数`update_beta(beta, alpha, grad)`。
```python
def update_beta(beta, alpha, grad):
new_beta = np.array(beta) - alpha * grad
return new_beta
```
(4)计算$\nabla L\_{\beta^{i+1}}$,如果$\|\nabla L\_{\beta^{i+1}}\|\_2\leq tol$,则迭代停止,最优解的取值为$\beta^{i+1}$;如果$\|\nabla L\_{\beta^{i+1}}\|\_2>tol$,那么$i=i+1$,并返回第(3)步。
在实际问题中(特别是针对下文的随机梯度下降和小批量梯度下降),我们常常用$\left|L(\beta^{i+1})-L(\beta^{i})\right|$的大小来判断程序是否收敛,也就是设定$tol\_L$,若$\left|L(\beta^{i+1})-L(\beta^{i})\right|\leq tol\_L$则认为收敛。
这一步我们可以用`while`循环来实现。