一篇文章详解深度学习正则化方法(L1、L2、Dropout正则化相关概念、定义、数学公式、Python代码实现)

发布于:2024-04-16 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

一、什么是正则化?

二、正则化的作用?

三、常见的正则化方法

四、详解L1正则化 

 五、详解L2正则化

六、详解Dropout方法

总结:


博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战,深受全网粉丝喜爱与支持✌有需要可以联系作者我哦!

🍅文末三连哦🍅

👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟

 

一、什么是正则化?

正则化是指在机器学习和统计建模中的一种技术,用于控制模型的复杂度,防止模型在训练数据上过度拟合(overfitting)。当模型过度拟合时,它会学习到训练数据中的噪声和细微变化,导致在新数据上的性能下降。

正则化通过在模型的损失函数中引入额外的惩罚项,来对模型的参数进行约束,从而降低模型的复杂度。这个额外的惩罚通常与模型参数的大小或者数量相关,旨在鼓励模型学习简单的规律,而不是过度拟合训练数据。

在深度学习中,正则化通常涉及到对网络的权重进行约束,以防止它们变得过大或过复杂。最常见的正则化技术之一是 L1 和 L2 正则化,分别通过对权重的 L1 范数和 L2 范数进行惩罚来实现。这些技术有助于降低模型的复杂度,并提高模型在未见过的数据上的泛化能力。

二、正则化的作用?

  1. 防止过拟合:正则化通过对模型的复杂度进行限制,防止模型在训练数据上过度拟合。过拟合指的是模型在训练数据上表现良好,但在未见过的数据上表现较差的情况,这可能是因为模型学习到了训练数据中的噪声或者细节,而无法泛化到新数据上。正则化有助于使模型更加简单,从而提高其在未见过的数据上的泛化能力。

  2. 提高模型的泛化能力:正则化约束了模型的复杂度,使其更容易泛化到未见过的数据上。通过控制模型的参数大小或数量,正则化可以使模型更加稳定,减少对训练数据的过度依赖,从而提高模型的泛化能力。

  3. 减少模型的复杂度:正则化技术通过对模型的参数进行惩罚,促使模型更趋向于简单的解。例如,L1 和 L2 正则化会约束模型的权重,使其趋向于稀疏或较小的值,从而减少模型的复杂度。

  4. 控制模型的学习速度:正则化技术可以对模型的学习速度进行调节,防止模型在训练过程中权重变化过大,从而导致优化过程不稳定。这有助于加速模型的收敛,并提高模型在训练数据上的表现。

  5. 提高模型的鲁棒性:正则化有助于使模型更加鲁棒,即对输入数据的微小变化不敏感。通过降低模型的复杂度,正则化可以减少模型对训练数据中噪声的敏感度,从而提高模型的鲁棒性。

三、常见的正则化方法

  1. L1 正则化:也称为 Lasso 正则化,它通过在模型的损失函数中增加权重的 L1 范数(权重向量的绝对值之和)来实现正则化。L1 正则化倾向于产生稀疏权重矩阵,即将一些权重推向零,从而实现特征选择的效果。

  2. L2 正则化:也称为 Ridge 正则化,它通过在模型的损失函数中增加权重的 L2 范数(权重向量的平方和)来实现正则化。L2 正则化会使权重值变得较小,但不会直接导致权重稀疏,因此不具有特征选择的作用,但可以有效地控制模型的复杂度。

  3. Elastic Net 正则化:Elastic Net 是 L1 和 L2 正则化的组合,它在损失函数中同时使用 L1 和 L2 范数,可以综合两者的优点。

  4. Dropout:Dropout 是一种特殊的正则化技术,通过在训练过程中随机地丢弃(将其权重置为零)网络中的部分神经元,以及它们的连接,来减少神经网络的复杂度。这样可以防止神经元之间的共适应性,从而减少过拟合。

  5. 早停(Early Stopping):早停是一种简单而有效的正则化方法,它在训练过程中监视模型在验证集上的性能,一旦验证集上的性能开始下降,就停止训练。这样可以避免模型在训练集上过拟合。

  6. 数据增强(Data Augmentation):数据增强是通过对训练数据进行变换来增加数据的多样性,从而减少过拟合的风险。例如,在图像分类任务中可以进行随机裁剪、旋转、翻转等操作来增加训练数据的数量和多样性。

  7. 批量归一化(Batch Normalization):批量归一化是一种通过对每个批次的输入进行归一化来加速训练并减少过拟合的技术。它可以使得每一层的输入分布稳定,从而更容易优化模型。

  8. 权重衰减(Weight Decay):权重衰减是一种通过在损失函数中增加权重的平方和或绝对值之和来实现正则化的技术。它等价于对权重参数进行 L2 正则化。

