深度学习--------模型选择+过拟合和欠拟合

训练误差和泛化误差

训练误差:模型在训练数据上的误差
泛化误差:模型在新数据上的误差

例:根据模考成绩来预测未来考试分数
在过去的考试中表现很好(训练误差)不代表未来考试会好(泛化误差)。




验证数据集和测试数据集

验证数据集:一个用来评估模型好坏的数据集。
例:对数据集拿出50%的训练数据进行训练,另一半用来验证。

注意:不要跟训练数据混在一起(常犯错误)
测试数据集:只用一次的数据集。




K则交叉验证

在没有足够多数据时使用(这是常态)
算法:
     将训练数据分割成K块
     for i = 1,…,K
       使用第i块作为验证数据集,其余的作为训练数据集
     报告K个验证集误差的平均
常用:K=5或10

在这里插入图片描述

在这里插入图片描述

                                                                                       ……

在这里插入图片描述




总结

训练数据集:训练模型参数
验证数据集:选择模型超参数
非大数据集上通常使用k折交叉验证

过拟合和欠拟合

在这里插入图片描述
在这里插入图片描述

模型容量

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

在这里插入图片描述

模型容量的影响

在这里插入图片描述
通过观察可知,当模型过于简单就会导致训练误差大,当增加模型的复杂度就会使用训练误差减少,使用复杂的模型不管数据有多大,都可以记住,但是并不是记住所有的数据都是好的,数据里有大量噪音记住没什么用。所以也要注意泛化误差。




估计模型容量

难以在不同的种类算法之间比较
   例如:树模型和神经网络
给定一个模型种类,将有两个主要因素
   参数的个数
   参数值的选择范围

假设有d个数据,会有d+1个可以学习的,那个1是偏移,线性模型的参数个数是d+1。
d是特征向量的维度,1是偏置b的维度。
在这里插入图片描述
做了一个单层的隐藏层
假设:隐藏层是m的话,K是最后的分类的类别数。那么参数的个数为(d+1)m+(m+1)k

在这里插入图片描述




VC维

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

在这里插入图片描述

线性分类器的VC维

2维输入的感知机,VC维=3
   能够分类任何三个点

在这里插入图片描述
输入的特征是2,输出是1,VC维=3
第一个图是:三正
第二个图:两个正一个负
第三个图和第四个图:两个负一个正



但不能4个(即:不能做XOR)
在这里插入图片描述
支持N维输入的感知机的VC维是N+1
一些多层感知机的VC维O(N l o g 2 log_2 log2N)


VC维的好处

提供了一些理论的依据
    它可以衡量训练误差和泛化误差之间的间隔。
但深度学习中很少使用,因为:
    衡量不是很准确
    计算深度学习模型的VC维很困难


数据复杂度

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




总结

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




多项式回归

通过多项式拟合来交互地探索这些概念

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

生成数据集

给定x,我们将(使用三阶多项式来生成训练和测试数据的标签
在这里插入图片描述
噪声项 𝜖 服从均值为0且标准差为0.1的正态分布。 在优化的过程中,我们通常希望避免非常大的梯度值或损失值。 这就是我们将特征从 x i x^i xi调整为 x i x^i xi/i!的原因, 这样可以避免很大的 𝑖 带来的特别大的指数值。 我们将为训练集和测试集各生成100个样本。

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])  # 第4项之后的系数均为0
# n_train + n_test为数据集,1为特征
features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)  # 随机排序features
poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
# 使用 np.power() 函数将 features 数组中的元素分别取不同幂次(从 0 到 max_degree-1)
# 形状为(n_train + n_test,max_degree)
# 结果保存在 poly_features 数组中,每行为某一feature的不同幂次结果
for i in range(max_degree):
    # poly_features中的单项式由gamma函数重新缩放gamma(n)=(n-1)!
    poly_features[:, i] /= math.gamma(i + 1)
    # 按列对poly_features中相同幂次的元素除以相应的阶乘
# 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
# 遍历列表中的每个元素x,对每个元素执行转换数据类型,生成了一个新的列表张量
true_w, features, poly_features, labels = [torch.tensor(x, dtype=torch.float32) for x in [true_w, features, poly_features, labels]]
# features的shape为[n_train + n_test, 1]
# poly_features的shape为[n_train + n_test,max_degree]
# lables的shape为[1, n_train+n_test]
print(features[:2])
print(poly_features[:2, :])
print(labels[:2])

