《动手学深度学习》 11.模型选择 + 过拟合和欠拟合

训练误差和泛化误差

  • 训练误差 : 训练数据上的误差 -> 模考
  • 泛化误差 : 新数据上的误差 -> 高考

其实 我们一般所说的的 test_data 只是通俗的叫法 , 其实是验证数据集

训练数据集 & 验证数据集 & 测试数据集:

  • 训练数据集 : 用来训练模型参数

  • 验证数据集 : 用来选 超参数

    ​ 用来评估模型好坏的数据集

    ​ 例如拿出50%的训练数据

    ​ 不要跟训练数据混在一起 (常犯错误)

  • 测试数据集 :只用一次的数据集。也就是作为最终的结果

    ​ 例如

    ​ 未来的考试 , 我出价的房子的实际成交价

    没有足够多数据使用 -> 用k则交叉验证

过拟合和欠拟合

《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第1张图片

模型容量 要与 数据规模 匹配

模型容量的影响:

  • 拟合各种函数的能力

  • 低容量的模型难以拟合训练数据

  • 高容量的模型可以记住所有的训练数据

​ 任务 : 降低 泛化误差
​ 机器学习的核心:在模型足够大的前提下 -> 通过某种手段 使泛化损失下降

数据复杂度

  • 样本个数
  • 每个样本的元素个数
  • 时间、空间结构
  • 多样性

代码 eg.

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)
""" np.power()用法详见笔记"""
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)

print(poly_features.shape)
  • true_w 前4项是参数 ,后面的16项作为噪音项

  • features 训练+测试数据集 (n,1) -> 这里的 features

  • np.power() 用法: 对features 每一行也就是每一个x 做 20 个方, 一行类似于 (0 ,x, x2,x3…x^19)

​ 参考:

  • poly_features 就是一个(200, 20) 的矩阵,200个样本,然后每一行是 阶数累加的x

  • 再除以gamma -> 目的防止 带来的特别大的指数值

  • 根据 poly_features 的值 人为造出一个 labels ,其中加上了一些噪音

def evaluate_loss(net,data_iter,loss):

参考softmax 这个函数是为了评估 一个epoch 的 loss

生成的三个图像:

train(poly_features[:n_train,:4],poly_features[n_train:,:4],
      labels[:n_train],labels[n_train:])

《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第2张图片

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

《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第3张图片

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

《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第4张图片

可以看到 用 poly_features 的前4列 当输入,无论是训练误差还是测试误差都很低
前2列当输入,测试误差训练误差都很高 -> 欠拟合
所有列当输入,测试误差会比训练误差高一点 -> 过拟合

练习:

[注] : module ‘d2l.torch’ has no attribute ‘train_epochs_ch3’
可能开发人员把 ch3 章节代码删了

解决办法:
import d2l
print(d2l._file_)
查出你的电脑里d2l的包的地址
然后进去 torch.py
把 之前 softmax的0开始实现里的 train_epoch_ch3 和 train_ch3 复制粘贴进去,然后就可以了

  1. 这个多项式回归问题可以准确地解出吗?提示:使用线性代数。

    答:不怎么会 ,线性代数可以解决 多维度问题么?

  2. 代码如下:

    • 随着feature_num的增加 loss的变化
    # 随着feature_num的增加 loss的变化
    def train1(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)
        for epoch in range(num_epochs):
            d2l.train_epoch_ch3(net, train_iter, loss, trainer)
            if epoch == 399:
                train_loss=evaluate_loss(net,train_iter,loss)
                test_loss = evaluate_loss(net,test_iter,loss)
                return train_loss,test_loss
                
    import matplotlib.pyplot as plt
    
    a = range(1,20)
    
    animator = d2l.Animator(xlabel='feature_nums', ylabel='loss', yscale='log',
                                xlim=[1, 20], ylim=[1e-3, 1e2],
                                legend=['train', 'test'])
    for i in a:
        c=0
        d=0
        c,d=train1(poly_features[:n_train,:i],poly_features[n_train:,:i],
             labels[:n_train],labels[n_train:])
        animator.add(i,(c,d))        
    

    结果:《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第5张图片

    结论 : 随着 feature_nums 的增加模型的 loss 趋于稳定,虽然没有最低点nums=4效果好

    ​ 但是 误差已经很小了,测试集和训练集相差结果也不是很大,过拟合可以接受

    • 随着训练数据量的增加 loss的变化:

      def train2(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)
          for epoch in range(num_epochs):
              d2l.train_epoch_ch3(net, train_iter, loss, trainer)
              if epoch == (num_epochs-1):
                  return evaluate_loss(net, train_iter, loss),evaluate_loss(net, test_iter, loss)
      
      
      
      
      b= range(1,n_train)
      
      anm = d2l.Animator(xlabel='data_nums',ylabel='loss',yscale='log',
                         xlim=[1,n_train],ylim=[1e-3, 1e2],
                        legend=['train','test'])
      for i in b:
          c=0
          d=0
          c,d = train2(poly_features[:i,:4],poly_features[n_train:,:4],
                       labels[:i],labels[n_train:])
          anm.add(i,(c,d))
      

      结果:《动手学深度学习》 11.模型选择 + 过拟合和欠拟合_第6张图片

      结论: 一开始明显过拟合 ,数据量太小 ,训练集误差小,测试集误差大

      ​ 随着训练数据量的增加,训练集和测试集的loss 差距逐渐减小

      ​ 80个epochs 后二者都趋于平稳

  3. 可能会发生上溢出 , 超过数据表示范围 ,而且数据太大也不利于计算

  4. 误差误差,泛化误差和训练误差都不可能为0(除非只有一个样本,训练误差为0)

总结

模型容量需要匹配数据复杂度, 否则可能导致欠拟合过拟合

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