问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

欠拟合、过拟合概念以及示例

创作时间:
作者:
@小白创作中心

欠拟合、过拟合概念以及示例

引用
CSDN
1.
https://blog.csdn.net/weixin_61904259/article/details/139751172

欠拟合和过拟合是机器学习中常见的两个问题。欠拟合是指模型无法很好地拟合训练数据,而过拟合则是指模型在训练数据上表现很好,但在新数据上泛化能力较差。本文通过一个具体的代码示例,使用线性回归模型、简单MLP和复杂MLP来展示欠拟合、正常拟合和过拟合的情况。

过拟合欠拟合的直观展示

欠拟合(Underfitting):

第一个模型LinearRegression是一个线性回归模型,它只有一层线性变换,没有非线性激活函数。因此,这个模型只能学习线性关系,而无法捕捉到数据中的非线性模式。

对于一个非线性问题(如你的例子中y = x^2 + 1加上噪声),线性模型显然是不够复杂的,它无法很好地拟合这种非线性关系。因此,这个模型会表现出欠拟合,即模型在训练数据上的性能也不佳,因为它没有足够的能力去学习数据的底层结构。

正常拟合(Good Fit):

第二个模型MLP是一个多层感知机,具有一个隐藏层,该隐藏层有8个神经元,并使用了ReLU激活函数。

这个模型有足够的复杂度去学习数据中的非线性模式,同时又不是过于复杂,因此可以在训练数据上达到良好的性能,并且有较好的泛化能力到未见过的数据。

过拟合(Overfitting):

第三个模型MLPOverfitting是一个更复杂的多层感知机,具有两个隐藏层,每层都有256个神经元。

这个模型非常复杂,具有大量的参数。虽然它可能在训练数据上表现得非常好,甚至能够几乎完美地拟合训练数据,但这种高度的复杂性可能导致模型在未见过的数据上泛化能力下降。

过拟合发生时,模型会学习到训练数据中的噪声和细节,而不是数据的底层结构或规律。因此,当面对新的、未见过的数据时,模型可能无法做出准确的预测。

总的来说,模型的复杂度需要与问题的复杂度相匹配。如果模型太简单(如线性模型用于非线性问题),则会发生欠拟合;如果模型太复杂(如具有大量参数的深层网络用于相对简单的问题),则可能会发生过拟合。

import numpy as np
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader,TensorDataset
from sklearn.model_selection import train_test_split
np.random.seed(32) #设置随机种子 保证每次结果可以复现
#生成满足 y = x^2 + 1 的数据
num_samples = 100 #生成100个样本点
X = np.random.uniform(-5,5,(num_samples,1)) #均匀分布
Y=X**2 + 1 +5 *np.random.normal(0,1,(num_samples,1)) #正态分布噪声
#将NumPy 变量转化为浮点型 Pytorch 变量
X = torch.from_numpy(X).float()
Y = torch.from_numpy(Y).float()
#绘制数据散点图
plt.scatter(X,Y)
plt.show()
#将数据划分为训练集和测试集
train_X,test_X,train_Y,test_Y=train_test_split(X,Y,test_size=0.3,random_state=0)
#将数据封装成数据加载器
train_dataloader = DataLoader(TensorDataset(train_X,train_Y),batch_size=32,shuffle=True)
test_dataloader = DataLoader(TensorDataset(test_X,test_Y),batch_size=32,shuffle=False)
#定义线性回归模型(欠拟合)
class LinearRegression(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(1,1)
        
    def forward(self,x):
        return self.linear(x)
#定义多层感知机(正常)
class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(1,8)
        self.output = nn.Linear(8,1)
    
    def forward(self,x):
        x = torch.relu(self.hidden(x))
        return self.output(x)
#定义更复杂的多层感知机(过拟合)
class MLPOverfitting(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden1 = nn.Linear(1,256)
        self.hidden2 = nn.Linear(256,256)
        self.output = nn.Linear(256,1)
    
    def forward(self,x):
        x = torch.relu(self.hidden1(x))
        x = torch.relu(self.hidden2(x))
        return self.output(x)
def plot_errors(models,num_epochs,train_dataloader,test_dataloader):
    #定义损失函数
    loss_fn = nn.MSELoss()
    
    #定义训练和测试误差数组
    train_losses = []
    test_losses = []
    
    #遍历每类模型
    for model in models:
        optimizer = torch.optim.SGD(model.parameters(),lr=0.005)
        
        train_losses_per_model = []
        test_losses_per_model = []
        
        for epoch in range(num_epochs):
            #在训练数据上迭代
            model.train()
            train_loss = 0 
            for inputs,targets in train_dataloader:
                optimizer.zero_grad()
                outputs = model(inputs)
                loss = loss_fn(outputs,targets)
                loss.backward()
                optimizer.step()
                #记录loss
                train_loss += loss.item()
            
            train_loss/=len(train_dataloader)
            train_losses_per_model.append(train_loss)
            
            model.eval()
            test_loss = 0
            with torch.no_grad():
                for inputs,targets in test_dataloader:
                    outputs = model(inputs)
                    loss = loss_fn(outputs,targets)
                    test_loss += loss.item()
                test_loss/=len(test_dataloader)
                test_losses_per_model.append(test_loss)
        
        
        #记录当前模型每轮的训练测试误差
        train_losses.append(train_losses_per_model)
        test_losses.append(test_losses_per_model)
    return train_losses,test_losses
num_epochs=200
models = [LinearRegression(),MLP(),MLPOverfitting()]
train_losses,test_losses = plot_errors(models,num_epochs,train_dataloader,test_dataloader)
for i,model in enumerate(models):
    plt.figure(figsize=(8,4))
    plt.plot(range(num_epochs),train_losses[i],label=f"Train{model.__class__.__name__}")
    plt.plot(range(num_epochs),test_losses[i],label=f"Test{model.__class__.__name__}")
    plt.legend()
    plt.legend()
    plt.ylim((0,200))
    plt.show()


© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号