自学内容网 自学内容网

深度学习2

MAE损失:

MAE(Mean Absolute Error,平均绝对误差)通常也被称为 L1-Loss,通过对预测值和真实值之间的绝对差取平均值来衡量他们之间的差异。

特点:
  1. 鲁棒性:与均方误差(MSE)相比,MAE对异常值(outliers)更为鲁棒,因为它不会像MSE那样对较大误差平方敏感。

  2. 物理意义直观:MAE以与原始数据相同的单位度量误差,使其易于解释。

import torch
import torch.nn as nn
# 初始化MAE损失函数
mae_loss = nn.L1Loss()
# 假设 y_true 是真实值, y_pred 是预测值
y_true = torch.tensor([3.0, 5.0, 2.5])
y_pred = torch.tensor([2.5, 5.0, 3.0])
# 计算MAE
loss = mae_loss(y_pred, y_true)
print(f'MAE Loss: {loss.item()}')

 MSE损失:

均方差损失,也叫L2Loss。MSE(Mean Squared Error,均方误差)通过对预测值和真实值之间的误差平方取平均值,来衡量预测值与真实值之间的差异。

特点:
  1. 平方惩罚:因为误差平方,MSE 对较大误差施加更大惩罚,所以 MSE 对异常值更为敏感。

  2. 凸性:MSE 是一个凸函数,这意味着它具有一个唯一的全局最小值,有助于优化问题的求解。

import torch
import torch.nn as nn
# 初始化MSE损失函数
mse_loss = nn.MSELoss()
# 假设 y_true 是真实值, y_pred 是预测值
y_true = torch.tensor([3.0, 5.0, 2.5])
y_pred = torch.tensor([2.5, 5.0, 3.0])
# 计算MSE
loss = mse_loss(y_pred, y_true)
print(f'MSE Loss: {loss.item()}')

 SmoothLLoss:

SmoothL1Loss可以做到在损失较小时表现为 L2 损失,而在损失较大时表现为 L1 损失。

特点:
  1. 平滑过渡:当误差较小时,损失函数表现为 L2 Loss(平方惩罚);当误差较大时,损失函数逐渐向 L1 Loss过渡。这种平滑过渡既能对大误差有所控制,又不会对异常值过度敏感。

  2. 稳健性:对于异常值更加稳健,同时在小误差范围内提供了较好的优化效果。

import torch
import torch.nn as nn
# 创建模型的预测值和真实值
predictions = torch.tensor([1.0, 2.0, 3.0, 4.0])
targets = torch.tensor([3.0, 2.5, 3.5, 4.5])
# 计算损失方式1
smooth_loss = nn.SmoothL1Loss()
loss1 = smooth_loss(predictions, targets)  # 0.46875
# 计算损失方式2
loss2 = nn.functional.smooth_l1_loss(predictions, targets)
print("模型预测值:", predictions)
print("真实值:", targets)
print("均方误差损失:", loss1, loss2)

CrossEntropyLoss:

交叉熵损失函数,使用在输出层使用softmax激活函数进行多分类时,一般都采用交叉熵损失函数

特点:

Softmax 直白来说就是将网络输出的 logits 通过 softmax 函数,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)节点,作为我们的预测目标类别。

import torch
import torch.nn as nn
# 假设有三个类别,模型输出是未经softmax的logits
logits = torch.tensor([[1.5, 2.0, 0.5], [0.5, 1.0, 1.5]])
# 真实的标签
labels = torch.tensor([1, 2])  # 第一个样本的真实类别为1,第二个样本的真实类别为2
# 初始化CrossEntropyLoss
criterion = nn.CrossEntropyLoss()
# 计算损失
loss = criterion(logits, labels)
print(f'Cross Entropy Loss: {loss.item()}')

BCELoss:

二分类交叉熵损失函数,使用在输出层使用sigmoid激活函数进行二分类时。

import torch
import torch.nn as nn
# y 是模型的输出,已经被sigmoid处理过,确保其值域在(0,1)
y = torch.tensor([[0.7], [0.2], [0.9], [0.7]])
# targets 是真实的标签,0或1
t = torch.tensor([[1], [0], [1], [0]], dtype=torch.float)
# 计算损失方式一:
bceLoss = nn.BCELoss()
loss1 = bceLoss(y, t)
#计算损失方式二: 两种方式结果相同
loss2 = nn.functional.binary_cross_entropy(y, t)
print(loss1, loss2)
  • 当输出层使用softmax多分类时,使用交叉熵损失函数;

  • 当输出层使用sigmoid二分类时,使用二分类交叉熵损失函数, 比如在逻辑回归中使用;

  • 当功能为线性回归时,使用smooth L1损失函数或均方差损失-L2 loss;

 BP算法:

