• 12李沐动手学深度学习v2/数据复杂度与模型容量选择不当造成的 过拟合和欠拟合现象


    总结训练误差(训练损失)和泛化误差(验证损失)曲线:

    1. 恰当拟合:训练误差和泛化误差曲线,都很小和紧密贴合(gap小)
    2. 欠拟合:训练误差和泛化误差曲线,都很大
    3. 过拟合:训练误差和泛化误差曲线,训练误差一直减小,泛化误差是凹曲线。某个epoch之前贴合(gap小),之后分开(gap大)
    # 通过多样式拟合来观察过拟合和欠拟合现象
    import math
    import numpy as np
    import torch
    from torch import nn
    from d2l import torch as d2l
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用三阶多项式生成训练数据集的标签和测试数据集的标签
    y = 1.2 x − 3.4 x 2 2 ! + 5.6 x 3 3 ! + ϵ   , w h e r e   ϵ   ∼ N ( 0 , 0. 1 2 ) y=1.2x-3.4\frac{x^2}{2!}+5.6\frac{x^3}{3!}+\epsilon\ ,where\ \epsilon\ \sim N(0,0.1^2) y=1.2x3.42!x2+5.63!x3+ϵ ,where ϵ N(0,0.12)
    , ϵ \epsilon ϵ是噪音

    # 多项式的最大阶数
    max_degree = 20  
    # n_test是validation
    # 训练和测试数据集大小
    n_train, n_test = 100, 100  
    true_w = np.zeros(max_degree)  
    # 生成的数据集只有前面4列是有权重的正常的数据,后面1列的数据是噪音
    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 = np.dot(poly_features, true_w)
    labels += np.random.normal(scale=0.1, size=labels.shape)
     
    # 查看生成数据
    # numpy的ndarray转tensor
    true_w, features, poly_features, labels = [torch.tensor(x, dtype=d2l.float32) for x in [true_w, features, poly_features, labels]]
    features[:2], poly_features[:2, :], labels[:2]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    (tensor([[-0.7365],
             [ 0.5832]]),
     tensor([[ 1.0000e+00, -7.3652e-01,  2.7123e-01, -6.6588e-02,  1.2261e-02,
              -1.8061e-03,  2.2170e-04, -2.3327e-05,  2.1476e-06, -1.7575e-07,
               1.2944e-08, -8.6669e-10,  5.3194e-11, -3.0137e-12,  1.5855e-13,
              -7.7849e-15,  3.5836e-16, -1.5526e-17,  6.3527e-19, -2.4626e-20],
             [ 1.0000e+00,  5.8318e-01,  1.7005e-01,  3.3057e-02,  4.8196e-03,
               5.6214e-04,  5.4638e-05,  4.5520e-06,  3.3183e-07,  2.1502e-08,
               1.2540e-09,  6.6481e-11,  3.2309e-12,  1.4494e-13,  6.0375e-15,
               2.3473e-16,  8.5557e-18,  2.9350e-19,  9.5092e-21,  2.9187e-22]]),
     tensor([2.8299, 5.2456]))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    # 评估平均损失
    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]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    # 训练
    def train(train_features, test_features, train_labels, test_labels, num_epochs=800):
        # 损失函数
        loss = nn.MSELoss()
        # 模型
        input_shape = train_features.shape[-1]
        # 输出层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())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    展示预测函数的拟合情况

    恰当拟合

    多样式函数拟合

    ploy_features选择前4个特征数据,即 1 , x , x 2 2 ! , x 3 3 ! 1, x, \frac{x^2}{2!}, \frac{x^3}{3!} 1,x,2!x2,3!x3

    # train_features选择前面n_train行的数据,test_features选择第n_train行到最后的数据
    print(train(poly_features[:n_train,:4],poly_features[n_train:,:4],labels[:n_train],labels[n_train:]))
    
    • 1
    • 2
    weight: [[ 5.0088735  1.2420155 -3.4160125  5.509955 ]]
    None
    
    • 1
    • 2

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zrERHPfW-1662041429433)(output_8_1.svg)]

    欠拟合

    线性函数拟合

    ploy_features选择前2个特征数据,即 1 , x 1, x 1,x

    print(train(poly_features[:n_train,:2],poly_features[n_train:,:2],labels[:n_train],labels[n_train:]))
    
    • 1
    weight: [[3.2691808 4.0887265]]
    None
    
    • 1
    • 2

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W642CmoD-1662041429435)(output_10_1.svg)]

    过拟合

    多项式函数拟合

    ploy_features选择所有特征数据,即 1 , x , x 2 2 ! , x 3 3 ! , ϵ ( 噪音项 ) 1, x, \frac{x^2}{2!}, \frac{x^3}{3!},\epsilon(噪音项) 1,x,2!x2,3!x3ϵ(噪音项)

    print(train(poly_features[:n_train,:],poly_features[n_train:,:],labels[:n_train],labels[n_train:]))
    
    • 1
    weight: [[ 4.9652715   1.32939    -3.2067175   5.0756216  -0.6167561   1.0779084
      -0.19108813  0.21295705 -0.16514365  0.1888543  -0.10817137  0.11056256
       0.19794509  0.07623929  0.1727855   0.21495496 -0.03231318 -0.01818779
       0.00740698  0.01728407]]
    None
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nz5YmX4f-1662041429437)(output_12_1.svg)]
    todo(test loss并没有先降低再升高)

    query

    svm对比神经网络的缺点

    • 答:svm需要使用kernel,kernel算起来不容易,超过100万个样本点不要使用svm,svm能调整的参数不多
    • 答:神经网络的优点,神经网络本身是一种语言,可编程性好,可结合CNN

    模型剪枝和蒸馏(去粗取精distillation)的作用

    • 答:模型部署时的trick。提高性能

    训练集,验证集,测试集的划分标准

    • 答:训练:测试=7:3,训练集上做5折交叉验证。数据集大的情况下,训练:测试=5:5
    • 答:举例,imageNet,1000个类别,每个类别5000个样本,从每个类别中拿出50张图片样本作为测试集,共1000类别*50张图片样本/类=5万张图片做测试集样本

    数据具有时序序列,比如股票图片

    • 答:验证集一定要再训练集之后,不能使用k折交叉验证

    训练集合验证集需要一起进行“数据清洗(异常值处理)”和“特征构建(标准化(均值归一化))”吗?

    • 答:能拿到验证集可以考虑一起(鲁棒性更强)。最好当然分开

    数据集不够大的情况下才做k折交叉验证

    • 答:深度学习,训练集一般大,不用k折交叉验证。传统机器学习一般会使用k折交叉验证

    超参数的设计和选择

    • 答:如何选择,贝叶斯方法,网格(遍历),随机,为超参数的设计和选择设计1个模型
    • 答:靠经验

    数据集类型不平衡。例如,二分类问题A类样本1个,B类样本9个

    • 答:验证集的不同类别的样本数量做到相等,A类样本数:B类样本数=1:1,避免训练倾向没有通过验证集发现
    • 答:先明确是不是真实世界就是这样的类别分布,还是采样每采样好。如果是采样没有采样好,则采用1方,使用权重平衡A类样本和B类型样本(loss中小的类别给更大的权重;简单点就直接把少样本类别复制到数量跟多样本类型差不多) 2方,验证集1:1

    k折交叉验证的目的是确定超参数,然后

    • 答:1. 经过k折确定好模型(超参数)之后,再在整个数据集上训练1次。2. 确定好模型(超参数)之后,不再重新训练,直接取效果好(验证误差最小)的那1折的数据生成的模型。3. 把k折生成的k个模型,分别在测试集上跑一次得到预测结果,再将预测结果取均值

    SVM比MLP流行,CNN又比SVM流行

    随机森林在深度学习中的应用

    • 答:随机森林的训练无法使用梯度下降,应用少

    打比赛

    • 答:不同的随机值训练模型,将这些模型左average整合成1个模型,效果好

    k折交叉验证

    • 答:k确定之后,划分为k份之后,随机打乱1次之后,就不再打乱

    神经网络是一种语言

    • 答:通过神经网络来描述我对这个问题的理解

    同样的模型,同样的数据,随机初始化不同,将训练处理的模型集成效果会很好

    • 答:每个模型都有各自优劣,优势互补

    数据集中的噪音越少越好,清除噪音

  • 相关阅读:
    c++ 获取时间 微秒
    chrome v3开发插件实现所有网站允许跨域
    微信小程序 获取当前屏幕的可见高宽度
    MySQL高可用九种方案
    解决golang无法下载依赖的奇葩问题
    redis集群之主从复制集群的原理和部署
    请描述一下Spring MVC的工作流程。在Spring MVC中,DispatcherServlet的作用是什么?
    一个简单的Oracle Redaction实验
    TS封装小程序wx.showModal弹窗及调用
    Ubuntu上Qt安装和配置的完整步骤
  • 原文地址:https://blog.csdn.net/baidu_35805755/article/details/126652373