在这里插入图片描述


对模型进行训练和测试

实现一个函数在评估模型在给定数据集上的损失。

def evaluate_loss(net, data_iter, loss):  #@save
    """评估给定数据集上模型的损失"""
    metric = d2l.Accumulator(2)  
    # 通过遍历数据迭代器每次迭代都会获得一批数据X和对应标签y
    for X, y in data_iter:
    	# 将当前批次的数据x送入神经网络net进行前向传播
        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):
    # 均方误差损失,reduction='none'直接返回每个元素的损失
    loss = nn.MSELoss(reduction='none')
    input_shape = train_features.shape[-1] # 得到特征数量
    # 不设置偏置,因为我们已经在多项式中实现了它
    # 第一个参数是输入特征的数量,第二个参数是输出特征的数量
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    # 第二个参数是训练标签的第一个维度大小,用来获得训练数据集中样本的总数
    # 确保batch_size既不会太大,也不会超出训练集的范围
    batch_size = min(10, train_labels.shape[0]) # 防止最后剩下的size不足10
    # 将训练特征和训练标签打包成一个元组
    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)
        # 记录初始损失值,此后每隔20个epochs记录一次损失值
        if epoch == 0 or (epoch + 1) % 20 == 0:
            # 将记录的轮数和训练损失以及测试损失添加到animator
            animator.add(epoch + 1, (evaluate_loss(net, train_iter, loss),
                                     evaluate_loss(net, test_iter, loss)))
    # 打印第一层的权重值
    print('weight:', net[0].weight.data.numpy())



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

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

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:])

输出:
在这里插入图片描述
发现:与真实值**w=[5,1.2]**相差较大。

在这里插入图片描述
结论:训练误差和验证误差都很大,需要用更复杂的模型减少训练误差。



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

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

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

输出:

在这里插入图片描述
在这里插入图片描述
结论:复杂模型对数据造成了过拟合。




问题

①SVM从理论上讲应该对于分类分体效果不错,和神经网络相比,缺点在哪里?
SVM的缺点:大数据集用SVM算起来特别慢,且能调的东西不多(即可调性低)。
神经网络的优点:它是一个语言。具有强大的学习能力、泛化能力、灵活性、处理复杂模式的能力、分布式表示、自适应和容错性以及并行处理能力。

②验证数据集和训练数据清洗(如异常值处理)和特征构建(如标准化)是否需要放在一起处理?
假设做标准化:把这一数据减去它的均值除以它的方差,就是说均值和方差怎么算?
有两种做法
第一种做法:把测试集和训练集所有的集拿过来,算均值和方差。(这个好一点,分布的变化会更加鲁棒)
第二种做法:只在训练集上算均值和方差,然后把均值和方差作用到验证数据集上去。(这个保险点)

③深度学习一般训练集合比较大,所以K则交叉验证在深度学习中是不是没有什么应用?
是的,训练成本太高。

④为什么cross validation(交叉验证)好呢?它并没有解决数据来源的问题。
cross validation只是用来选择超参数的,不能解决其他的。

⑤模型参数和超参数不一样吗?
不一样,模型的参数是指w,b那些元素的值,是我们要估计的,是在训练过程中自动学习的。
超参数是模型外部的参数,需要在训练之前手动设置,用于控制模型的学习能力和复杂度。

⑥K折交叉验证的目的是确定超参数吗?然后还要用这个超参数再训练一遍全数据吗?
是的

⑦为什么SVM一开始打败了多层感知机,后来深度学习CNN(卷积神经网络)又打败了SVM。
一:SVM比较简单,SVM的精度并没有比多层感知机要好,但它不那么要调参。
二:SVM有数学理论。
深度学习CNN没有理论,但实际效果很好。

⑧所有的验证集上loss曲线都是先下降后上升的吗?为什么网上大部分的图都是一直下降的?
在这里插入图片描述
网上的:
在这里插入图片描述
在这幅图中只是其中的一个点。
在这里插入图片描述

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值