多层神经网络的学习能力比单层网络强得多。想要训练多层网络,需要更强大的学习算法。误差反向传播算法(Back Propagation)是其中最杰出的代表,它是目前最成功的神经网络学习算法。现实任务使用神经网络时,大多是在使用 BP 算法进行训练,值得指出的是 BP 算法不仅可用于多层前馈神经网络,还可以用于其他类型的神经网络。

 步骤:
  1. 前向传播:正向计算得到预测值。

  2. 计算损失:通过损失函数 L(y_{\text{pred}}, y_{\text{true}}) 计算预测值和真实值的差距。

  3. 梯度计算:反向传播的核心是计算损失函数 L 对每个权重和偏置的梯度。

  4. 更新参数:一旦得到每层梯度,就可以使用梯度下降算法来更新每层的权重和偏置,使得损失逐渐减小。

  5. 迭代训练:将前向传播、梯度计算、参数更新的步骤重复多次,直到损失函数收敛或达到预定的停止条件。

 前向传播:

前向传播(Forward Propagation)把输入数据经过各层神经元的运算并逐层向前传输,一直到输出层为止。

反向传播:

反向传播(Back Propagation,简称BP)通过计算损失函数相对于每个参数的梯度来调整权重,使模型在训练数据上的表现逐渐优化。反向传播结合了链式求导法则和梯度下降算法,是神经网络模型训练过程中更新参数的关键步骤。

import torch
import torch.nn as nn
import torch.optim as optim
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.linear1 = nn.Linear(2, 2)
        self.linear2 = nn.Linear(2, 2)
        # 网络参数初始化
        self.linear1.weight.data = torch.tensor([[0.15, 0.20], [0.25, 0.30]])
        self.linear2.weight.data = torch.tensor([[0.40, 0.45], [0.50, 0.55]])
        self.linear1.bias.data = torch.tensor([0.35, 0.35])
        self.linear2.bias.data = torch.tensor([0.60, 0.60])
    def forward(self, x):
        x = self.linear1(x)
        x = torch.sigmoid(x)
        x = self.linear2(x)
        x = torch.sigmoid(x)
        return x
if __name__ == "__main__":
    inputs = torch.tensor([[0.05, 0.10]])
    target = torch.tensor([[0.01, 0.99]])
    # 获得网络输出值
    net = Net()
    output = net(inputs)
    # 计算误差
    loss = torch.sum((output - target) ** 2) / 2
    # 优化方法
    optimizer = optim.SGD(net.parameters(), lr=0.5)
    # 梯度清零
    optimizer.zero_grad()
    # 反向传播
    loss.backward()
    # 打印(w1-w8)观察w5、w7、w1 的梯度值是否与手动计算一致
    print(net.linear1.weight.grad.data)
    print(net.linear2.weight.grad.data)
    #更新梯度
    optimizer.step()
    # 打印更新后的网络参数
    print(net.state_dict())

传统梯度下降:

梯度下降算法的目标是找到使损失函数L(\theta) 最小的参数 \theta,其核心是沿着损失函数梯度的负方向更新参数,以逐步逼近局部或全局最优解,从而使模型更好地拟合训练数据。

批量梯度下降:
  • 特点

    • 每次更新参数时,使用整个训练集来计算梯度。

  • 优点

    • 收敛稳定,能准确地沿着损失函数的真实梯度方向下降。

    • 适用于小型数据集。

  • 缺点

    • 对于大型数据集,计算量巨大,更新速度慢。

    • 需要大量内存来存储整个数据集。

随机梯度下降:
  • 特点

    • 每次更新参数时,仅使用一个样本来计算梯度。

  • 优点

    • 更新频率高,计算快,适合大规模数据集。

    • 能够跳出局部最小值,有助于找到全局最优解。

  • 缺点

    • 收敛不稳定,容易震荡,因为每个样本的梯度可能都不完全代表整体方向。

    • 需要较小的学习率来缓解震荡。

