多层感知机MLP-part2-拟合问题

摘要:本文探讨了深度学习中的模型选择与过拟合问题。在模型评价方面,指出泛化能力是核心指标,受参数量、参数取值和训练样本数量影响。重点分析了欠拟合和过拟合现象,其中过拟合表现为训练误差小而测试误差大。为应对过拟合,介绍了正则化技术,特别是L2正则化(权重衰减),通过向损失函数添加惩罚项来提升泛化性能。文章通过PyTorch实现展示了权重衰减的效果:未正则化时模型明显过拟合,而加入L2正则化后测试误差显著降低。最后强调正则化是平衡模型复杂度、防止过拟合的有效方法。

1.模型选择(model selection)

1.1模型的评价      

        多层感知机即深度神经网络的训练过程就是用模型拟合训练集数据的过程。使用不同的隐藏层数和隐藏单元数的模型都可以达到满足拟合要求的程度,即训练误差(training error)满足要求。但不同模型在测试集的表现却不一定优秀,即模型的泛化能力不同,即泛化误差(generalization error)不同。

        在训练模型的过程中,影响模型泛化能力的因素主要有三点:

        (1)可调整参数的数量。参数量较多时,模型容易过拟合;

        (2)参数的取值。参数的权值取值范围较大时,模型可能过拟合;

        (3)训练样本的数量。样本越少,过拟合越容易。

        因此,评价选择的模型就是看模型的泛化能力。

1.2拟合问题

        欠拟合是值模型通过训练无法达到训练误差的要求,通常表明选择的模型过于简单,无法满足拟合要求。通常表现是模型训练中继续迭代训练误差无法继续减小。欠拟合的原因是模型过于简单或者训练不足导致。

        过拟合是指在训练集中表现优秀但测试集中表现较差的情况,即训练误差远小于验证误差。这种情况下训练已经无法提高模型质量了。

        由于不能基于训练误差来估计泛化误差,因此简单地最小化训练误差并不一定意味着泛化误差的减小。机器学习模型需要防止过拟合,即防止泛化误差过大。

        为了防止过拟合,研究者们想出了很多方法。

1.3防止过拟合

        正则化技术就是防止模型过拟合的方法。正则化方法即为在此时向原始模型引入额外信息,以便防止过拟合和提高模型泛化性能的一类方法的统称。在实际的深度学习场景中我们几乎总是会发现,最好的拟合模型(从最小化泛化误差的意义上)是一个适当正则化的大型模型。权重衰减是最广泛的正则化技术之一,也被成为L2正则化。

        范数L1,L2和Lp的表达式如下,L1和L2是Lp范数的特里。

||x||_{1}= \sum_{i=1}^{n}\left | x_{i} \right |         ||x||_{2}=\sqrt{\sum_{i=1}^{n}x_{i}^{2}}           ||x||_{p}=\left ( \sum_{i=1}^{n}\left | x_{i} \right |^{p} \right )^{1/p}

        使用了权重衰减后,将原来的训练目标进行了调整,是将范数当作惩罚项添加到了最小化损失中:

训练目标:最小化训练标签上的预测损失->最小化预测损失和惩罚项之和

2权重衰减的实现

2.1 从零实现

2.1.1模型建立

%matplotlib inline
import math
import numpy as np
import torch
from torch import nn
from d2l import torch as d2l

#生成数据
n_train,n_test,num_inputs,batch_size=20,100,200,5
true_w,true_b=torch.ones((num_inputs,1))*0.01,0.05
train_data=d2l.synthetic_data(true_w,true_b,n_train)
train_iter=d2l.load_array(train_data,batch_size)
test_data=d2l.synthetic_data(true_w,true_b,n_test)
test_iter=d2l.load_array(test_data,batch_size,is_train=False)

2.1.2初始化模型参数

#初始化函数
def init_params():
    w=torch.normal(0,1,size=(num_inputs,1),requires_grad=True)
    b=torch.zeros(1,requires_grad=True)
    return [w,b]

2.1.3定义L2范数惩罚

#L2范数惩罚
def l2_penalty(w):
    return torch.sum(w.pow(2))/2

2.1.4训练定义

