程序员的资源宝库

网站首页 > gitee 正文

3.11模型选择、欠拟合和过拟合 欠拟合与过拟合的例子

sanyeah 2024-03-29 18:01:18 gitee 7 ℃ 0 评论

3.11模型选择、欠拟合和过拟合

Dive Into Deep Learning

训练误差和泛化误差

训练误差(train-error):
模型在训练数据集上表现出的误差
泛化误差(generalization error):
模型在任意一个测试数据样本上表现出的误差的期望,并常常通过测试数据集上的误差来近似
机器学习模型应关注降低泛化误差。

验证数据集

验证数据集(validation data set):预留一部分在训练数据集和测试数据集以外的数据来进行模型选择。
我们可以从给定的训练集中随机选取一小部分作为验证集,而将剩余部分作为真正的训练集。

\(k\)折交叉验证(\(k\) -fold cross-validation)

\(1\) 个数据集验证,\(k-1\)个数据集训练
\(k\) 个数据集不相交

过拟合和欠拟合

过拟合:模型的训练误差远小于它在测试数据集上的误差(测试误差较大)
欠拟合:一类是模型无法得到较低的训练误差(训练误差较大)

模型复杂度

给定一个由标量数据特征\(x\)和对应的标量标签\(y\)组成的训练数据集,多项式函数拟合的目标是找一个\(K\)阶多项式函数

\[\hat{y} = b + \sum_{k=1}^K x^k w_k \]

来近似\(y\)

训练数据集大小

训练数据集 \(\downarrow\) \(\rightarrow\) 过拟合 \(\uparrow\)
泛化误差不会随训练数据集里样本数量增加而增大

多项式函数拟合实验

  • 导入包,模块
%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, gluon, nd
from mxnet.gluon import data as gdata, loss as gloss, nn
  • 生成数据集:
    给定样本特征\(x\),用如下的三阶多项式函数来生成该样本的标签:

\[y = 1.2x - 3.4x^2 + 5.6x^3 + 5 + \epsilon, \]

其中噪声项\(\epsilon\)服从均值为 \(0\)、标准差为\(0.1\)的正态分布。训练数据集和测试数据集的样本数都设为\(100\)

#训练数据集样本数是100,测试数据集样本数是100,权重是三个数字,也就是上面的函数的系数[1.2,-3.4,5.6],偏置是b = 5
n_train, n_test, true_w, true_b = 100, 100, [1.2, -3.4, 5.6], 5
#初始化样本特征值,shape 是 [200,1],也就是200 * 1的矩阵,随机值是它的每个元素都随机采样于均值为0、标准差为1的正态分布。 
features = nd.random.normal(shape=(n_train + n_test, 1))
#这里是nd.concat矩阵合并调用,nd.concat(.....dim = ?),这里的dim表示的是维数,是行方向合并还是列方向合并,默认是行方向合并,所以这里就是把x,x^2,x^3都计算出合并成一个矩阵
poly_features = nd.concat(features, nd.power(features, 2),nd.power(features, 3))
#根据上面的函数,算出x对应的y
labels = (true_w[0] * poly_features[:, 0] + true_w[1] * poly_features[:, 1]
          + true_w[2] * poly_features[:, 2] + true_b)
#加上\epslion的噪声项
labels += nd.random.normal(scale=0.1, shape=labels.shape)
  • 定义、训练和测试模型
  • 先定义作图函数semilogy,已保存在d2lzh包中
# 本函数已保存在d2lzh包中方便以后使用
def semilogy(x_vals, y_vals, x_label, y_label, x2_vals=None, y2_vals=None,
             legend=None, figsize=(3.5, 2.5)):
    d2l.set_figsize(figsize)
    d2l.plt.xlabel(x_label)
    d2l.plt.ylabel(y_label)
    d2l.plt.semilogy(x_vals, y_vals)
    if x2_vals and y2_vals:
        d2l.plt.semilogy(x2_vals, y2_vals, linestyle=':')
        d2l.plt.legend(legend)

多项式函数拟合也使用平方损失函数

  • 模型定义:
#定义 num_epochs表示迭代次数100,loss = gloss.L2Loss(),调用gluon自带的方法,使用平方损失(mean squared error)
num_epochs, loss = 100, gloss.L2Loss()

gloss
\(L = \frac{1}{2} \sum_{i} \vert {label}_i - {pred}_i \vert^2.\)