小批量梯度下降 :
  • 特点

    • 每次更新参数时,使用一小部分训练集(小批量)来计算梯度。

  • 优点

    • 在计算效率和收敛稳定性之间取得平衡。

    • 能够利用向量化加速计算,适合现代硬件(如GPU)。

  • 缺点

    • 选择适当的批量大小比较困难;批量太小则接近SGD,批量太大则接近批量梯度下降。

    • 通常会根据硬件算力设置为32\64\128\256等2的次方。

 缺点:
  • 收敛速度慢:BGD和MBGD使用固定学习率,太大会导致震荡,太小又收敛缓慢。

  • 局部最小值和鞍点问题:SGD在遇到局部最小值或鞍点时容易停滞,导致模型难以达到全局最优。

  • 训练不稳定:SGD中的噪声容易导致训练过程中不稳定,使得训练陷入震荡或不收敛。

优化梯度下降:

传统的梯度下降优化算法中,可能会碰到以下情况:碰到平缓区域,梯度值较小,参数优化变慢 碰到 “鞍点” ,梯度为 0,参数无法优化 碰到局部最小值 对于这些问题, 出现了一些对梯度下降算法的优化方法,例如:Momentum、AdaGrad、RMSprop、Adam 等.

加权平均:指的是给每个数赋予不同的权重求得平均数。

移动平均数:,指的是计算最近邻的 N 个数来获得平均数。

指数移动加权平均:(Exponential Moving Average简称EMA)则是参考各数值,并且各数值的权重都不同,距离越远的数字对平均数计算的贡献就越小(权重较小),距离越近则对平均数的计算贡献就越大(权重越大)。

 Momentum:

动量(Momentum)是对梯度下降的优化方法,可以更好地应对梯度变化和梯度消失问题,从而提高训练模型的效率和稳定性。

  • 惯性效应: 该方法加入前面梯度的累积,这种惯性使得算法沿着当前的方向继续更新。如遇到鞍点,也不会因梯度逼近零而停滞。

  • 减少震荡: 该方法平滑了梯度更新,减少在鞍点附近的震荡,帮助优化过程稳定向前推进。

  • 加速收敛: 该方法在优化过程中持续沿着某个方向前进,能够更快地穿越鞍点区域,避免在鞍点附近长时间停留。

AdaGrad:

AdaGrad(Adaptive Gradient Algorithm)为每个参数引入独立的学习率,它根据历史梯度的平方和来调整这些学习率,这样就使得参数具有较大的历史梯度的学习率减小,而参数具有较小的历史梯度的学习率保持较大,从而实现更有效的学习。AdaGrad避免了统一学习率的不足,更多用于处理稀疏数据和梯度变化较大的问题。

MRMSProp:

RMSProp(Root Mean Square Propagation)在时间步中,不是简单地累积所有梯度平方和,而是使用指数加权平均来逐步衰减过时的梯度信息。这种方法专门用于解决AdaGrad在训练过程中学习率过度衰减的问题。

ADdam:

Adam(Adaptive Moment Estimation)算法将动量法和RMSProp的优点结合在一起:

  • 动量法:通过一阶动量(即梯度的指数加权平均)来加速收敛,尤其是在有噪声或梯度稀疏的情况下。

  • RMSProp:通过二阶动量(即梯度平方的指数加权平均)来调整学习率,使得每个参数的学习率适应其梯度的变化。

  • Momentum 使用指数加权平均计算当前的梯度值、AdaGrad、RMSProp 使用自适应的学习率,Adam 结合了 Momentum、RMSProp 的优点,使用:移动加权平均的梯度和移动加权平均的学习率。使得能够自适应学习率的同时,也能够使用 Momentum 的优点。

欠拟合:

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

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

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

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

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

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

过拟合:

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

过拟合常见原因有:

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

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

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

L2正则化:

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

作用:
  1. 防止过拟合:当模型过于复杂、参数较多时,模型会倾向于记住训练数据中的噪声,导致过拟合。L2 正则化通过抑制参数的过大值,使得模型更加平滑,降低模型对训练数据噪声的敏感性。

  2. 限制模型复杂度:L2 正则化项强制权重参数尽量接近 0,避免模型中某些参数过大,从而限制模型的复杂度。通过引入平方和项,L2 正则化鼓励模型的权重均匀分布,避免单个权重的值过大。

  3. 提高模型的泛化能力:正则化项的存在使得模型在测试集上的表现更加稳健,避免在训练集上取得极高精度但在测试集上表现不佳。

  4. 平滑权重分布:L2 正则化不会将权重直接变为 0,而是将权重值缩小。这样模型就更加平滑的拟合数据,同时保留足够的表达能力。

import torch.optim as optim
optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=0.001)  # L2 正则化,weight_decay就是L2正则化前面的参数λ
 L1正则化:

