您的位置:

随机梯度下降法

一、基本概念

随机梯度下降法(Stochastic Gradient Descent,SGD)相对于传统的梯度下降法,是一种更为高效的机器学习优化算法。梯度下降法每次迭代都要遍历整个训练集,计算所有样本的梯度才能更新权重,因此在大规模数据的情况下会十分耗时。而SGD每次只选取一个或一小批量样本来计算梯度,从而使得每次迭代的计算量大大降低,具有更高的计算效率。

SGD的具体实现过程如下:对于目标函数 $J(w)$,权重 $w$,学习率 $\eta$,SGD每次从训练集中随机选取一个样本 $x_i$,计算该样本的梯度 $g_i$,然后使用梯度下降法的公式更新权重:$w = w - \eta g_i$。这样不断迭代更新,直到达到一定的迭代次数或者达到收敛要求即可。

下面给出SGD的伪代码实现:

for i in range(0, max_iter):
    shuffle(X)  # 打乱训练集
    for j in range(num_samples):
        # 随机选取一个训练样本进行梯度计算
        xi = X[j]
        yi = y[j]
        gi = compute_gradient(J, xi, yi, w)
        # 更新权重
        w = w - eta * gi

二、SGD的优点

1、高效:SGD每次只需要计算一个样本的梯度,计算量较小,适合大规模数据集的优化问题。

2、易于并行:SGD每次更新只操作一个样本,易于实现并行化操作,从而大大缩短了计算时间。

3、可收敛到局部最优解:SGD的收敛路径具有一定的随机性,能在一定程度上跳出局部最优解,收敛到全局最优解的概率也相对较大。

三、SGD的缺点与改进

1、收敛速度慢:SGD每次只更新一个样本,可能会出现跳出最优解的情况,同时也容易受到样本噪声的干扰,导致收敛速度慢。

2、有一定的不稳定性:由于每次只考虑一个样本,SGD可能会受到单个样本的影响,进而影响到整个模型的参数更新。

为了克服SGD的缺点,研究者们提出了一系列改进方法。其中最常见的是Batch SGD和Mini-batch SGD。Batch SGD每次更新所有的样本梯度,Mini-batch SGD选取一个小批量样本进行梯度计算,大小通常设置在2~256之间。这样权衡了运算速度和参数更新的精度。

下面给出Mini-batch SGD的实现代码:

for i in range(0, max_iter):
    shuffle(X)  # 打乱训练集
    for j in range(0, num_samples, batch_size):
        # 随机选取一个小批量训练样本进行梯度计算
        batch_indices = range(j, min(j + batch_size, num_samples))
        X_batch = X[batch_indices]
        y_batch = y[batch_indices]
        gi = compute_gradient(J, X_batch, y_batch, w)
        # 更新权重
        w = w - eta * gi

四、实战代码示例

下面以sklearn库中的breast_cancer数据集为例,展示如何使用SGDClassifier类进行二分类问题训练。在示例代码中,我们使用SGDClassifier类进行100次迭代的训练,打印出了训练集和测试集上的分类准确率。

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 加载数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 数据归一化
scaler = StandardScaler()
X = scaler.fit_transform(X)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 使用SGDClassifier进行训练
clf = SGDClassifier(max_iter=100, tol=1e-3)
clf.fit(X_train, y_train)

# 打印结果
print("Train set score:", clf.score(X_train, y_train))
print("Test set score:", clf.score(X_test, y_test))