Power by GeekHades

线性回归——梯度下降实现

前言

梯度下降(Gradient Descent)是一种常见数学优化方法,其目的是求得一组参数latex1, 使得代价函数(Cost Function) 𝐽(𝞱)取值最小。

本文先分析线性回归使用梯度下降的原理,最后给出Octave\Matlab & Python的相应实现。

原理分析

设一假设函数(Hypothesis Function) 为H(x);,则在线性回归(Linear Regression)中可表示为如下形式:

latex3

其矩阵(向量)表示形式为:

latex4

线性回归的目的就是找到一个合适的数学模型能够尽量多的拟合给定数据。因此只要向量 𝞱确定那么数学模型也相应被确定。那么我们该如何评估每一组𝞱的好与坏?

所以我们需要引入代价函数,其定义如下:

latex5

显然latex6 是求出假设函数H(x) 与目标值y之间的均方差和,我们的目的就是要求均方差和最小。

为此引入梯度下降的算法模型:

latex7

其中𝝰是下降率,亦称学习率,代表着梯度下降算法的下降速度,是一个大于零的实数。

的偏导数。

假设 函数𝐽(𝞱)的函数图像如下图所示,A, B分别为𝞱在两个不同取值下的对应函数点,图像上两线段分别为A,B两点的切线,其切线斜率也即该点的一阶偏导数latex9

1

从图中易知,A点的切线斜率符号为负,B点的切线斜率符号为正。因此假设此时𝞱取值为A点,则根据梯度下降公式:

latex10

易得出:

latex11

可知位于A点时 𝞱 在迭代更新过程中会不断的向右靠拢一直到局部最低点,此时latex9

B点同理。

实现

注意事项

  • 代价函数不收敛:在使用梯度下降对𝞱 进行多次迭代的时候,很可能会出现的现象就是不收敛,不收敛的一个主要原因可能是其下降率(学习率)𝝰过大,导致在迭代的过程中越过了局部极值点。因此建议换一个较小的𝝰,常用的𝝰值有0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1
  • 更新𝞱 的策略:在迭代过程中要非常注意的一点,千万不要使用本轮迭代更新后的前𝑖项𝞱 对第𝑖 + 1项𝞱 进行求值,会造成程度不一的误差。

在实现之前我们约定几个公共的数据项:

latex12

矩阵𝑿为训练数据(Training data)矩阵,行向量𝒚为对应的目标值,行向量𝞱为方程的参数矩阵;其中𝒎代表样本个数, 𝒏代表数据特征(feature)个数,矩阵𝑿的第一列均为1, 因为𝞱0是常数项。

目标算法:

latex7

即:

latex13

任何包含了线性代数算法的语言都可以实现梯度下降算法,伪代码如下:

h_vals = X * theta;     // prediction values;
temp = theta - ((alpha/m) * (transpose(X) * (h_vals-y)));   // gradient descent;
theta = temp;           // update theta;

Octave/Matlab:

function theta = GradientDescent(X, y, alpha, theta, iter)
    % X is training data matrix
    % y is label value
    % alpha is learning rate
    % theta is hypothesis parameters
    % iter is iteration number.
    m = length(y);
    n = size(theta, 1);
    temp = zeros(n, 1);

    for i = 1:iter
        h_vals = X * theta;
        temp = theta - ((alpha/m) * (X'*(h_vals-y)));
        theta = temp;
    end
end

Python:

import numpy as np

def GradientDescent(X: np.ndarray, y: np.ndarray, 
                      alpha: float, theta: np.ndarray, iter: int) -> np.ndarray:
    m = X.shape[0]
    n = theta.shape[0]
    temp = np.zeros((n, 1))
    for _ in range(iter):
        h = np.dot(X, theta)
        temp = theta - ( (alpha/m) * np.dot(np.transpose(X), (h-y) ) )
        theta = temp
    return theta

以上代码全部编译通过且结果与期望值一致。

最后祝大家学习进步、工作顺利、身体健康!



* 如果你对文章有任何意见或建议请发 邮件 给我!
* if you have any suggestion that you could send a E-mail to me, Please!