SGDRegressor() 不断地不提高验证性能
SGDRegressor() constantly not increasing validation performance
在大约 20'000 个训练记录后,我的 SGDRegressor
的模型拟合不会提高或降低其在验证集 (test
) 上的性能。即使我尝试将 penalty
、early_stopping (True/False)
或 alpha
、eta0
切换到极高或极低的水平,“卡住”验证分数的行为也没有变化test
.
我之前使用 StandardScaler
并打乱了训练集和测试集的数据。
train_test_split(X,y, test_size = 0.3, random_state=85, shuffle=True)
print(X_train.shape, X_test.shape)
print(y_train.shape, y_test.shape)
>>>(336144, 10) (144063, 10)
>>>(336144,) (144063,)
我的验证代码有什么问题吗?或者由于 SGDRegressor
对训练数据的处理限制,这种行为是否可以解释?
from sklearn.linear_model import SGDRegressor
from sklearn.metrics import mean_squared_error
import pandas
import matplotlib.pyplot as plt
scores_test = []
scores_train = []
my_rng = range(10,len(X_train),30000)
for m in my_rng:
print(m)
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
ypred_train = modelSGD.predict(X_train[:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
我如何“强制”SGDRegressor
遵守大量训练数据并改变其在 test
数据上的表现?
编辑:
我试图想象模型在接受 30'000 或 300'000 条记录训练后不会改变其在 test
上的分数。这就是我在循环中初始化 SGDRegressor 的原因,因此它在每次迭代中都是全新训练的。
如@Nikaido 所问,这些是拟合后的模型coef_
、intercept_
:
trainsize: 10, coef: [ 0.81815135 2.2966633 1.61231584 -0.00339933 -3.03094922 0.12757874 -2.60874563 1.52383531 0.3250487 -0.61251297], intercept: [50.77553038]
trainsize: 30010, coef: [ 0.19097587 -0.35854903 -0.16142221 0.11281925 -0.66771756 0.55912533 0.90462141 -1.417289 0.50487032 -1.42423654], intercept: [83.28458307]
trainsize: 60010, coef: [ 0.09848169 -0.1362008 -0.15825232 -0.4401373 0.31664536 0.04960247 -0.37299047 0.6641436 0.02782047 -1.15355052], intercept: [80.87163096]
trainsize: 90010, coef: [-0.00923631 0.5845441 0.28485334 -0.29528061 -0.30643056 1.20320208 1.9723999 -0.47707621 1.25355186 -2.04990825], intercept: [85.17812028]
trainsize: 120010, coef: [-0.04959943 -0.15744169 -0.17071373 -0.20829149 -1.38683906 2.18572481 1.43380752 -1.48133799 2.18962484 -3.41135224], intercept: [86.40188522]
trainsize: 150010, coef: [ 0.56190926 0.05052168 0.22624504 0.55751301 -0.50829818 1.27571154 1.49847285 -0.15134682 1.30017967 -0.88259823], intercept: [83.69264344]
trainsize: 180010, coef: [ 0.17765624 0.1137466 0.15081498 -0.51520765 -1.00811419 -0.13203398 1.28565565 -0.03594421 -0.08053252 -2.31793746], intercept: [85.21824705]
trainsize: 210010, coef: [-0.53937513 -0.33872786 -0.44854466 0.70039384 -0.77073389 0.4361326 0.88175392 -0.32460908 0.5141777 -1.5123801 ], intercept: [82.75353293]
trainsize: 240010, coef: [ 0.70748011 -0.08992019 0.25365326 0.61999278 -0.29374005 0.25833863 -0.00485613 -0.21211637 0.19286126 -1.09503691], intercept: [85.76414815]
trainsize: 270010, coef: [ 0.73787648 0.30155102 0.44013832 -0.2355825 0.26255699 1.55410066 0.4733571 0.85352683 1.4399516 -1.73360843], intercept: [84.19473044]
trainsize: 300010, coef: [ 0.04861321 -0.35446415 -0.17774692 -0.1060901 -0.5864299 1.03429399 0.57160049 -0.13900199 1.09189946 -1.26298814], intercept: [83.14797646]
trainsize: 330010, coef: [ 0.20214825 0.22605839 0.17022397 0.28191112 -1.05982574 0.74025932 0.04981973 -0.27232538 0.72094765 -0.94875017], intercept: [81.97656309]
编辑2:
@Nikaido 自找的:这是数据的分布。非常相似的分布式 train-/testdata 特征是由于原始值是类别(范围 1-9)或解构的时间戳,如 NumberOfMonth、DayOfWeek、Hours、Minutes。
labels
图显示 100 左右缺乏正态分布。原因是:缺失值已被每个类别的全球平均值所取代,该平均值介于 80 和 95 之间。
此外,我创建了一个图表,通过更改以下代码片段显示由上面的代码片段生成的验证缩放:
my_rng = range(1000,len(X_train)-200000,2000)
可以看到典型的 SGD 围绕最佳值跳跃。但是无论如何,随着训练集记录的增加,测试分数的趋势不会发生任何显着变化。
编辑:关于你的输出,我的猜测是你的结果对于验证集来说非常接近,因为像 SGDregressor 这样的线性模型往往不适合复杂的数据
要查看此信息,您可以检查模型在每次迭代时输出的权重。你会看到它们是相同的或非常接近
要增强输出的可变性,您需要引入非线性和复杂性
您正在获得机器学习中所谓的“偏差”(与“方差”相对)
我想我现在明白了。
SamAmani 最后我觉得是欠拟合的问题。以及您正在使用数据集的增量大小这一事实。模型欠拟合非常快(这意味着模型一开始就卡在或多或少固定的模型上)
只有第一次训练为测试集输出不同的结果,因为它或多或少没有达到最终模型
潜在的可变性存在于增量训练集中。
简单来说,测试结果是对欠拟合模型性能的更准确估计。并且添加训练样本最终会导致测试和训练之间的接近结果,而不会改进太多。
您可以检查训练的增量数据集与测试集不同的事实。你做错的是检查所有训练集的统计数据
首先,您为什么要在增量训练集大小上进行训练?奇怪的结果是由于您正在以增量方式训练您的数据集。
当你这样做时:
for m in my_rng:
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
[...]
您基本上是以增量方式训练您的模型,增量大小为:
for m in range(10, 180001, 30000):
print(m)
10
30010
60010
90010
120010
150010
如果您尝试进行小批量梯度下降,则应将数据集拆分为独立的批次,而不是进行增量批次。像这样:
previous = 0
for m in range(30000, 180001, 30000):
modelSGD.partial_fit(X_train[previous:m], y_train[previous:m])
previous = m
# training set ranges
0 30000
30000 60000
60000 90000
90000 120000
120000 150000
150000 180000
另请注意,我使用的是 partial_fit
方法,而不是 fit
(因为我没有从零开始重新训练模型,我只做了一步,梯度下降的迭代),而且我不会每次都初始化一个新模型(我的 sgd 初始化不在 for 循环中)。完整的代码应该是这样的:
my_rng = range(0 ,len(X_train), 30000)
previous = 0
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
for m in my_rng:
modelSGD.partial_fit(X_train[previous:m], y_train[previous:m])
ypred_train = modelSGD.predict(X_train[previous:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[previous:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
通过这种方式,您可以模拟 一个时期 小批量随机梯度。为了制造更多的时代,需要一个外部循环
来自 sklearn:
SGD allows minibatch (online/out-of-core) learning via the partial_fit
method. For best results using the default learning rate schedule, the
data should have zero mean and unit variance.
详情here
我认为您要做的是查看数据集大小增加对模型性能的影响。如果是这种情况,如您所见,随着数据大小的增加,错误会增加,并且它会达到一个阶段,在这个阶段,有了足够的数据,它就会开始学习(训练错误略有减少),并随着数据集的增加而最终稳定下来,现在这无关紧要。它也不会过度拟合,因为默认情况下 SGDRegressor
仅运行 1000 个时期。
我建议你在拟合之前对数据进行归一化(0 均值和单位方差)。
测试代码:
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import SGDRegressor
from sklearn.metrics import mean_squared_error
import pandas
import matplotlib.pyplot as plt
X = np.random.randn(336144+144063, 10)
y = np.sum(X, axis=1) + np.random.randn(336144+144063)
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.3, random_state=85, shuffle=True)
print (X_train.shape, X_test.shape)
scores_test = []
scores_train = []
my_rng = range(5000,len(X_train),10000)
for m in my_rng:
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
ypred_train = modelSGD.predict(X_train[:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
plt.plot(scores_train)
plt.plot(scores_test)
如果您正在尝试批量梯度体面,请遵循@Nikaido
的回答
在大约 20'000 个训练记录后,我的 SGDRegressor
的模型拟合不会提高或降低其在验证集 (test
) 上的性能。即使我尝试将 penalty
、early_stopping (True/False)
或 alpha
、eta0
切换到极高或极低的水平,“卡住”验证分数的行为也没有变化test
.
我之前使用 StandardScaler
并打乱了训练集和测试集的数据。
train_test_split(X,y, test_size = 0.3, random_state=85, shuffle=True)
print(X_train.shape, X_test.shape)
print(y_train.shape, y_test.shape)
>>>(336144, 10) (144063, 10)
>>>(336144,) (144063,)
我的验证代码有什么问题吗?或者由于 SGDRegressor
对训练数据的处理限制,这种行为是否可以解释?
from sklearn.linear_model import SGDRegressor
from sklearn.metrics import mean_squared_error
import pandas
import matplotlib.pyplot as plt
scores_test = []
scores_train = []
my_rng = range(10,len(X_train),30000)
for m in my_rng:
print(m)
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
ypred_train = modelSGD.predict(X_train[:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
我如何“强制”SGDRegressor
遵守大量训练数据并改变其在 test
数据上的表现?
编辑:
我试图想象模型在接受 30'000 或 300'000 条记录训练后不会改变其在 test
上的分数。这就是我在循环中初始化 SGDRegressor 的原因,因此它在每次迭代中都是全新训练的。
如@Nikaido 所问,这些是拟合后的模型coef_
、intercept_
:
trainsize: 10, coef: [ 0.81815135 2.2966633 1.61231584 -0.00339933 -3.03094922 0.12757874 -2.60874563 1.52383531 0.3250487 -0.61251297], intercept: [50.77553038]
trainsize: 30010, coef: [ 0.19097587 -0.35854903 -0.16142221 0.11281925 -0.66771756 0.55912533 0.90462141 -1.417289 0.50487032 -1.42423654], intercept: [83.28458307]
trainsize: 60010, coef: [ 0.09848169 -0.1362008 -0.15825232 -0.4401373 0.31664536 0.04960247 -0.37299047 0.6641436 0.02782047 -1.15355052], intercept: [80.87163096]
trainsize: 90010, coef: [-0.00923631 0.5845441 0.28485334 -0.29528061 -0.30643056 1.20320208 1.9723999 -0.47707621 1.25355186 -2.04990825], intercept: [85.17812028]
trainsize: 120010, coef: [-0.04959943 -0.15744169 -0.17071373 -0.20829149 -1.38683906 2.18572481 1.43380752 -1.48133799 2.18962484 -3.41135224], intercept: [86.40188522]
trainsize: 150010, coef: [ 0.56190926 0.05052168 0.22624504 0.55751301 -0.50829818 1.27571154 1.49847285 -0.15134682 1.30017967 -0.88259823], intercept: [83.69264344]
trainsize: 180010, coef: [ 0.17765624 0.1137466 0.15081498 -0.51520765 -1.00811419 -0.13203398 1.28565565 -0.03594421 -0.08053252 -2.31793746], intercept: [85.21824705]
trainsize: 210010, coef: [-0.53937513 -0.33872786 -0.44854466 0.70039384 -0.77073389 0.4361326 0.88175392 -0.32460908 0.5141777 -1.5123801 ], intercept: [82.75353293]
trainsize: 240010, coef: [ 0.70748011 -0.08992019 0.25365326 0.61999278 -0.29374005 0.25833863 -0.00485613 -0.21211637 0.19286126 -1.09503691], intercept: [85.76414815]
trainsize: 270010, coef: [ 0.73787648 0.30155102 0.44013832 -0.2355825 0.26255699 1.55410066 0.4733571 0.85352683 1.4399516 -1.73360843], intercept: [84.19473044]
trainsize: 300010, coef: [ 0.04861321 -0.35446415 -0.17774692 -0.1060901 -0.5864299 1.03429399 0.57160049 -0.13900199 1.09189946 -1.26298814], intercept: [83.14797646]
trainsize: 330010, coef: [ 0.20214825 0.22605839 0.17022397 0.28191112 -1.05982574 0.74025932 0.04981973 -0.27232538 0.72094765 -0.94875017], intercept: [81.97656309]
编辑2:
@Nikaido 自找的:这是数据的分布。非常相似的分布式 train-/testdata 特征是由于原始值是类别(范围 1-9)或解构的时间戳,如 NumberOfMonth、DayOfWeek、Hours、Minutes。
labels
图显示 100 左右缺乏正态分布。原因是:缺失值已被每个类别的全球平均值所取代,该平均值介于 80 和 95 之间。
此外,我创建了一个图表,通过更改以下代码片段显示由上面的代码片段生成的验证缩放:
my_rng = range(1000,len(X_train)-200000,2000)
可以看到典型的 SGD 围绕最佳值跳跃。但是无论如何,随着训练集记录的增加,测试分数的趋势不会发生任何显着变化。
编辑:关于你的输出,我的猜测是你的结果对于验证集来说非常接近,因为像 SGDregressor 这样的线性模型往往不适合复杂的数据
要查看此信息,您可以检查模型在每次迭代时输出的权重。你会看到它们是相同的或非常接近
要增强输出的可变性,您需要引入非线性和复杂性
您正在获得机器学习中所谓的“偏差”(与“方差”相对)
我想我现在明白了。
SamAmani 最后我觉得是欠拟合的问题。以及您正在使用数据集的增量大小这一事实。模型欠拟合非常快(这意味着模型一开始就卡在或多或少固定的模型上)
只有第一次训练为测试集输出不同的结果,因为它或多或少没有达到最终模型
潜在的可变性存在于增量训练集中。 简单来说,测试结果是对欠拟合模型性能的更准确估计。并且添加训练样本最终会导致测试和训练之间的接近结果,而不会改进太多。
您可以检查训练的增量数据集与测试集不同的事实。你做错的是检查所有训练集的统计数据
首先,您为什么要在增量训练集大小上进行训练?奇怪的结果是由于您正在以增量方式训练您的数据集。
当你这样做时:
for m in my_rng:
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
[...]
您基本上是以增量方式训练您的模型,增量大小为:
for m in range(10, 180001, 30000):
print(m)
10
30010
60010
90010
120010
150010
如果您尝试进行小批量梯度下降,则应将数据集拆分为独立的批次,而不是进行增量批次。像这样:
previous = 0
for m in range(30000, 180001, 30000):
modelSGD.partial_fit(X_train[previous:m], y_train[previous:m])
previous = m
# training set ranges
0 30000
30000 60000
60000 90000
90000 120000
120000 150000
150000 180000
另请注意,我使用的是 partial_fit
方法,而不是 fit
(因为我没有从零开始重新训练模型,我只做了一步,梯度下降的迭代),而且我不会每次都初始化一个新模型(我的 sgd 初始化不在 for 循环中)。完整的代码应该是这样的:
my_rng = range(0 ,len(X_train), 30000)
previous = 0
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
for m in my_rng:
modelSGD.partial_fit(X_train[previous:m], y_train[previous:m])
ypred_train = modelSGD.predict(X_train[previous:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[previous:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
通过这种方式,您可以模拟 一个时期 小批量随机梯度。为了制造更多的时代,需要一个外部循环
来自 sklearn:
SGD allows minibatch (online/out-of-core) learning via the partial_fit method. For best results using the default learning rate schedule, the data should have zero mean and unit variance.
详情here
我认为您要做的是查看数据集大小增加对模型性能的影响。如果是这种情况,如您所见,随着数据大小的增加,错误会增加,并且它会达到一个阶段,在这个阶段,有了足够的数据,它就会开始学习(训练错误略有减少),并随着数据集的增加而最终稳定下来,现在这无关紧要。它也不会过度拟合,因为默认情况下 SGDRegressor
仅运行 1000 个时期。
我建议你在拟合之前对数据进行归一化(0 均值和单位方差)。
测试代码:
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import SGDRegressor
from sklearn.metrics import mean_squared_error
import pandas
import matplotlib.pyplot as plt
X = np.random.randn(336144+144063, 10)
y = np.sum(X, axis=1) + np.random.randn(336144+144063)
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.3, random_state=85, shuffle=True)
print (X_train.shape, X_test.shape)
scores_test = []
scores_train = []
my_rng = range(5000,len(X_train),10000)
for m in my_rng:
modelSGD = SGDRegressor(alpha=0.00001, penalty='l1')
modelSGD.fit(X_train[:m], y_train[:m])
ypred_train = modelSGD.predict(X_train[:m])
ypred_test = modelSGD.predict(X_test)
mse_train = mean_squared_error(y_train[:m], ypred_train)
mse_test = mean_squared_error(y_test, ypred_test)
scores_train.append(mse_train)
scores_test.append(mse_test)
plt.plot(scores_train)
plt.plot(scores_test)
如果您正在尝试批量梯度体面,请遵循@Nikaido
的回答