#训练代码
def train(lambd):
    w,b=init_params()
    net,loss=lambda X:d2l.linreg(X,w,b),d2l.squared_loss
    num_epochs,lr=100,0.003
    animator=d2l.Animator(xlabel='epochs',ylabel='loss',yscale='log',xlim=[5,num_epochs],legend=['train','test'])
    for epoch in range(num_epochs):
        for X, y in train_iter:
            #增加了L2范数惩罚项
            #广播机制使l2_penalty(w)成为一个长度为batch_size的向量
            l=loss(net(X),y)+lambd*l2_penalty(w)
            l.sum().backward()
            d2l.sgd([w,b],lr,batch_size)
        if(epoch+1)%5==0:
            animator.add(epoch+1,(d2l.evaluate_loss(net,train_iter,loss),d2l.evaluate_loss(net,test_iter,loss)))
    print('w的L2范数是:',torch.norm(w).item())

2.1.5训练

        忽略正则化训练

#忽略正则化直接训练
train(lambd=0)

        注意,训练误差减小但测试误差没有减小,意味着出现了严重的过拟合。

        使用权重衰减

#使用权重衰减
train(lambd=3)

        注意,训练误差在减小后有轻微反弹,但测试误差减小,符合我们期望从正则化中得到的效果。

2.2函数实现

        将权重衰减用函数实现:

def train_concise(wd):
    net=nn.Sequential(nn.Linear(num_inputs,1))
    for param in net.parameters():
        param.data.normal_()
    loss=nn.MSELoss(reduction='none')
    num_epochs,lr=100,0.003
    #偏置参数没有衰减
    trainer=torch.optim.SGD([{"params":net[0].weight,'weight_decay':wd},{"params":net[0].bias}],lr=lr)
    animator=d2l.Animator(xlabel='epochs',ylabel='loss',yscale='log',xlim=[5,num_epochs],legend=['train','test'])
    for epoch in range(num_epochs):
        for X, y in train_iter:
            trainer.zero_grad()
            l=loss(net(X),y)
            l.mean().backward()
            trainer.step()
        if(epoch+1)%5==0:
            animator.add(epoch+1,(d2l.evaluate_loss(net,train_iter,loss),d2l.evaluate_loss(net,test_iter,loss)))
    print('w的L2范数是:',net[0].weight.norm().item())
#无正则化
train_concise(0)

#权重衰减
train_concise(3)

        正则化是处理过拟合的常用方法:在训练集中的损失函数中加入惩罚项,以降低已学习的模型的复杂度。

### MLP(多层感知器)工作原理 #### 输入层到隐藏层的数据传递 MLP是一种特殊类型的前馈神经网络,其中除了输入和输出层外还存在一个或多个隐藏层[^1]。每一层中的节点通过权重连接至下一层的所有节点,形成全连接结构。 #### 权重更新机制 当给定一组训练样本时,MLP会调整各层间连接的权值来最小化预测误差。这一过程通常采用反向传播算法实现,在每次迭代过程中计算损失函数关于各个参数的梯度并据此修改模型参数。 #### 非线性激活函数的应用 为了使网络能够拟合复杂的非线性关系,每两个相邻层次间的转换不仅限于简单的加权求和操作;而是加入了非线性的激活函数f(x),常见的有Sigmoid, ReLU等。这使得即使在网络较深的情况下也能保持良好的表达能力。 #### 输出层处理 最终经过一系列变换后的特征表示被送入输出层完成具体的任务目标——比如分类或者回归分析。对于二分类问题可以使用sigmoid作为最后一层激活函数得到概率估计;而对于多类别情况则常选用softmax函数将得分转化为各自类别的可能性分布。 ```python import numpy as np def sigmoid(z): return 1 / (1 + np.exp(-z)) def relu(z): return max(0,z) # Example of forward propagation with one hidden layer using ReLU activation function X = ... # input data matrix shape=(n_samples,n_features) W1,b1,W2,b2 = initialize_parameters() # Initialize weights and biases randomly or via some initialization scheme Z1 = X @ W1 + b1 # Linear combination at first hidden layer A1 = relu(Z1) # Apply non-linear transformation through ReLU Z2 = A1 @ W2 + b2 # Compute linear part before output layer output_probabilities = softmax(Z2) # Convert scores into probabilities for classification task. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三之又三

金钱出真知

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值