模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记

训练误差和泛化误差

  1. 训练误差(training error):模型在训练数据集上计算得到的误差
  2. 泛化误差(generalization error):模型应用在同样从原始样本的分布中抽取的无限多数据样本时,模型误差的期望

验证数据集和测试数据集

  1. 验证数据集:选择模型超参数,一个用来评估模型好坏的数据集
    1. 例如拿出50%的训练数据
    2. 不要跟训练数据混在一起(常犯错误)
  2. 测试数据集:只用一次的数据集。
  3. 训练数据集:训练模型参数

K折交叉验证

在没有足够多数据时使用(非大数据集上通常使用)(这是常态)

算法:

  1. 将训练数据分割成K块
  2. For  i = 1,...,K
    1. 使用第i块作为验证数据集,其余的作为训练数据集
  3. 报告K个验证集误差的平均

常用:K=5 或 10
这里,原始训练数据被分成K个不重叠的子集。 然后执行K次模型训练和验证,每次在K−1个子集上进行训练,并在剩余的一个子集(在该轮中没有用于训练的子集)上进行验证。 最后,通过对K次实验的结果取平均来估计训练和验证误差。 

过拟合和欠拟合

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第1张图片

模型容量

  1. 拟合各种函数的能力
  2. 低容量的模型难以拟合训练数据
  3. 高容量的模型可以记住所有的训练数据

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第2张图片

模型容量的影响

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第3张图片

估计模型容量

  1. 难以在不同的种类算法之间比较

    1. 例如树模型和神经网络

  2. 给定一个模型种类,将有两个主要因素

    1. 参数的个数

    2. 参数值的选择范围

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第4张图片

VC维

  1. 统计学习理论的一个核心思想
  2. 对于一个分类模型,VC等于一个最大的数据集的大小,不管如何给定标号,都存在一个模型来对它进行完美分类

线性分类器的VC维

  1. 2维输入的感知机,VC维=3
    1. 能够分类任何三个点,但不是4个(xor)
  2. 支持N维输入的感知机的VC维是N+1
  3. 一些多层感知机的VC维O(N logN)

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第5张图片

VC 维的用处

  1. 提供为什么一个模型好的理论依据
    1. 它可以衡量训练误差和泛化误差之间的间隔
  2. 但深度学习中很少使用
    1. 衡量不是很准确
    2. 计算深度学习模型的VC维很困难

 数据复杂度

  1. 多个重要因素
    1. 样本个数
    2. 每个样本的元素个数
    3. 时间、空间结构
    4. 多样性

总结

  1. 模型容量需要匹配数据复杂度,否则可能导致欠拟合和过拟合
  2. 统计机器学习提供数学工具来衡量模型复杂度
  3. 实际中一般靠观察训练误差和验证误差

代码实现:

使用以下三阶多项式来生成训练和测试数据的标签:

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)) #numpy.random.normal(loc=0,scale=1e-2,size=shape) ,loc(float):正态分布的均值,scale(float):正态分布的标准差,参数size(int 或者整数元组):输出的值赋在shape里,默认为None。
np.random.shuffle(features) # 对数组进行重新排列
poly_features = np.power(features, np.arange(max_degree).reshape(1, -1)) # power(x, y) 函数,计算x的y次方
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)

#从生成的数据集中查看一下前2个样本, 第一个值是与偏置相对应的常量特征
# 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): 
    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())
# 三阶多项式函数拟合(正常)
# 从多项式特征中选择前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:])
# 结果表明,该模型能有效降低训练损失和测试损失。 学习到的模型参数也接近真实值。

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第6张图片

#  线性函数拟合(欠拟合)
# 从多项式特征中选择前2个维度,即1和x
train(poly_features[:n_train, :2], poly_features[n_train:, :2], labels[:n_train], labels[n_train:])
# 线性函数拟合,减少该模型的训练损失相对困难。 在最后一个迭代周期完成后,训练损失仍然很高。

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第7张图片

# 高阶多项式函数拟合(过拟合)
# 从多项式特征中选取所有维度
train(poly_features[:n_train, :], poly_features[n_train:, :], labels[:n_train], labels[n_train:], num_epochs=2000)
# 没有足够的数据用于学到高阶系数应该具有接近于零的值。 因此,这个过于复杂的模型会轻易受到训练数据中噪声的影响。 虽然训练损失可以有效地降低,但测试损失仍然很高。 结果表明,复杂模型对数据造成了过拟合。

模型选择 + 过拟合和欠拟合(动手学深度学习v2)笔记_第8张图片

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