动手学习深度学习(总结梳理)——4.模型选择,过拟合,欠拟合

目录

1. 从训练误差和泛化误差 ——》 模型复杂度 ——》过拟合与欠拟合 ——》模型复杂性 ——》 引入验证集 ——》K折交叉验证 ——》数据大小和模型容量 的理论 (来自李沐老师的官网)

2. 多项式回归

2.1 生成数据集

​编辑

2.2 对模型进行训练和测试

2.3 三阶多项式函数拟合(正常)

2.4 线性函数拟合(欠拟合)

 2.5 高阶多项式函数拟合(过拟合)



过拟合和欠拟合 数据
简单 复杂
模型容量 正常 欠拟合
过拟合 正常

2. 多项式回归

我们现在可以通过多项式拟合来探索这些概念

import math
import numpy as np
import torch
from torch import nn
from d2l import torch as d2l

2.1 生成数据集

动手学习深度学习(总结梳理)——4.模型选择,过拟合,欠拟合_第1张图片

这里使用np.power生成带有阶数的数据,本来features是一个size * 1的张量,借助power函数和np.arrange(max_degree).reshape(1,-1),使其变成一个size * 20的向量,每个向量对相应位置的索引取得阶乘。从而实现X @ W = Y ,即size * 1的向量。 

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)

 将他们转化为tensor张量,以便可以在pytorch中进行梯度运算。

# 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]

2.2 对模型进行训练和测试

首先让我们实现一个函数来评估模型在给定数据集上的损失,其中Accumulator类是我们之前在softmax章节封装过的一个累加器类

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_epochs=400):
    loss = nn.MSELoss(reduction='none')
    input_shape = train_features.shape[-1]
    ''' 不设置偏置,因为我们已经在多项式中实现了它 '''
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    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_train=False)
    trainer = torch.optim.SGD(net.parameters(), lr=0.01)
    animator = d2l.Animator(xlabel='epoch', ylabel='loss', yscale='log',
                            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())

2.3 三阶多项式函数拟合(正常)

我们将首先使用三阶多项式函数,它与数据生成函数的阶数相同。 结果表明,该模型能有效降低训练损失和测试损失。 学习到的模型参数也接近真实值 w = [5, 1.2, -3.4, 5.6]

# 从多项式特征中选择前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:])

动手学习深度学习(总结梳理)——4.模型选择,过拟合,欠拟合_第2张图片

2.4 线性函数拟合(欠拟合)

让我们再看看线性函数拟合,减少该模型的训练损失相对困难。 在最后一个迭代周期完成后,训练损失仍然很高。 当用来拟合非线性模式(如这里的三阶多项式函数)时,线性模型容易欠拟合。

# 从多项式特征中选择前2个维度,即1和x
train(poly_features[:n_train, :2], poly_features[n_train:, :2],
      labels[:n_train], labels[n_train:])

动手学习深度学习(总结梳理)——4.模型选择,过拟合,欠拟合_第3张图片

 2.5 高阶多项式函数拟合(过拟合)

让我们尝试使用一个阶数过高的多项式来训练模型。 在这种情况下,没有足够的数据用于学到高阶系数应该具有接近于零的值。 因此,这个过于复杂的模型会轻易受到训练数据中噪声的影响。 虽然训练损失可以有效地降低,但测试损失仍然很高。 结果表明,复杂模型对数据造成了过拟合。

# 从多项式特征中选取所有维度
train(poly_features[:n_train, :], poly_features[n_train:, :],
      labels[:n_train], labels[n_train:], num_epochs=1500)

 动手学习深度学习(总结梳理)——4.模型选择,过拟合,欠拟合_第4张图片

 

你可能感兴趣的:(深度学习,学习,人工智能)