1. 考虑多项式的模型选择。
- 绘制训练损失与模型复杂度(多项式的阶数)的关系图。观察到了什么?需要多少阶的多项式才能将训练损失减少到0?
- 在这种情况下绘制测试的损失图。
- 生成同样的图,作为数据量的函数。
for i in range(max_degree):
d = i + 1
e = d * 100
# e = 2000
train(poly_features[:n_train, :d], poly_features[n_train:, :d],
labels[:n_train], labels[n_train:], num_epochs=e)
2. 如果不对多项式特征进行标准化(),会发生什么事情?能用其他方法解决这个问题吗?
with gamma
max_degree = 20 # 多项式的最大阶数
n_train, n_test = 100, 100 # 训练和测试数据集大小
true_w = np.zeros(max_degree) # 分配大量的空间
true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])
features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)
gamma_poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
for i in range(max_degree):
gamma_poly_features[:, i] /= math.gamma(i + 1) # gamma(n)=(n-1)!
# labels的维度:(n_train+n_test,)
gamma_labels = np.dot(gamma_poly_features, true_w)
gamma_labels += np.random.normal(scale=0.1, size=labels.shape)
# NumPy ndarray转换为tensor
true_w, features, gamma_poly_features, gamma_labels = [torch.tensor(x, dtype=
torch.float32) for x in [true_w, features, gamma_poly_features, gamma_labels]]
features.shape, gamma_poly_features.shape, gamma_labels.shape, features[:2], gamma_poly_features[:2, :], gamma_labels[:2]
(torch.Size([200, 1]),
torch.Size([200, 20]),
torch.Size([200]),
tensor([[-0.0621],
[-0.4298]]),
tensor([[ 1.0000e+00, -6.2061e-02, 1.9258e-03, -3.9840e-05, 6.1813e-07,
-7.6724e-09, 7.9360e-11, -7.0360e-13, 5.4583e-15, -3.7639e-17,
2.3359e-19, -1.3179e-21, 6.8160e-24, -3.2539e-26, 1.4425e-28,
-5.9681e-31, 2.3149e-33, -8.4510e-36, 2.9138e-38, -9.5176e-41],
[ 1.0000e+00, -4.2976e-01, 9.2345e-02, -1.3229e-02, 1.4213e-03,
-1.2216e-04, 8.7497e-06, -5.3718e-07, 2.8857e-08, -1.3779e-09,
5.9217e-11, -2.3135e-12, 8.2855e-14, -2.7390e-15, 8.4079e-17,
-2.4089e-18, 6.4702e-20, -1.6356e-21, 3.9052e-23, -8.8330e-25]]),
tensor([4.9596, 4.0755]))
d = 4
e = d * 100
train(gamma_poly_features[:n_train, :d], gamma_poly_features[n_train:, :d],
gamma_labels[:n_train], gamma_labels[n_train:], num_epochs=e)
weight: [[ 5.01118 1.2015356 -3.4186318 5.5990167]]
without gamma
max_degree = 20 # 多项式的最大阶数
n_train, n_test = 100, 100 # 训练和测试数据集大小
true_w = np.zeros(max_degree) # 分配大量的空间
true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])
features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)
poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
# for i in range(max_degree):
# poly_features[:, i] /= math.gamma(i + 1) # gamma(n)=(n-1)!
# labels的维度:(n_train+n_test,)
labels = np.dot(poly_features, true_w)
labels += np.random.normal(scale=0.1, size=labels.shape)
# NumPy ndarray转换为tensor
true_w, features, poly_features, labels = [torch.tensor(x, dtype=
torch.float32) for x in [true_w, features, poly_features, labels]]
features.shape, poly_features.shape, labels.shape, features[:2], poly_features[:2, :], labels[:2]
(torch.Size([200, 1]),
torch.Size([200, 20]),
torch.Size([200]),
tensor([[-0.1662],
[ 0.8026]]),
tensor([[ 1.0000e+00, -1.6618e-01, 2.7615e-02, -4.5891e-03, 7.6261e-04,
-1.2673e-04, 2.1060e-05, -3.4997e-06, 5.8157e-07, -9.6645e-08,
1.6060e-08, -2.6689e-09, 4.4351e-10, -7.3703e-11, 1.2248e-11,
-2.0353e-12, 3.3823e-13, -5.6206e-14, 9.3403e-15, -1.5522e-15],
[ 1.0000e+00, 8.0259e-01, 6.4416e-01, 5.1700e-01, 4.1494e-01,
3.3303e-01, 2.6729e-01, 2.1452e-01, 1.7218e-01, 1.3819e-01,
1.1091e-01, 8.9014e-02, 7.1442e-02, 5.7339e-02, 4.6020e-02,
3.6936e-02, 2.9644e-02, 2.3792e-02, 1.9096e-02, 1.5326e-02]]),
tensor([4.7135, 6.7431]))
d = 4
e = d * 100
train(poly_features[:n_train, :d], poly_features[n_train:, :d],
labels[:n_train], labels[n_train:], num_epochs=e)
weight: [[ 4.9793344 1.2051544 -3.3951492 5.6004477]]
3. 泛化误差可能为零吗?
泛化误差是指模型在未知数据上的表现与在训练数据上的表现之间的差异。理想情况下,我们希望模型的泛化误差尽可能小,但这通常受到多种因素的影响,包括模型的复杂度、数据的质量和数量、以及模型是否过拟合或欠拟合。
对于给定的多项式回归问题,如果满足以下条件,理论上泛化误差可以为零:
-
数据完全由模型生成:如果所有的数据点都是由上述多项式方程精确生成的,没有额外的噪声或误差,那么理论上存在一个模型能够完美地拟合所有数据点。
-
模型复杂度足够:对于多项式回归,如果多项式的阶数高于或等于数据中多项式的阶数,并且数据点足够覆盖多项式的变化,那么模型可以完美地拟合训练数据。
-
没有过拟合:如果模型没有对训练数据过拟合,即它不仅在训练数据上表现良好,而且能够推广到新的、未见过的数据上,那么泛化误差可以为零。
然而,在现实世界中,泛化误差为零的情况非常罕见,因为:
- 数据通常包含噪声或测量误差。
- 模型可能无法捕捉到数据生成过程中的所有复杂性。
- 即使模型能够完美拟合训练数据,它也可能因为过拟合而无法泛化到新数据上。
由于存在噪声项 ,即使模型能够完美地拟合训练数据,它在未知数据上的表现(即泛化误差)也不可能为零,因为噪声项会导致预测值与实际值之间存在偏差。此外,如果模型过于复杂,它可能会对训练数据过拟合,从而在新数据上表现不佳,这也会增加泛化误差。
因此,虽然理论上在某些理想情况下泛化误差可以为零,但在实际应用中,我们通常期望通过选择合适的模型复杂度、使用足够的数据以及采用正则化技术等方法来最小化泛化误差,而不是完全消除它。
without
max_degree = 20 # 多项式的最大阶数
n_train, n_test = 100, 100 # 训练和测试数据集大小
true_w = np.zeros(max_degree) # 分配大量的空间
true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])
features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)
gamma_poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
for i in range(max_degree):
gamma_poly_features[:, i] /= math.gamma(i + 1) # gamma(n)=(n-1)!
# labels的维度:(n_train+n_test,)
gamma_labels = np.dot(gamma_poly_features, true_w)
# gamma_labels += np.random.normal(scale=0.1, size=labels.shape)
# NumPy ndarray转换为tensor
true_w, features, gamma_poly_features, gamma_labels = [torch.tensor(x, dtype=
torch.float32) for x in [true_w, features, gamma_poly_features, gamma_labels]]
features.shape, gamma_poly_features.shape, gamma_labels.shape, features[:2], gamma_poly_features[:2, :], gamma_labels[:2]
(torch.Size([200, 1]),
torch.Size([200, 20]),
torch.Size([200]),
tensor([[ 0.1988],
[-0.5901]]),
tensor([[ 1.0000e+00, 1.9882e-01, 1.9765e-02, 1.3099e-03, 6.5112e-05,
2.5891e-06, 8.5797e-08, 2.4369e-09, 6.0565e-11, 1.3380e-12,
2.6602e-14, 4.8082e-16, 7.9666e-18, 1.2184e-19, 1.7304e-21,
2.2936e-23, 2.8501e-25, 3.3333e-27, 3.6819e-29, 3.8529e-31],
[ 1.0000e+00, -5.9012e-01, 1.7412e-01, -3.4251e-02, 5.0531e-03,
-5.9638e-04, 5.8656e-05, -4.9449e-06, 3.6476e-07, -2.3917e-08,
1.4114e-09, -7.5718e-11, 3.7236e-12, -1.6903e-13, 7.1248e-15,
-2.8030e-16, 1.0338e-17, -3.5887e-19, 1.1765e-20, -3.6542e-22]]),
tensor([5.1787, 3.5080]))
d = 4
e = d * 100
train(gamma_poly_features[:n_train, :d], gamma_poly_features[n_train:, :d],
gamma_labels[:n_train], gamma_labels[n_train:], num_epochs=e)
weight: [[ 5.013901 1.2503921 -3.4414685 5.448303 ]]
d = 20
e = d * 500
train(gamma_poly_features[:n_train, :d], gamma_poly_features[n_train:, :d],
gamma_labels[:n_train], gamma_labels[n_train:], num_epochs=e)
weight: [[ 5.0032783e+00 1.2176764e+00 -3.4226160e+00 5.4686260e+00
6.2438816e-02 6.0024190e-01 3.7112460e-01 -3.9951559e-02
-4.5692152e-03 -7.6371424e-02 1.3686322e-01 -1.3537474e-01
5.5166412e-02 -1.7218257e-01 -1.7852859e-01 -5.8814079e-02
1.9375089e-01 -1.5742062e-01 -1.2403440e-02 1.2170445e-01]]