四、详解L1正则化 

L1 正则化,也称为 Lasso 正则化,是一种常用的正则化技术,用于控制模型的复杂度和防止过拟合。它的原理是通过在模型的损失函数中增加权重的 L1 范数(权重向量的绝对值之和)作为惩罚项,从而鼓励模型产生稀疏权重,即让一部分权重趋近于零,实现特征选择的效果。

L1 正则化的损失函数:

L_{\text{L1}} = L_{\text{data}} + \lambda \sum_{i=1}^{n} |w_i|

其中:
- L_{\text{data}}是模型的数据损失,通常是模型的预测值与真实标签之间的误差,如均方误差(MSE)或交叉熵损失(Cross-entropy loss)。
- \lambda是正则化参数,用于控制正则化项的强度。
- |w_i| 表示模型的权重的绝对值。

公式推导: 

L1 正则化是一种通过在模型的损失函数中增加权重的 L1 范数作为惩罚项来控制模型复杂度的技术。L1 范数是向量中各个元素的绝对值之和,其数学表示如下:

||\mathbf{w}||_1 = \sum_{i=1}^{n} |w_i|

其中 \mathbf{w}是模型的权重向量,n是权重向量的长度,即权重的数量。

在 L1 正则化中,惩罚项可以写为权重的 L1 范数:

\text{penalty} = \lambda ||\mathbf{w}||_1

其中 \lambda是正则化参数,用于控制正则化的强度。

现在,我们来推导一下 L1 正则化的损失函数。假设我们有一个带有 L1 正则化的线性回归模型,其损失函数可以表示为:

L(\mathbf{w}) = L_{\text{data}}(\mathbf{w}) + \lambda ||\mathbf{w}||_1

其中 L_{\text{data}}(\mathbf{w})是模型的数据损失,通常是模型的预测值与真实标签之间的误差。

我们的目标是最小化整个损失函数。为了找到最小化损失函数的权重 \mathbf{w},我们可以使用梯度下降等优化算法。在梯度下降中,我们需要计算损失函数关于权重的梯度,然后根据梯度的方向和大小来更新权重。

现在,我们来推导损失函数关于权重的梯度。为了简化推导,我们假设 L_{\text{data}}(\mathbf{w})是均方误差损失函数,即:

L_{\text{data}}(\mathbf{w}) = \frac{1}{2} ||\mathbf{y} - \mathbf{X}\mathbf{w}||_2^2

其中 \mathbf{X}是输入特征矩阵,\mathbf{y}是真实标签向量。

我们的目标是最小化总损失函数:

L(\mathbf{w}) = \frac{1}{2} ||\mathbf{y} - \mathbf{X}\mathbf{w}||_2^2 + \lambda ||\mathbf{w}||_1

现在,我们对L(\mathbf{w})求导数,得到梯度:

\nabla L(\mathbf{w}) = -\mathbf{X}^T (\mathbf{y} - \mathbf{X}\mathbf{w}) + \lambda \text{sign}(\mathbf{w})

其中 \text{sign}(\mathbf{w})是权重向量 \mathbf{w}各个元素的符号函数。这意味着每个权重的梯度由数据损失和正则化项的梯度之和组成。

最后,我们可以使用梯度下降等优化算法来最小化损失函数,并找到最优的权重 \mathbf{w}。在优化过程中,L1 正则化项会促使一些权重趋向于零,从而实现特征选择的效果,降低模型的复杂度,防止

可视化对比L1正则化效果: 

过拟合Python 代码,用于生成带有噪声的线性数据集,并分别应用没有 L1 正则化和有 L1 正则化的线性模型来拟合数据,并在同一页面可视化对比两种情况的结果:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression, Lasso

# 生成带有噪声的线性数据集
np.random.seed(0)
X = np.random.rand(100, 1)  # 特征
y = 3 * X.squeeze() + np.random.normal(0, 0.3, 100)  # 标签

# 不使用正则化的线性回归模型
linear_model = LinearRegression()
linear_model.fit(X, y)

# 使用 L1 正则化的 Lasso 回归模型
lasso_model = Lasso(alpha=0.2)  # 正则化参数 alpha
lasso_model.fit(X, y)