参数
Parameters
权重(float or None):全局标量权重损失大小默认1.0
weight (float or None) – Global scalar weight for loss.
batch_axis(int,default 0):表示mini-batch的轴
batch_axis (int, default 0) – The axis that represents mini-batch.
输入
Inputs:
预测标签:任意维度预测张量
pred: prediction tensor with arbitrary shape
目标标签:与预测张量相同的大小的目标张量
label: target tensor with the same size as pred.
权重:元素级权重张量。要求和预测张量维度相同
sample_weight: element-wise weighting tensor. Must be broadcastable to the same shape as pred. For example, if pred has shape (64, 10) and you want to weigh each sample in the batch separately, sample_weight should have shape (64, 1).
输出
Outputs:
损失:损失张量的大小是(批量大小,),这里的batch_size是选择预测集中的数据大小。
loss: loss tensor with shape (batch_size,).
维度大于batch_axis(参数,默认是0)会被平均计算。
Dimenions other than batch_axis are averaged out.
def fit_and_plot(train_features, test_features, train_labels, test_labels):
    #Stacks Blocks sequentially.顺序的堆叠块,定义一个Sequential实例,在Gluon中,Sequential实例可以看作是一个串联各个层的容器。
    net = nn.Sequential()
    #在容器中加入输出全连接层,该层输出个数是1
    net.add(nn.Dense(1))
    #默认初始化模型参数如权重,偏差
    net.initialize()
    #批次大小是10
    batch_size = min(10, train_labels.shape[0])
class mxnet.gluon.data.DataLoader(dataset, batch_size=None, shuffle=False, sampler=None, last_batch=None, batch_sampler=None, batchify_fn=None, num_workers=0, pin_memory=False, pin_device_id=0, prefetch=None, thread_pool=False, timeout=120)  
数据集:数据集
dataset : Dataset
        元数据集。numpy和mxnet数组可以直接使用
        Source dataset. Note that numpy and mxnet arrays can be directly used
        as a Dataset.
batch_size : int
        小批量数据集大小
        Size of mini-batch.
shuffle : bool
        是否打乱数据
        Whether to shuffle the samples.
从数据集中加载数据同时返回最小批次的数据,
Loads data from a dataset and returns mini-batches of data.
mxnet.gluon.data.ArrayDataset(*args)
组合了其他数据集的一个整的数据集
A dataset that combines multiple dataset-like objects, e.g. Datasets, lists, arrays, etc.

The i-th sample is defined as (x1[i], x2[i], …).
train_iter = gdata.DataLoader(gdata.ArrayDataset(
        train_features, train_labels), batch_size, shuffle=True)

DataLoader

class mxnet.gluon.Trainer(params, optimizer, optimizer_params=None, kvstore='device', compression_params=None, update_on_kvstore=None)
在参数集上应用一个优化器,训练器需要和autograd一起使用
Applies an Optimizer on a set of Parameters. Trainer should be used together with autograd.
需要去最优化的参数集
params (ParameterDict) – The set of parameters to optimize.
使用的优化器
optimizer (str or Optimizer) – The optimizer to use. See help on Optimizer for a list of available optimizers.
当前优化器的学习速率
learning_rate (float) – The current learning rate of the optimizer. Given an Optimizer object optimizer, its learning rate can be accessed as optimizer.learning_rate.
trainer = gluon.Trainer(net.collect_params(), 'sgd',
                            {'learning_rate': 0.01})
    #在训练集上的损失率和在测试集上的损失率    
    train_ls, test_ls = [], []
    #开始迭代100次
    for _ in range(num_epochs):
        #取出训练的特征X和标签y
        for X, y in train_iter:
            #Returns an autograd recording scope context to be used in ‘with’ statement and captures code that needs gradients to be calculated.
            #默认条件下MXNet不会记录用于求梯度的计算。我们需要调用record函数来要求MXNet记录与求梯度有关的计算。
            with autograd.record():
            #得到损失
                l = loss(net(X), y)
            #对l求梯度
            l.backward()
            #使用小批量随机梯度下降迭代模型参数
            #迭代计算
            trainer.step(batch_size)
            #计算在训练集上的损失
        train_ls.append(loss(net(train_features),
                             train_labels).mean().asscalar())
            #计算在测试集上的损失
        test_ls.append(loss(net(test_features),
                            test_labels).mean().asscalar())
    print('final epoch: train loss', train_ls[-1], 'test loss', test_ls[-1])
    semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
             range(1, num_epochs + 1), test_ls, ['train', 'test'])
    print('weight:', net[0].weight.data().asnumpy(),
          '\nbias:', net[0].bias.data().asnumpy())
#调用函数
fit_and_plot(poly_features[:n_train, :], poly_features[n_train:, :],
             labels[:n_train], labels[n_train:])

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

得到结果

线性函数拟合(欠拟合)

线性模型在非线性模型(如三阶多项式函数)生成的数据集上容易欠拟合。

#features.shape = (200,1),这里是用features作为训练特征,也就是将线性模型应用在非线性生成的数据集上。
fit_and_plot(features[:n_train, :], features[n_train:, :], labels[:n_train],
             labels[n_train:])

训练样本不足(过拟合)

如果训练样本不足,该模型依然容易过拟合。

#只使用三阶函数模型的前两个数据,训练样本显然不足。
fit_and_plot(poly_features[0:2, :], poly_features[n_train:, :], labels[0:2],
             labels[n_train:])

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表