L1 正则化通过在损失函数中添加权重参数的绝对值之和来约束模型的复杂度。

作用:
  1. 稀疏性:L1 正则化的一个显著特性是它会促使许多权重参数变为 。这是因为 L1 正则化倾向于将权重绝对值缩小到零,使得模型只保留对结果最重要的特征,而将其他不相关的特征权重设为零,从而实现 特征选择 的功能。

  2. 防止过拟合:通过限制权重的绝对值,L1 正则化减少了模型的复杂度,使其不容易过拟合训练数据。相比于 L2 正则化,L1 正则化更倾向于将某些权重完全移除,而不是减小它们的值。

  3. 简化模型:由于 L1 正则化会将一些权重变为零,因此模型最终会变得更加简单,仅依赖于少数重要特征。这对于高维度数据特别有用,尤其是在特征数量远多于样本数量的情况下。

  4. 特征选择:因为 L1 正则化会将部分权重置零,因此它天然具有特征选择的能力,有助于自动筛选出对模型预测最重要的特征。

def train():
    # 模型构建  
    # 损失函数
    # 优化器
    # 输入数据
    # 预测
    # 计算损失:L1 正则化项并将其加入到总损失中
    l1_lambda = 0.001
l1_norm = sum(p.abs().sum() for p in model.parameters())
    loss = criterion(output, target)+l1_lambda*l1_norm
    print(loss)
    # 梯度清零
    # 反向传播
    # 进行权重参数更新
    # 打印更新之后的权重参数
    # 保存模型权重参数
 Dropout:

Dropout 是一种在训练过程中随机丢弃部分神经元的技术。它通过减少神经元之间的依赖来防止模型过于复杂,从而避免过拟合。

import torch
import torch.nn as nn
def dropout():
    dropout = nn.Dropout(p=0.5)
    x = torch.randint(0, 10, (5, 6), dtype=torch.float)
    print(x)
    # 开始dropout
    print(dropout(x))
if __name__ == "__main__":
    dropout()
简化模型:
  • 减少网络层数和参数: 通过减少网络的层数、每层的神经元数量或减少卷积层的滤波器数量,可以降低模型的复杂度,减少过拟合的风险。

  • 使用更简单的模型: 对于复杂问题,使用更简单的模型或较小的网络架构可以减少参数数量,从而降低过拟合的可能性。

数据增强:

通过对训练数据进行各种变换(如旋转、裁剪、翻转、缩放等),可以增加数据的多样性,提高模型的泛化能力。

早停:

早停是一种在训练过程中监控模型在验证集上的表现,并在验证误差不再改善时停止训练的技术。这样可避免训练过度,防止模型过拟合。

模型集成:

通过将多个不同模型的预测结果进行集成,可以减少单个模型过拟合的风险。常见的集成方法包括投票法、平均法和堆叠法。

交叉验证:

使用交叉验证技术可以帮助评估模型的泛化能力,并调整模型超参数,以防止模型在训练数据上过拟合。

批量标准化:

在神经网络的搭建过程中,Batch Normalization (批量归一化)是经常使用一个网络层,其主要的作用是控制数据的分布,加快网络的收敛。

作用:

 缓解梯度问题:

标准化处理可以防止激活值过大或过小,避免了激活函数(如 Sigmoid 或 Tanh)饱和的问题,从而缓解梯度消失或爆炸的问题。

加速训练:

由于 BN 使得每层的输入数据分布更为稳定,因此模型可以使用更高的学习率进行训练。这可以加快收敛速度,并减少训练所需的时间。

减少过拟合:

  • 类似于正则化:虽然 BN 不是一种传统的正则化方法,但它通过对每个批次的数据进行标准化,可以起到一定的正则化作用。它通过在训练过程中引入了噪声(由于批量均值和方差的估计不完全准确),这有助于提高模型的泛化能力。

  • 避免对单一数据点的过度拟合:BN 强制模型在每个批次上进行标准化处理,减少了模型对单个训练样本的依赖。这有助于模型更好地学习到数据的整体特征,而不是对特定样本的噪声进行过度拟合。

import torch
import torch.nn as nn
def test001():
    x = torch.randint(0, 10, (4, 3, 32, 32)).float()
    print(x)
    bn = nn.BatchNorm2d(num_features=3, eps=1e-8, affine=True, momentum=0.9)
    print(bn(x))
if __name__ == "__main__":
    test001()

 


原文地址:https://blog.csdn.net/m0_74284888/article/details/144143763

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!