# 可视化结果
plt.figure(figsize=(12, 6))

# 绘制原始数据和线性回归模型拟合结果
plt.subplot(1, 2, 1)
plt.scatter(X, y, color='blue', label='Data')
plt.plot(X, linear_model.predict(X), color='red', linewidth=2, label='Linear Regression')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Without L1 Regularization')
plt.legend()

# 绘制原始数据和 Lasso 回归模型拟合结果
plt.subplot(1, 2, 2)
plt.scatter(X, y, color='blue', label='Data')
plt.plot(X, lasso_model.predict(X), color='green', linewidth=2, label='Lasso Regression')
plt.xlabel('X')
plt.ylabel('y')
plt.title('With L1 Regularization (Lasso)')
plt.legend()

plt.show()

结果展示包含两个子图的图像,左侧子图展示了没有应用 L1 正则化的线性回归模型拟合结果,右侧子图展示了应用了 L1 正则化的 Lasso 回归模型拟合结果。通过这两个子图的对比,我们可以清晰地看到 L1 正则化的作用,它使得模型的权重变得更加稀疏,从而实现了特征选择的效果。

 五、详解L2正则化

L2 正则化,也称为 Ridge 正则化。它通过向模型的损失函数添加一个权重参数的 L2 范数的惩罚项来实现。下面我们来详细解释一下 L2 正则化的原理和数学公式。

数学公式:

在 L2 正则化中,惩罚项通常被定义为权重参数的 L2 范数的平方。具体地,L2 正则化的损失函数可以表示为:

L_{\text{L2}} = L_{\text{data}} + \lambda ||\mathbf{w}||_2^2

其中:
- L_{\text{data}}是模型的数据损失,通常是模型的预测值与真实标签之间的误差。
- \lambda是正则化参数,用于控制正则化的强度。
- ||\mathbf{w}||_2^2是权重向量\mathbf{w} 的 L2 范数的平方,表示为权重向量中各个参数的平方和。

使用 L2 正则化的损失函数时,优化算法在优化过程中会同时考虑数据损失和正则化项,从而在保持对训练数据的拟合能力的同时,尽可能减小模型参数的大小,降低模型的复杂度。

可视化L2正则化效果: 

首先,我们将生成一个带有噪声的线性数据集,并分别使用没有 L2 正则化的普通线性回归模型和带有 L2 正则化的 Ridge 回归模型来拟合数据。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression, Ridge

# 生成带有噪声的线性数据集
np.random.seed(0)
X = np.random.rand(100, 1)  # 特征
y = 3 * X.squeeze() + np.random.normal(0, 0.3, 100)  # 标签

# 没有使用 L2 正则化的线性回归模型
linear_model = LinearRegression()
linear_model.fit(X, y)

# 使用 L2 正则化的 Ridge 回归模型
ridge_model = Ridge(alpha=1.0)  # 正则化参数 alpha
ridge_model.fit(X, y)

# 可视化结果
plt.figure(figsize=(10, 6))
plt.scatter(X, y, color='blue', label='Data')
plt.plot(X, linear_model.predict(X), color='red', linewidth=2, label='Linear Regression (No L2 Regularization)')
plt.plot(X, ridge_model.predict(X), color='green', linewidth=2, label='Ridge Regression (L2 Regularization)')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Comparison of Linear Regression with and without L2 Regularization')
plt.legend()
plt.show()

 生成一个散点图,其中蓝色的点表示原始数据,红色的线表示没有 L2 正则化的普通线性回归模型的拟合结果,绿色的线表示带有 L2 正则化的 Ridge 回归模型的拟合结果。通过观察这张图,我们可以直观地比较两种模型的拟合效果,以及 L2 正则化对模型的影响。

六、详解Dropout方法

Dropout 是一种在神经网络中常用的正则化技术,用于减少过拟合。其原理是在网络的训练过程中,随机地将部分神经元的输出置为零(即失活),从而使得网络在每次迭代时都在不同的子网络上训练,以减少神经元之间的复杂依赖关系,从而增强模型的泛化能力。

工作原理:

  1. 随机失活神经元:在每次训练迭代时,Dropout 方法会以一定的概率(通常为 0.5)随机地将某些神经元的输出置为零,即使得这些神经元在此次迭代中不参与前向传播和反向传播。这样可以阻止网络过度依赖于某些特定的神经元,增强模型的泛化能力。

  2. 训练时与测试时的区别:在训练时,通过随机失活神经元来减少过拟合;而在测试时,所有的神经元都保持活跃,但是输出值需要按照训练时的概率进行缩放,以保持期望输出的一致性。

  3. Dropout的随机性:Dropout 是通过在每次迭代中随机选择要失活的神经元来实现的。这种随机性会导致网络在每次迭代时都训练在不同的子网络上,从而相当于训练了多个不同的模型,最终取平均或者加权平均作为最终的预测结果。

