随机梯度下降
(SGD)是一种在凸损失函数(如(线性)
支持向量机
和
Logistic回归
)下拟合线性分类器和回归器的简单而有效的方法。尽管SGD在机器学习社区中已经存在了很长一段时间,但就在最近大规模学习的背景下,它得到了相当多的关注。
SGD已成功地应用于文本分类和自然语言处理中经常遇到的大规模和稀疏的机器学习问题。由于数据稀疏,本模块中的分类器很容易处理到具有
个训练样本和
个特征以上的问题。
严格地说,SGD只是一种优化技术,并不与特定的机器学习模型相对应。它只是训练模型的一种方式。通常,scikit-learn API中
SGDClassifier
或
SGDRegressor
具有等效的估计,只是可能使用了不同的优化技巧。例如,使用
SGDClassifier(loss='log')
将导致Logistic回归, 即一个等价于
LogisticRegression
的模型可以通过SGD拟合而不是
LogisticRegression
中其他的优化方案。类似的。
SGDRegressor(loss='squared_loss', penalty='l2')
和
Ridge
就是通过不同的方法解决了相同的优化问题。
随机梯度下降的优点是:
随机梯度下降的缺点包括:
在拟合模型之前,一定要重新排序(打乱的)训练数据,或者在每次迭代后(默认情况下使用)使用
shuffle=True
来打乱数据。此外,理想情况下,应该使用
make_pipeline(StandardScaler(), SGDClassifier())
(参见
Pipelines
)对特征进行标准化。
SGDClassifier
分类器实现了一个简单的随机梯度下降学习程序,支持不同的损失函数和惩罚项。下面是用合页损失(hinge loss)训练的
SGDClassifier
分类器的决策边界,相当于线性支持向量机。
作为其他分类器,SGD必须fit两个数组:一个包含训练样本的形状(n_samples, n_features) 的
X
和一个包含训练样本目标值(类标签)的形状 (n_samples)的数组y。
>>> from sklearn.linear_model import SGDClassifier
>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = SGDClassifier(loss="hinge", penalty="l2", max_iter=5)
>>> clf.fit(X, y)
SGDClassifier(max_iter=5)
经拟合后,该模型可用于预测新的值:
>>> clf.predict([[2., 2.]])
array([1])
SGD拟合训练数据的线性模型。
coef_
属性保存了模型参数:
>>> clf.coef_
array([[9.9..., 9.9...]])
intercept_
保存了截距项(又被称为 偏移(offset)或者偏差(bias))
>>> clf.intercept_
array([-9.9...])
模型是否使用截距项,即有偏的超平面(a biased hyperplane),是由参数
fit_intercept
控制的。
到超平面的符号距离(计算为系数和输入样本之间的点积,加上截距)可由
SGDClassifier.decision_function
:
>>> clf.decision_function([[2., 2.]])
array([29.6...])
可以通过
loss
参数设置具体的损失函数。
SGDClassifier
分类器支持以下损失函数:
loss="hinge"
:(软-间隔)线性支持向量机
loss="modified_huber
:平滑的合页损耗(smoothed hinge loss)
以及以下所有的回归损失。在这种情况下,目标被编码为-1或1,并且这个问题被看作是一个回归问题。然后,预测的类对应于预测目标的符号。
请参阅下面的
数学部分
的公式。前两个损失函数是懒惰的,它们只在一个样本违反边际约束的情况下更新模型参数,这使得训练非常有效,并且也可能导致稀疏模型(即更多的零系数), 即使使用的是L2惩罚。
使用
loss="log"
或者
loss="modified_huber"
来激活
predict_proba
方法,这会给每个样本
一个概率估计的向量
。
>>> clf = SGDClassifier(loss="log", max_iter=5).fit(X, y)
>>> clf.predict_proba([[1., 1.]])
array([[0.00..., 0.99...]])
具体的惩罚项可以通过
penalty
参数来设定。SGD支持以下惩罚项:
penalty="l2"
: L2 范数惩罚 在
coef_
penalty="l1"
: L1 范数惩罚 在
coef_
penalty="elasticnet"
: L1和L2的凸组合;
(1 - l1_ratio) * L2 + l1_ratio * L1
默认设置为
penalty="l2"
。L1惩罚会导致稀疏解,使大部分系数变为零。弹性网[11]在具有高度相关属性的情况下,解决了L1惩罚的一些不足。参数
l1_ratio
控制L1和L2惩罚的凸组合。
SGDClassifier
分类器通过使用“one versus all” (OVA)方案组合多个二分类器来支持多分类。对于每个
类,学习了一个二分类器,该分类器区分该类和所有其他
类。在测试时,我们计算每个分类器的置信分数(即到超平面的符号距离),并选择置信度分数最高的类。下图说明了在 iris数据集的OVA方法。虚线表示三个OVA分类器,背景颜色表示由三个分类器决定的的决策面。
在多分类的情况下,
coef_
是一个形状是 (n_classes, n_features)的二维数组,而
intercept_
是一个形状是(n_classes,)的一维数组。
coef_
的第i行是第i类的OVA分类器的权重向量;类按升序进行索引(请参见
class_
)。请注意,原则上,由于它们允许创建概率模型,所以
loss="log"
和
loss="modified_huber"
更适合于 one-vs-all分类。
SGDClassifier
分类器可以通过fit方法的参数
class_weight
和
sample_weight
来支持对类加权和对实例加权。有关更多信息,请参见下面的示例和
SGDClassifier.fit
的说明文档。
SGDClassifier
支持平均最近梯度下降(averaged SGD (ASGD))[10]。通过设置
average=True
来启用。ASGD与常规的SGD表现出相同的更新(参见数学公式),但不使用系数的最后一个值作为
coef_
(即上次更新的值),相反,
coef_
被设置为所有更新中系数的平均值。
对于具有逻辑损失的分类,另一种采用平均策略的SGD方法是用随机平均梯度(SAG)算法进行的,它可以作为
LogisticRegression
中的求解器。