ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【动手学深度学习】多层感知机模型选择、欠拟合和过拟合研究详情

【动手学深度学习】多层感知机模型选择、欠拟合和过拟合研究详情 目录1. 研究目的2. 研究准备3. 研究内容3.1 多层感知机模型选择、⽋拟合和过拟合3.2 基础练习4. 研究体会1. 研究目的多层感知机模型选择比较不同多层感知机模型的性能选择最适合解决给定问题的模型欠拟合和过拟合研究模型在训练数据上出现欠拟合或过拟合的情况以便了解模型的泛化能力和优化方法的效果模型正则化和调参通过实验观察和比较研究正则化技术和调参对模型的影响以改善模型的泛化性能模型复杂度与性能探究多层感知机模型的复杂度对训练和测试性能的影响以及如何找到合适的模型复杂度。2. 研究准备根据GPU安装pytorch版本实现GPU运行研究代码配置环境用来运行 Python、Jupyter Notebook和相关库等相关库。3. 研究内容启动jupyter notebook使用新增的pytorch环境新建ipynb文件为了检查环境配置是否合理输入import torch以及torch.cuda.is_available()若返回TRUE则说明研究环境配置正确若返回False但可以正确导入torch则说明pytorch配置成功但研究运行是在CPU进行的结果如下3.1多层感知机模型选择、⽋拟合和过拟合1使用jupyter notebook新增的pytorch环境新建ipynb文件完成基本数据操作的研究代码与练习结果如下导入相关库import math import numpy as np import torch from torch import nn from d2l import torch as d2l生成数据集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_trainn_test,) labels np.dot(poly_features, true_w) labels np.random.normal(scale0.1, sizelabels.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[:2], poly_features[:2, :], labels[:2]对模型进行训练和测试def evaluate_loss(net, data_iter, loss): #save 评估给定数据集上模型的损失 metric d2l.Accumulator(2) # 损失的总和,样本数量 for X, y in data_iter: out net(X) y y.reshape(out.shape) l loss(out, y) metric.add(l.sum(), l.numel()) return metric[0] / metric[1] def train(train_features, test_features, train_labels, test_labels, num_epochs400): loss nn.MSELoss(reductionmean) input_shape train_features.shape[-1] # 不设置偏置因为我们已经在多项式中实现了它 net nn.Sequential(nn.Linear(input_shape, 1, biasFalse)) batch_size min(10, train_labels.shape[0]) train_iter d2l.load_array((train_features, train_labels.reshape(-1,1)), batch_size) test_iter d2l.load_array((test_features, test_labels.reshape(-1,1)), batch_size, is_trainFalse) trainer torch.optim.SGD(net.parameters(), lr0.01) animator d2l.Animator(xlabelepoch, ylabelloss, yscalelog, xlim[1, num_epochs], ylim[1e-3, 1e2], legend[train, test]) for epoch in range(num_epochs): d2l.train_epoch_ch3(net, train_iter, loss, trainer) if epoch 0 or (epoch 1) % 20 0: animator.add(epoch 1, (evaluate_loss(net, train_iter, loss), evaluate_loss(net, test_iter, loss))) print(weight:, net[0].weight.data.numpy())三阶多项式函数拟合(正常)# 从多项式特征中选择前4个维度即1,x,x^2/2!,x^3/3! train(poly_features[:n_train, :4], poly_features[n_train:, :4], labels[:n_train], labels[n_train:])线性函数拟合(欠拟合)# 从多项式特征中选择前2个维度即1和x train(poly_features[:n_train, :2], poly_features[n_train:, :2], labels[:n_train], labels[n_train:])高阶多项式函数拟合(过拟合)# 从多项式特征中选取所有维度 train(poly_features[:n_train, :], poly_features[n_train:, :], labels[:n_train], labels[n_train:], num_epochs1500)3.2 基础练习1.这个多项式回归问题可以准确地解出吗提示使用线性代数。可以求解。多项式回归问题可以转化为一个线性方程组的求解问题。假设多项式回归模型是一个关于特征变量 x 的多项式函数形式为 y w0 w1 * x w2 * x^2 ... wn * x^n其中 wi 是待求解的系数。现在假设有 m 个样本点每个样本点的特征变量 x 和对应的目标变量 y 都已知。你可以将这 m 个样本点组成一个矩阵 X 和一个向量 Y其中 X 是一个 m×(n1) 的矩阵每一行包含特征变量 x 的不同幂次的值Y 是一个 m 维的向量包含每个样本点的目标变量 y。通过线性代数的方法可以使用最小二乘法求解以下方程组来找到系数向量 wX^T * X * w X^T * Y其中 X^T 表示 X 的转置矩阵。解这个方程组可以得到系数向量 w 的准确解从而得到多项式回归模型。需要注意的是这种方法只在样本点的数量 m 大于等于系数的数量 n1 时才能准确求解。当 m 小于 n1 时这个线性方程组是一个超定方程组可能没有准确解。在这种情况下可以使用最小二乘法的近似解。总结起来对于多项式回归问题当样本点的数量充足m n1时可以使用线性代数的方法准确求解系数向量 w。当样本点的数量不足时可以使用最小二乘法来近似求解。2.考虑多项式的模型选择。2.1.绘制训练损失与模型复杂度多项式的阶数的关系图。观察到了什么需要多少阶的多项式才能将训练损失减少到0?在这个修改后的代码中循环遍历不同的多项式阶数对于每个阶数调用train函数并将返回的训练损失添加到train_losses列表中。最后使用plt.plot函数绘制多项式阶数与训练损失之间的关系图表。运行修改后的代码将会生成训练损失与多项式阶数之间的图表。观察图表可以看到随着多项式阶数的增加训练损失逐渐减小。然而当多项式阶数过高时训练损失可能会变得很小甚至降低到接近零的程度。但需要注意的是过高的多项式阶数可能导致过拟合问题。根据图表可以看出多项式阶数为4时训练损失已经减少到接近零的程度。因此至少需要4阶的多项式才能将训练损失减少到零。import matplotlib.pyplot as plt def train(train_features, test_features, train_labels, test_labels, num_epochs400): loss nn.MSELoss(reductionmean) input_shape train_features.shape[-1] # 不设置偏置因为我们已经在多项式中实现了它 net nn.Sequential(nn.Linear(input_shape, 1, biasFalse)) batch_size min(10, train_labels.shape[0]) train_iter d2l.load_array((train_features, train_labels.reshape(-1,1)), batch_size) test_iter d2l.load_array((test_features, test_labels.reshape(-1,1)), batch_size, is_trainFalse) trainer torch.optim.SGD(net.parameters(), lr0.01) animator d2l.Animator(xlabelepoch, ylabelloss, yscalelog, xlim[1, num_epochs], ylim[1e-3, 1e2], legend[train, test]) for epoch in range(num_epochs): d2l.train_epoch_ch3(net, train_iter, loss, trainer) if epoch 0 or (epoch 1) % 20 0: animator.add(epoch 1, (evaluate_loss(net, train_iter, loss), evaluate_loss(net, test_iter, loss))) train_loss evaluate_loss(net, train_iter, loss) return net, train_loss degrees np.arange(max_degree) train_losses [] for degree in degrees: _, train_loss train(poly_features[:n_train, :(degree1)], poly_features[n_train:, :(degree1)], labels[:n_train], labels[n_train:]) train_losses.append(train_loss) plt.plot(degrees, train_losses) plt.xlabel(Degree of Polynomial) plt.ylabel(Train Loss) plt.show()2.2 在这种情况下绘制测试的损失图。degree 4 _, test_loss train(poly_features[:n_train, :degree1], poly_features[n_train:, :degree1], labels[:n_train], labels[n_train:]) print(fTest Loss (Degree {degree}): {test_loss}) plt.plot([degree], [test_loss], ro) plt.xlabel(Degree of Polynomial) plt.ylabel(Test Loss) plt.show()2.3 生成同样的图作为数据量的函数。degrees np.arange(1, max_degree1) test_losses [] for degree in degrees: _, test_loss train(poly_features[:degree*n_train, :4], poly_features[n_train:, :4], labels[:degree*n_train], labels[n_train:]) test_losses.append(test_loss) plt.plot(degrees * n_train, test_losses) plt.xlabel(Number of Data Points) plt.ylabel(Test Loss) plt.show()依次是1阶至20阶的图像数据3.如果不对多项式特征x^i进行标准化(1/i)会发生什么事情能用其他方法解决这个问题吗如果不对多项式特征 x^i 进行标准化1/i!会导致不同阶数的多项式特征具有不同的数值范围和尺度。这可能会使训练过程变得困难因为不同特征的权重更新可能会受到不同程度的影响使得模型难以收敛。另一种解决这个问题的方法是使用特征缩放feature scaling。特征缩放是将不同特征的数值范围映射到相同范围的过程常见的方法是将特征值减去均值并除以标准差即进行标准化。这样做可以确保所有特征具有相似的尺度有助于加速模型的训练过程和收敛性。在多项式特征的情况下如果不进行标准化可以尝试对原始特征进行标准化而不是对多项式特征进行标准化。这意味着对输入特征 x 进行标准化然后再进行多项式特征的构建。这样可以确保所有输入特征具有相似的尺度并且多项式特征也会受到相同的标准化影响。以下是修改后的代码示例import math import numpy as np import torch from torch import nn from d2l import torch as d2l import matplotlib.pyplot as plt 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) # 特征缩放对原始特征进行标准化 mean np.mean(features) std np.std(features) features (features - mean) / std poly_features np.power(features, np.arange(max_degree).reshape(1, -1)) labels np.dot(poly_features, true_w) labels np.random.normal(scale0.1, sizelabels.shape) # NumPy ndarray转换为tensor true_w, features, poly_features, labels [torch.tensor(x, dtypetorch.float32) for x in [true_w, features, poly_features, labels]] def evaluate_loss(net, data_iter, loss): 评估给定数据集上模型的损失 metric d2l.Accumulator(2) # 损失的总和,样本数量 for X, y in data_iter: out net(X) y y.reshape(out.shape) l loss(out, y) metric.add(l.sum(), l.numel()) return metric[0] / metric[1] def train(train_features, test_features, train_labels, test_labels, num_epochs400): loss nn.MSELoss(reductionmean) input_shape train_features.shape[-1] # 不设置偏置因为我们已经在多项式中实现了它 net nn.Sequential(nn.Linear(input_shape, 1, biasFalse)) batch_size min(10, train_labels.shape[0]) train_iter d2l.load_array((train_features, train_labels.reshape(-1,1)), batch_size) test_iter d2l.load_array((test_features, test_labels.reshape(-1,1)), batch_size, is_trainFalse) trainer torch.optim.SGD(net.parameters(), lr0.01) animator d2l.Animator(xlabelepoch, ylabelloss, yscalelog, xlim[1, num_epochs], ylim[1e-3, 1e2], legend[train, test]) for epoch in range(num_epochs): d2l.train_epoch_ch3(net, train_iter, loss, trainer) if epoch 0 or (epoch 1) % 20 0: animator.add(epoch 1, (evaluate_loss(net, train_iter, loss), evaluate_loss(net, test_iter, loss))) print(weight:, net[0].weight.data.numpy()) # 从多项式特征中选择前4个维度即1,x,x^2/2!,x^3/3! train(poly_features[:n_train, :4], poly_features[n_train:, :4], labels[:n_train], labels[n_train:])这段代码会生成训练损失与模型复杂度多项式的阶数的关系图。观察图可以帮助理解模型复杂度和训练损失之间的关系。在代码中通过标准化原始特征来处理多项式特征即将特征进行了缩放以便在训练过程中更好地优化模型。这样做有助于保持不同特征的相对重要性并提高模型的训练效果。如果不对多项式特征进行标准化可能会导致模型训练过程中的数值不稳定性。特征缩放有助于避免梯度爆炸或梯度消失等问题提高训练的稳定性和效果。除了标准化之外还可以考虑使用其他方法来处理多项式特征。例如采用正则化方法如L1正则化、L2正则化来控制模型的复杂度以避免过拟合。另外还可以尝试使用特征选择方法选择对模型性能影响较大的特征以减少特征的维度和模型的复杂度。综上所述标准化多项式特征是一种常用且有效的方法可以提高模型的训练效果和稳定性。4.泛化误差可能为零吗在实际情况下泛化误差几乎不可能为零。泛化误差是指模型在未见过的数据上的误差即在训练集之外的数据上的性能。即使模型在训练集上表现得非常好泛化误差仍然存在因为模型需要适应新的数据和不同的样本。泛化误差的存在是由于数据的噪声、样本的多样性、模型的假设等因素。即使使用了良好的模型选择和训练方法泛化误差也无法完全消除。一个模型的目标是尽可能减小泛化误差即在训练集和测试集上都能获得较低的误差。通过合适的模型选择、正则化技术、交叉验证等方法可以帮助减小模型的泛化误差并提高模型的性能。因此泛化误差几乎不可能为零但可以通过优化模型和数据处理的方法来尽可能地减小泛化误差以获得更好的模型性能。4. 研究体会通过这次实验我尝试使用不同的多层感知机模型架构如不同的隐藏层数和隐藏单元数等超参数组合来构建多个模型。通过在训练集上训练这些模型并在验证集上进行评估比较它们在给定问题上的性能。在实验中可以选择使用流行的深度学习框架如TensorFlow或PyTorch来实现和训练多层感知机模型。需要定义模型的结构包括输入层、多个隐藏层和输出层并选择适当的激活函数和损失函数。在模型训练过程中使用适当的优化算法如随机梯度下降和合适的学习率来更新模型参数。通过记录训练集和验证集上的性能指标比如准确率和损失函数值评估不同模型的性能。根据实验结果可以选择性能最好的模型并进一步进行优化以提高其性能。研究模型在训练数据上出现欠拟合或过拟合现象是为了了解模型的泛化能力和优化方法的效果。欠拟合指模型在训练数据上表现不佳而过拟合指模型过度拟合了训练数据导致在新数据上的性能下降。为了探究这些问题可以通过调整模型的复杂度来观察欠拟合和过拟合的现象。通过增加隐藏层数或隐藏单元数增加了模型的复杂度可能更好地拟合训练数据但也可能导致过拟合。相反减少隐藏层数或隐藏单元数模型的复杂度降低可能导致欠拟合。模型正则化是解决过拟合的常用方法之一。可以尝试引入正则化项如L1正则化或L2正则化来限制模型参数的大小防止过拟合。此外还可以使用Dropout技术在训练过程中随机地将一些隐藏单元设置为零以减少不同单元之间的依赖关系从而增加模型的泛化能力。另外调参也是改善模型泛化性能的重要步骤。在实验中我们可以尝试调整学习率、批量大小、优化算法等超参数以找到最佳的组合。使用网格搜索、随机搜索或贝叶斯优化等方法可以自动搜索超参数空间以寻找最佳的超参数配置。
返回列表