机器学习 - 梯度与梯度下降

梯度的本意是一个向量(矢量),表示某一函数(该函数一般是二元及以上的)在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。当函数是一元函数时,梯度就是导数。这里我们用一个最简单的例子来讲解梯度下降法,然后推广理解更为复杂的函数。

本文分为 理论介绍Python 代码示例 两部分

👉 点此直接跳转到代码示例

理论介绍

线性回归模型

单变量线性回归

$$ h_ {\theta } (x)= \theta _ {0} + \theta _ {1} x $$
1
h = theta_0 + theta_1 * x  

代价函数

为了评估出线性函数拟合的怎么样,需要使用到 Cost Function(代价函数),代价函数越接近 0,说明越好,等于 0 的时候即为完全拟合。

$$ J( \theta _ {0} , \theta _ {1} )= \frac {1}{2m} \sum _ {i=1}^ {m} (h_ {\theta }(x^ {(i)})-y^ {(i)})^2 $$
1
cost = 0.5 * np.sum(((theta_0 + theta_1 * x) - y) ** 2)  

梯度下降

梯度的本意是一个向量(矢量),表示某一函数(该函数一般是二元及以上的)在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。

当函数是一元函数时,梯度就是导数。这里我们用一个最简单的例子来讲解梯度下降法,然后推广理解更为复杂的函数。

还是用上面的例子,有 n 组数据,自变量 $x(x1,x2,…,xn)$ ,因变量 $y(y1,y2,…,yn)$ ,但这次我们假设它们之间的关系是:$f(x)=ax$ 。记 $J(a)$ 为 $f(x)$ 和 $y$ 之间的差异,即:

$$ J(a)= \sum _ {i=1}^ {n} (f( x^ {(i)} - y^ {(i))^ {2}} = \sum _ {i=1}^ {n} (ax^ {(i)}-y^ {(i)})^ {2} $$

在梯度下降法中,需要我们先给参数 a 赋一个预设值,然后再一点一点的修改 a,直到 J(a) 取最小值时,确定 a 的值。下面直接给出梯度下降法的公式(其中 $\alpha$ 为正数):

$$ repeat\{ a:=a- \alpha \frac {\partial J(a)}{\partial a} \} $$

img1

如果给 $a$ 去的预设值是 $a1$ ,那么 $a$ 对 $J(a)$ 的导数为负数,意味着 $a$ 会向右移。然后重复这个步骤,直到 $J(a)$ 到达最小值。

同理给 $a$ 取得预设值是 $a2$ ,那么 $a$ 对 $J(a)$ 的导数为正数,意味着 $a$ 会向左移,然后重复这个步骤,直到 $J(a)$ 到达最小值。

因此我们可以得到,不管 $a$ 的预设值取多少, $J(a)$ 经过梯度下降法的多次重复后,最后总能到达最小值。

对于上述公式的理解可以用上山下山的例子来说明,给 a 的预设值就好比是你正处在一个山的山坡上,如果你想走到山谷,那么你就会判断你是向左还是向右走,走完第一次之后又会重新判断。在公式中 $\alpha$ 叫做学习率,也就是你走的步伐的大小, $\alpha$ 越大,步伐就越大,当然, $\alpha$ 也不是越大越好,就好比如果你就快到山谷了,但是由于步伐太大而刚好跨过山谷,下一步往回走又会跨过山谷,这样就永远到不了山谷了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# alpha 为学习率  
alpha = 0.005  
# m 为样本数量  
m, n = y.shape  
# 计算梯度下降的方向  
d_theta_0 = np.sum((theta_0 + theta_1 * x) - y) / m  
d_theta_1 = np.sum(((theta_0 + theta_1 * x) - y) * x) / m  
# 更新 theta  
theta_0 = theta_0 - alpha * d_theta_0  
theta_1 = theta_1 - alpha * d_theta_1  

多变量线性回归

多变量线性回归于单变量线性回归其实差不了多少,只是需要计算的参数从两个变成多个了而已。

假设有 n 组数据,其中目标值(因变量)与特征值(自变量)之间的关系为:

$$ f(x(i))= \theta _ {0} + \theta _ {1} x_ {1}^ {(i)} + \cdots + \theta _ {n} x_ {n}^ {(i)} $$

其中 $i$ 表示第 $i$ 组数据,损失函数为:

$$ J( \theta )= \sum _ {i=1}^ {n} (f( x^ {(i)} - y^ {(i)})^ {2} $$

梯度下降法公式为:

$$ repeat \{\theta _ {j} := \theta _ {j} - \alpha \frac {\partial J(\theta )}{\partial \theta _ {j}}\} $$

Python 代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from sklearn.datasets import make_regression
import numpy as np
from sklearn.model_selection import train_test_split
np.random.seed(10)


def cost(theta, x, y):
    cost = np.sum((theta.dot(x.T) - y) ** 2) / 2
    return cost


def lr(x, y, alpha=0.0005, iterations=50000):
    """
    :param x: 特征值
    :param y: 目标值
    :param alpha: 学习率
    :param iterations: 迭代次数
    :return: 最终得到的 theta 值
    """
    # 初始化 theta 为零向量
    theta = np.zeros(x.shape[1])
    
    # 学习率与迭代次数请根据实际情况进行调整
    # 通过循环不断更新 theta
    for _ in range(iterations):
        # 计算预测值与实际值之间的差值
        gradient = x.dot(theta) - y
        # 计算 theta 的梯度
        grad_theta = gradient.dot(x) / len(y)
        # 更新 theta
        theta -= alpha * grad_theta
    
    return theta