深度学习4月22笔记

1、过拟合与欠拟合

在训练深层神经网络时,由于模型参数较多,在数据量不足时很容易过拟合。而正则化技术主要就是用于防止过拟合,提升模型的泛化能力(对新数据表现良好)和鲁棒性(对异常数据表现良好)。

1. 概念认知

这里我们简单的回顾下过拟合和欠拟合的基本概念~

1.1 过拟合

过拟合是指模型对训练数据拟合能力很强并表现很好,但在测试数据上表现较差。

过拟合常见原因有:

  1. 数据量不足:当训练数据较少时,模型可能会过度学习数据中的噪声和细节。

  2. 模型太复杂:如果模型很复杂,也会过度学习训练数据中的细节和噪声。

  3. 正则化强度不足:如果正则化强度不足,可能会导致模型过度学习训练数据中的细节和噪声

1.2 欠拟合

欠拟合是由于模型学习能力不足,无法充分捕捉数据中的复杂关系。

1.3 如何判断

那如何判断一个错误的结果是过拟合还是欠拟合呢?

过拟合

训练误差低,但验证时误差高。模型在训练数据上表现很好,但在验证数据上表现不佳,说明模型可能过度拟合了训练数据中的噪声或特定模式。

欠拟合

训练误差和测试误差都高。模型在训练数据和测试数据上的表现都不好,说明模型可能太简单,无法捕捉到数据中的复杂模式。

2. 解决欠拟合

欠拟合的解决思路比较直接:

  1. 增加模型复杂度:引入更多的参数、增加神经网络的层数或节点数量,使模型能够捕捉到数据中的复杂模式。

  2. 增加特征:通过特征工程添加更多有意义的特征,使模型能够更好地理解数据。

  3. 减少正则化强度:适当减小 L1、L2 正则化强度,允许模型有更多自由度来拟合数据。

  4. 训练更长时间:如果是因为训练不足导致的欠拟合,可以增加训练的轮数或时间.

避免模型参数过大是防止过拟合的关键步骤之一。

模型的复杂度主要由权重w决定,而不是偏置b。偏置只是对模型输出的平移,不会导致模型过度拟合数据。

怎么控制权重w,使w在比较小的范围内?

考虑损失函数,损失函数的目的是使预测值与真实值无限接近,如果在原来的损失函数上添加一个非0的变量

 L_1(\hat{y},y) = L(\hat{y},y) + f(w)

其中f(w)是关于权重w的函数,f(w)>0

要使L1变小,就要使L变小的同时,也要使f(w)变小。从而控制权重w在较小的范围内。

2正则化

L2 正则化通过在损失函数中添加权重参数的平方和来实现,目标是惩罚过大的参数值

设损失函数为 L(\theta),其中 \theta 表示权重参数,加入L2正则化后的损失函数表示为:

L_{\text{total}}(\theta) = L(\theta) + \lambda \cdot \frac{1}{2} \sum_{i} \theta_i^2

其中:

  • L(\theta) 是原始损失函数(比如均方误差、交叉熵等)。

  • \lambda是正则化强度,控制正则化的力度。

  • \theta_i 是模型的第 i 个权重参数。

  • \frac{1}{2} \sum_{i} \theta_i^2 是所有权重参数的平方和,称为 L2 正则化项。

L2 正则化会惩罚权重参数过大的情况,通过参数平方值对损失函数进行约束。

为什么是\frac{\lambda}{2}

假设没有1/2,则对L2 正则化项\theta_i的梯度为:2\lambda\theta_i,会引入一个额外的系数 2,使梯度计算和更新公式变得复杂。

添加1/2后,对2\lambda\theta_i的梯度为:\lambda\theta_i

梯度更新

在 L2 正则化下,梯度更新时,不仅要考虑原始损失函数的梯度,还要考虑正则化项的影响。更新规则为:

\theta_{t+1} = \theta_t - \eta \left( \nabla L(\theta_t) + \lambda \theta_t \right)

其中:

  • \eta是学习率。

  • \nabla L(\theta_t)是损失函数关于参数 \theta_t 的梯度。

  • \lambda \theta_t 是 L2 正则化项的梯度,对应的是参数值本身的衰减。