Dropout的优点:

  • 减少过拟合:通过随机失活部分神经元,阻止网络过度拟合训练数据,从而提高了模型的泛化能力。
  • 简单易用:Dropout 是一种简单而有效的正则化技术,可以直接应用于现有的神经网络模型中,而无需对网络结构进行修改。

数学公式:

在数学上,Dropout 的原理可以通过以下方式进行表述。

假设我们有一个具有L个隐藏层的神经网络,其中每个隐藏层l包含 n^{[l]}个神经元。对于每个隐藏层 l,我们定义一个二进制掩码向量\mathbf{d}^{[l]},其中d_{i}^{[l]} 表示第i个神经元是否被保留(未失活)。

在训练期间,对于每个训练示例t,Dropout 方法将随机地将掩码向量\mathbf{d}^{[l]}应用于每个隐藏层l 的输出,从而产生一个新的损失函数 L^{[l]}

L^{[l]}(\mathbf{W}^{[l]}, \mathbf{b}^{[l]}, \mathbf{d}^{[l]}) = \frac{1}{m} \sum_{t=1}^{m} L(y^{(t)}, \hat{y}^{(t)})

其中\mathbf{W}^{[l]}\mathbf{b}^{[l]} 是第l层的权重和偏置,L(y^{(t)}, \hat{y}^{(t)})是损失函数,\hat{y}^{(t)}是网络的输出,m是训练样本数量。

在测试期间,没有随机失活,因此需要通过缩放来调整每个隐藏层的输出。具体地,我们将每个神经元的输出值a^{[l]}乘以保留概率 p并除以p

\tilde{a}^{[l]} = \frac{a^{[l]}}{p}

通过这种方式,可以在测试期间保持期望输出不变,从而保持一致性。

在实践中,Dropout 的目标是将模型的期望输出与训练和测试期间的实际输出保持一致,从而减少过拟合并提高模型的泛化能力。

代码实现Dropout应用:

基于 PyTorch 框架,并使用 FashionMNIST 数据集来演示如何构建一个卷积神经网络(CNN)并应用 Dropout。在此示例中,我们将加载 FashionMNIST 数据集,创建一个包含 Dropout 层的简单 CNN 模型,并在训练过程中观察 Dropout 对模型性能的影响。

import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt

# 定义数据转换
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# 加载 FashionMNIST 数据集
trainset = torchvision.datasets.FashionMNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)

testset = torchvision.datasets.FashionMNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)

classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot')

# 定义卷积神经网络模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, padding=1)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(32, 64, 3, padding=1)
        self.fc1 = nn.Linear(64 * 7 * 7, 128)
        self.fc2 = nn.Linear(128, 10)
        self.dropout = nn.Dropout(0.5)  # 添加 Dropout 层

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 64 * 7 * 7)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)  # 在全连接层添加 Dropout
        x = self.fc2(x)
        return x

# 实例化模型和损失函数、优化器
net = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 训练模型
for epoch in range(5):  # 在 FashionMNIST 上训练 5 个 epoch
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

# 在测试集上评估模型
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

在模型中添加了一个 Dropout 层,其丢弃概率为 0.5。然后我们使用 SGD 优化器和交叉熵损失函数来训练模型。最后,我们在测试集上评估了模型的性能。

总结:

今天我们学习了正则化相关概念、常见神经网络中正则化数学公式及其作用。重点讲解正则化旨在防止模型过拟合,提高模型的泛化能力。常见的正则化方法包括L1和L2正则化,它们通过向损失函数添加正则项来限制模型参数的大小。另外,Dropout技术在训练过程中随机地关闭神经元,以减少神经网络的复杂性和过拟合风险。此外,数据增强也是一种有效的正则化方法,通过对训练数据进行微小的变换来增加数据的多样性,从而帮助模型更好地泛化到新的数据。这些正则化技术通常结合使用以提高模型的性能和鲁棒性。

今天内容分享到这里哦!

最后,创作不易!非常感谢大家的关注、点赞、评论啦!谢谢三连哦!好人好运连连,学习进步!工作顺利哦!