很明显,参数越大惩罚力度就越大,从而让参数逐渐趋向于较小值,避免出现过大的参数。

权重就会趋向于较小的值

早停

早停是一种在训练过程中监控模型在验证集上的表现,并在验证误差不再改善时停止训练的技术。这样可避免训练过度,防止模型过拟合。pytorch没有现成的API,需要自己写代码实现。

早停法的实现步骤

  1. 将数据集分为训练集和验证集。

  2. 在训练过程中,定期(例如每个 epoch)在验证集上评估模型的性能(如损失或准确率)。

  3. 记录验证集的最佳性能(如最低损失或最高准确率)。

  4. 如果验证集的性能在连续若干次评估中没有改善(即达到预设的“耐心值”),则停止训练。

  5. 返回验证集性能最佳时的模型参数。

早停法的关键参数

  1. 耐心值(Patience):

    • 允许验证集性能不提升的连续次数。

    • 例如,如果耐心值为 5,则当验证集损失连续 5 次没有下降时,停止训练。

  2. 最小改善值(Min Delta):

    • 定义“性能提升”的最小阈值。

    • 例如,如果验证集损失的变化小于该值,则认为性能没有提升。

  3. 恢复最佳权重(Restore Best Weights):

    • 是否在早停时恢复验证集性能最佳时的模型权重。

import torch
import torch.nn as nn
from torch import optim
from torch.utils.data import Dataset, DataLoader, TensorDataset
from sklearn.model_selection import train_test_split
import numpy as np


# 1.定义一个简单的神经网络
class simple_net(nn.Module):
    def __init__(self):
        super(simple_net, self).__init__()
        self.fc1 = nn.Linear(20, 10)
        self.fc2 = nn.Linear(10, 1)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.fc2(x)
        return x


# 早停法类
class Early_Stopping():
    def __init__(self, patience=10, min_delta=0.0):
        self.patience = patience
        self.min_delta = min_delta
        self.counter = 0
        self.best_loss = None
        self.early_stop = False

    def __call__(self, val_loss):
        # 如果best_loss 为空,,把损失赋值给最佳
        if self.best_loss is None:
            self.best_loss = val_loss
        # 新损失减少大于最少损失,耐心加一
        elif val_loss > self.best_loss - self.min_delta:
            self.counter += 1
            # 耐心大于等于设定的阈值,把flag置为true
            if self.counter >= self.patience:
                self.early_stop = True
        # 其他情况,更新最佳损失,计数器置0
        else:
            self.best_loss = val_loss
            self.counter = 0


# 生成随机数据
np.random.seed(0)
torch.manual_seed(0)

x = torch.randn(1000, 20)
y = torch.randn(1000, 1)


x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
# 转换为张量



# 创建Dataloader
train_set = TensorDataset(x_train, y_train)
train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
test_set = TensorDataset(x_test, y_test)
test_loader = DataLoader(test_set, batch_size=32, shuffle=True)

# 初始化模型、损失函数和优化器
model = simple_net()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 初始化早停
early_stopping = Early_Stopping(patience=10, min_delta=0.001)

# 循环次数epochs
epochs = 100
train_losses = []
test_losses = []
for epoch in range(epochs):
    model.train()
    epoch_loss = 0
    for x_batch, y_batch in train_loader:
        y_pred = model(x_batch)
        loss = criterion(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
    train_losses.append(epoch_loss/len(train_loader))


    # 验证阶段
    model.eval()
    epoch_test_loss = 0
    for x_batch, y_batch in test_loader:
        y_pred = model(x_batch)
        loss = criterion(y_pred, y_batch)
        epoch_test_loss += loss.item()

    test_losses.append(epoch_test_loss/len(test_loader))

    if epoch % 5 == 0:
        print(f'Epoch {epoch}: train_Loss {train_losses[-1]:.4f} test_Loss {test_losses[-1]:.4f}')

    # 早停法检测
    early_stopping(test_losses[-1])
    if early_stopping.early_stop:
        print('Early stopping')
        break

print('Training complete')

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值