深度学习loss

 pytorch模型训练demo代码

在PyTorch中,模型训练通常涉及几个关键步骤:定义模型、定义损失函数、选择优化器、准备数据加载器、编写训练循环。以下是一个简单的PyTorch模型训练演示代码,该代码实现了一个用于手写数字识别(使用MNIST数据集)的简单神经网络。

首先,确保你已经安装了PyTorch和torchvision(用于加载MNIST数据集)。

import torch  
import torch.nn as nn  
import torch.optim as optim  
from torchvision import datasets, transforms  
from torch.utils.data import DataLoader  # 定义模型  
class Net(nn.Module):  def __init__(self):  super(Net, self).__init__()  self.fc1 = nn.Linear(28*28, 500)  # 输入层到隐藏层  self.relu = nn.ReLU()  self.fc2 = nn.Linear(500, 10)     # 隐藏层到输出层  def forward(self, x):  x = x.view(-1, 28*28)  # 展平图像  x = self.relu(self.fc1(x))  x = self.fc2(x)  return x  # 准备数据  
transform = transforms.Compose([  transforms.ToTensor(),  # 转换为Tensor  transforms.Normalize((0.5,), (0.5,))  # 归一化  
])  train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)  
train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)  # 实例化模型、损失函数和优化器  
model = Net()  
criterion = nn.CrossEntropyLoss()  # 多分类交叉熵损失  
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)  # 训练模型  
num_epochs = 5  
for epoch in range(num_epochs):  for i, (images, labels) in enumerate(train_loader):  # 前向传播  outputs = model(images)  loss = criterion(outputs, labels)  # 反向传播和优化  optimizer.zero_grad()  # 清零梯度  loss.backward()        # 反向传播  optimizer.step()       # 更新参数  if (i+1) % 100 == 0:  print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {loss.item():.4f}')  print('Finished Training')

在这个例子中,我们定义了一个简单的全连接神经网络Net,它包含两个全连接层和一个ReLU激活函数。我们使用MNIST数据集进行训练,该数据集包含了手写数字的图像。我们使用了交叉熵损失函数和SGD优化器。

在训练循环中,我们遍历数据加载器中的每个批次,对每个批次执行前向传播以计算损失,然后执行反向传播以计算梯度,并使用优化器更新模型的参数。每处理100个批次,我们就打印当前的损失值,以便监控训练过程。

loss反向传播发生了什么(★)

在PyTorch中,loss.backward() 是一个非常重要的函数,它用于计算损失函数(loss)关于所有可训练参数(即需要梯度的参数)的梯度。这个过程是自动微分(Automatic Differentiation)的一部分,它允许PyTorch自动计算复杂的数学表达式(如神经网络中的损失函数)的梯度。下面是loss.backward()具体做了什么的一个详细解释:

  1. 计算梯度:当你调用loss.backward()时,PyTorch会首先计算损失函数loss关于其所有输入参数的梯度。在神经网络中,这些输入参数通常包括模型的权重和偏置(即模型的可训练参数)。

  2. 梯度累积:对于每个可训练参数,PyTorch会计算其梯度,并将这些梯度累加到该参数的.grad属性中。这意味着,如果你多次调用loss.backward()(在梯度被清零之前),梯度会被累加。这在你想要累积多个小批量(mini-batches)的梯度时很有用,但通常情况下,你需要在每次迭代后清零梯度,以避免梯度累积。

  3. 不影响原始数据loss.backward()只计算梯度,并不会改变模型参数(权重和偏置)的值。参数的更新通常是通过优化器(如SGD、Adam等)来完成的,这些优化器使用.grad属性中的梯度来更新参数。

  4. 图执行:在PyTorch中,计算图(computation graph)用于跟踪所有操作的顺序和依赖关系。当你调用loss.backward()时,PyTorch会遍历这个图,从损失函数开始,反向传播梯度直到到达所有可训练的参数。

  5. 注意:为了正确计算梯度,你需要确保在调用loss.backward()之前,损失函数loss的所有输入都是requires_grad=True的。这通常意味着这些输入是模型的输出,而模型的参数(如权重和偏置)在初始化时自动设置为requires_grad=True

  6. 梯度清零:在每次迭代或每个小批量之后,你需要使用optimizer.zero_grad()来清零所有参数的梯度,以确保下一次迭代或小批量使用的是新的梯度。

总结来说,loss.backward()是PyTorch中实现反向传播的关键步骤,它计算损失函数关于所有可训练参数的梯度,并将这些梯度累加到参数的.grad属性中,为后续的参数更新做准备。

可以查看“pytorch模型训练demo代码”,

# 反向传播和优化  
        optimizer.zero_grad()  # 清零梯度  
        loss.backward()        # 反向传播  
        optimizer.step()       # 更新参数

我们先把之前累计的梯度清零;然后调用反向传播,这个时候pytorch会遍历“计算图”,从损失函数开始,反向传播梯度直到到达所有可训练的参数;然后我们利用优化器来更新参数。

 数学基础-熵

让我们从理解熵这个术语开始。通常,我们用熵来表示无序或不确定性,它是对概率分布为p(X)的随机变量X进行测量的:

负号是用来使总数量为正的。

一个概率分布的熵值越大,表明该分布的不确定性越大。同样,值越小,分布越确定。

 BCELoss

Binary Cross Entropy Loss(二分类交叉熵损失函数),是深度学习中处理二分类问题时常用的损失函数之一

一、BCELoss的基本概念

BCELoss用于衡量模型预测结果(通常是一个概率值,取值范围为0到1)与真实标签(取值为0或1)之间的差异。它基于信息熵的概念,通过最小化损失函数来优化模型参数,使模型预测结果更加接近真实标签。

二、BCELoss的计算公式

BCELoss的计算公式为:

其中,N 是样本数量,yi​ 是第 i 个样本的真实标签,y^​i​ 是第 i 个样本的预测概率。这个公式实际上是对每个样本的损失进行平均(当 reduction='mean' 时),也可以选择不平均(当 reduction='none' 时)或求和(当 reduction='sum' 时)。

二元交叉熵适合作为损失函数来最小化它的值。对于输出概率p的分类模型,我们使用二元交叉熵损失。元素属于1类(或正类)的概率= p那么,元素属于0类(或负类)的概率= 1 - p

那么,定义输出标签y(可以取0和1)和预测概率p的交叉熵损失(这也叫做对数损失)为:

在这里插入图片描述

思考:为什么二元交叉熵适合作为分类问题的损失函数?

因为p->0时,L->0;而p->1时,L->0;所以可以收敛。

为了计算概率p,我们可以使用Sigmoid函数。这里,z是输入特征的函数:
在这里插入图片描述
Sigmoid函数的取值范围为[0,1],适合计算概率。

在这里插入图片描述

torch.nn.BCELoss

这个类接受一些可选参数,如 weight(用于对损失函数中的每个元素进行加权)、reduction(指定输出的格式,包括'none'、'mean'、'sum')等。

import torch  
import torch.nn as nn  # 创建二分类交叉熵损失函数  
loss_fn = nn.BCELoss(reduction='mean')  # 默认reduction为'mean'  # 模型预测结果(需要经过sigmoid函数处理,确保值在0到1之间)  
# 这里为了示例直接给出,实际中应该是模型的输出  
y_hat = torch.tensor([0.2, 0.8, 0.6, 0.3], requires_grad=True)  # 真实标签  
y = torch.tensor([0, 1, 1, 0], dtype=torch.float32)  # 计算损失  
loss = loss_fn(y_hat, y)  # 打印损失  
print(loss)

注意:在实际应用中,由于BCELoss要求输入的概率值在0到1之间,因此通常会在模型输出后接一个sigmoid函数来确保这一点。

然而,在PyTorch中,还有一个更方便的损失函数 BCEWithLogitsLoss,它将sigmoid函数和BCELoss结合在了一起,可以直接接受模型的原始输出(即logits)作为输入,并自动应用sigmoid函数后再计算损失。这样做的好处是数值上更加稳定,且计算效率更高。

nn.BCEWithLogitsLoss

nn.BCEWithLogitsLoss 是 PyTorch 中的一个损失函数,特别适用于二元分类问题。该函数结合了 Sigmoid 激活函数和 Binary Cross-Entropy (BCE) 损失函数,旨在提高训练效率和数值稳定性。以下是对 nn.BCEWithLogitsLoss 的详细解析:

一、定义与功能

nn.BCEWithLogitsLoss 是 PyTorch 中的一个类,它实现了将 Sigmoid 激活函数和二元交叉熵损失函数合并的功能。这个损失函数接受两个输入:模型的原始输出(未经 Sigmoid 激活)和目标(真实)标签,然后自动计算损失值。由于它在内部集成了 Sigmoid 激活函数,因此可以避免在正向和反向传播过程中可能出现的梯度爆炸或梯度消失问题。

二、计算过程

nn.BCEWithLogitsLoss 的计算过程大致如下:

  1. Sigmoid 激活:首先,对模型的原始输出应用 Sigmoid 激活函数,将其映射到 (0, 1) 区间内,表示每个样本属于正类的概率。

  2. 二元交叉熵损失计算:然后,使用二元交叉熵损失函数计算模型预测概率与真实标签之间的差异。二元交叉熵损失函数的公式为:

    [
    \text{BCEWithLogitsLoss}(x, y) = -\frac{1}{n} \sum_{i=1}^{n} \left[ y_i \cdot \log(\sigma(x_i)) + (1 - y_i) \cdot \log(1 - \sigma(x_i)) \right]
    ]

    其中,x 表示模型的输出结果(是未经 Sigmoid 激活的 logits),y 表示真实标签,σ 表示 Sigmoid 函数(\sigma(x_i) = \frac{1}{1 + e^{-x_i}}),n 表示样本数量。

  3. 参数处理:根据 size_averagereduce 和 reduction 参数(在较新版本的 PyTorch 中,通常只使用 reduction 参数),对损失值进行平均或求和操作。

三、优点与特性

  1. 数值稳定性:由于内部集成了 Sigmoid 函数,nn.BCEWithLogitsLoss 可以避免直接计算 log(1−p) 时的数值稳定性问题。

  2. 梯度计算:它能够自动计算 Sigmoid 函数的梯度,减轻了开发者的负担,并有助于梯度在反向传播过程中的正确传递。

  3. 联合优化:因为 Sigmoid 函数是包含在损失函数内部的,所以可以与其他层一起进行端到端的联合优化,简化了模型的设计和训练过程。

  4. 处理样本不平衡:通过 weight 和 pos_weight 参数,可以处理样本不平衡的问题,提高模型对少数类样本的学习能力。

四、使用示例

以下是一个使用 nn.BCEWithLogitsLoss 的简单示例:

import torch  
import torch.nn as nn  # 创建模型输出和目标标签  
inputs = torch.randn(10, 1, requires_grad=True)  # 假设有10个样本,每个样本的输出是一个实数  
targets = torch.randint(2, (10, 1), dtype=torch.float)  # 目标标签,0或1  
print(inputs.view(1,-1))
print(targets.view(1,-1))
# 定义损失函数  
criterion = nn.BCEWithLogitsLoss()  # 计算损失  
loss = criterion(inputs, targets)  # 反向传播  
loss.backward()
print(f"Loss: {loss.item()}")print(f"Gradients: {inputs.grad.view(1,-1)}")

在这个示例中,我们首先生成了一个包含10个随机实数的张量作为模型的输出,并生成了一个包含0和1的随机整数张量作为真实标签。然后,我们创建了一个 nn.BCEWithLogitsLoss 的实例,并将模型的输出和真实标签传递给该实例以计算损失值。最后,我们调用 loss.backward() 方法进行反向传播。

五、总结

nn.BCEWithLogitsLoss 是 PyTorch 中一个用于二元分类问题的强大损失函数,它通过结合 Sigmoid 激活函数和二元交叉熵损失函数,提高了训练的效率和数值稳定性。在实际应用中,它可以方便地处理样本不平衡等问题,并与其他层一起进行端到端的联合优化。

六、参数理解(☆)

torch.nn.BCEWithLogitsLosspos_weight参数用于处理数据集中正负样本不平衡的问题。当数据集中的正样本(即目标标签为1的样本)和负样本(目标标签为0的样本)数量差异很大时,模型可能会偏向于多数类(通常是负样本),导致对少数类(正样本)的预测性能不佳。为了缓解这个问题,pos_weight参数允许用户对正样本的损失进行加权,从而增加模型对正样本的关注度。

具体来说,pos_weight参数可以是一个标量或一个与类别数(在多标签分类中)相同长度的张量。但在二分类问题中,它通常是一个标量,表示正样本损失的权重系数。例如,如果正样本的数量是负样本数量的三分之一,那么你可以将pos_weight设置为3,这样正样本的每个损失值都会被乘以3,从而在训练过程中给予正样本更多的重视。

需要注意的是,pos_weight的应用方式是在计算二元交叉熵损失之前,先对正样本的损失进行加权。这样,即使数据集中正负样本的数量不平衡,模型也能通过调整权重来更好地学习如何区分两个类别。

此外,torch.nn.BCEWithLogitsLoss还提供了其他参数,如weight(用于为不同类别的样本设置权重,但在二分类中通常不使用)和reduction(用于指定损失的计算方式,如'mean'表示计算损失的平均值,'sum'表示计算损失的总和,'none'表示不应用任何约简并返回每个样本的损失值)。然而,在大多数情况下,用户主要关注的是pos_weight参数,以便处理数据集中的不平衡问题。

nn.BCEWithLogitsLoss的原理

我们自定义一个函数来实现nn.BCEWithLogitsLoss 的功能,便于我们理解它的原理。

但我们的实现并未完全达到 PyTorch 内置函数的效率和数值稳定性。在实际应用中,你应该直接使用 PyTorch的 nn.BCEWithLogitsLoss 类,因为它已经过优化,能够处理各种边界情况和数值稳定性问题。

以下是一个简化的 BCEWithLogitsLoss 实现示例:

import torch
import torch.nn as nn# 假设的模型输出(logits)
logits = torch.tensor([[1.0, -1.0, 2.0], [-0.5, 0.5, -1.5]], requires_grad=True)# 真实的标签(注意,这些应该是介于 0 和 1 之间的概率,但在二元分类中,我们通常使用 0 和 1)
targets = torch.tensor([[1, 0, 1], [0, 1, 0]], dtype=torch.float32)# 显式地计算 Sigmoid 函数
def sigmoid(x):return 1 / (1 + torch.exp(-x))probs = sigmoid(logits)
epsilon = 1e-9
bce_loss_manual = -torch.mean(targets * torch.log(probs + epsilon) + (1 - targets) * torch.log(1 - probs + epsilon))
# 注意:上面的 1e-9 是为了避免 log(0) 的情况,PyTorch 内部也有类似的处理。# 使用 PyTorch 内置的 BCEWithLogitsLoss
# 计算二元交叉熵损失
# 注意:PyTorch 的 BCE 损失期望输入的概率在 [epsilon, 1-epsilon] 范围内,
# 其中 epsilon 是一个很小的数,以避免 log(0)。这里我们直接使用 sigmoid 的输出,
# PyTorch 内部会处理这个问题。
bce_with_logits_loss = nn.BCEWithLogitsLoss(reduction='mean')(logits, targets)# 输出结果,以验证我们的手动实现
print("手动计算的 BCE 损失(已应用 Sigmoid):", bce_loss_manual.item())  # 注意:这行代码在上面的代码中未直接定义,但你可以通过取消注释相关行来计算
print("使用 PyTorch 内置的 BCEWithLogitsLoss:", bce_with_logits_loss.item())

CrossEntropyLoss

一、定义与应用场景

  • CrossEntropyLoss(交叉熵损失)
    • 定义:交叉熵损失函数是信息论中的一个概念,用于度量两个概率分布之间的差异。在机器学习中,它常作为损失函数来衡量模型预测的概率分布与真实标签的概率分布之间的差异。
    • 应用场景:适用于多分类问题,也可以用于二分类问题(但此时与BCEloss等价)。在多分类问题中,CrossEntropyLoss通常与softmax函数结合使用,将模型的输出转换为概率分布。

二、计算公式

  • CrossEntropyLoss(交叉熵损失)
    对于多分类问题,其一般形式为:

    其中,yic​ 是第 i 个样本对于类别 c 的真实标签(通常采用one-hot编码),p(yic​) 是模型预测第 i 个样本属于类别 c 的概率,C 是类别总数,N 是样本总数。

    对于二分类问题,CrossEntropyLoss可以简化为与BCEloss相同的公式。

 torch.nn.CrossEntropyLoss

  1. 定义模型:确保你的模型输出层没有应用softmax或log-softmax。输出应该是未经归一化的logits。

  2. 定义损失函数:使用torch.nn.CrossEntropyLoss作为你的损失函数。

  3. 前向传播和损失计算:将模型的输出(logits)和真实标签(通常是整数,表示每个样本的类别索引)传递给损失函数。

      

import torch  
import torch.nn as nn  
import torch.nn.functional as F  # 假设你有一个简单的模型  
class SimpleModel(nn.Module):  def __init__(self, input_size, num_classes):  super(SimpleModel, self).__init__()  self.fc = nn.Linear(input_size, num_classes)  # 假设只有一个全连接层  def forward(self, x):  return self.fc(x)  # 直接返回logits  # 实例化模型  
model = SimpleModel(input_size=10, num_classes=3)  # 定义损失函数  
criterion = nn.CrossEntropyLoss()  # 假设你有一些输入数据和真实标签  
inputs = torch.randn(1, 10)  # 假设批次大小为1,输入特征维度为10  
targets = torch.tensor([1])  # 假设真实标签是类别1(注意是整数索引)  # 前向传播得到logits  
logits = model(inputs)  # 计算损失  
loss = criterion(logits, targets)  print(loss)

在这个例子中,nn.CrossEntropyLoss接收logits和真实标签作为输入,并自动计算交叉熵损失。你不需要(也不应该)在将logits传递给损失函数之前显式地应用softmax或log-softmax。

注意

  • 真实标签应该是整数,表示每个样本的类别索引。
  • 如果你的模型输出层是nn.LogSoftmax,那么你应该使用nn.NLLLoss(负对数似然损失)而不是nn.CrossEntropyLoss,因为nn.CrossEntropyLoss期望的输入是logits而不是log-probabilities。但是,在大多数情况下,直接输出logits并使用nn.CrossEntropyLoss是更常见的做法。

softmax

Softmax函数,也称为归一化指数函数,是数学和机器学习领域,尤其是概率论和神经网络中广泛使用的一种函数。它的主要功能是将一个含任意实数的K维向量“压缩”到另一个K维实向量中,使得这个新向量的每个元素都在(0,1)之间,并且所有元素的和为1,从而形成一个概率分布。

定义与公式

Softmax函数的公式为:

其中,zi​是输入向量z的第i个元素,n是向量的维度(或类别数)。这个公式确保了输出向量的每个元素都是非负的,并且它们的和为1,满足概率分布的要求。

应用领域

Softmax函数在多分类问题中有着广泛的应用,如图像分类、文本分类、语音识别等。在神经网络中,Softmax函数通常用于输出层,将神经网络的原始输出(logits)转换为概率分布,以便于进行类别的预测和损失的计算。

特点与优势

  1. 归一化:Softmax函数能够将任意实数值的向量转换为概率分布,这是其最重要的特点之一。
  2. 可解释性:由于输出是概率分布,因此Softmax函数的输出具有很好的可解释性,可以直观地表示每个类别的预测概率。
  3. 稳定性:在处理大数值时,Softmax函数可能会遇到数值稳定性问题(如数值溢出)。然而,通过一些技巧(如减去输入向量中的最大值)可以有效地缓解这个问题。
  4. 与交叉熵损失函数的结合:Softmax函数经常与交叉熵损失函数联合使用,以衡量模型预测的概率分布与真实标签之间的差异,并在训练过程中通过反向传播算法来优化模型参数。

示例

假设我们有一个三维向量z=[1,2,3],应用Softmax函数后,可以得到一个三维概率分布p=[softmax(1),softmax(2),softmax(3)]。通过计算,我们可以得到p≈[0.0900,0.2447,0.6652],这个概率分布表示了输入向量z对应于三个类别的预测概率。

总结

Softmax函数是机器学习和神经网络中非常重要的一个函数,它能够将神经网络的原始输出转换为概率分布,从而方便地进行多分类问题的预测和损失的计算。在实际应用中,Softmax函数经常与交叉熵损失函数联合使用,并通过反向传播算法来优化模型参数。

nn.CrossEntropyLoss的原理

在PyTorch中,nn.CrossEntropyLoss 是一个非常常用的损失函数,用于多分类问题。它内部结合了 nn.LogSoftmax() 和 nn.NLLLoss() 的功能,即首先应用 softmax 函数将原始输出转换为概率分布,然后计算负对数似然损失(Negative Log Likelihood Loss)。下面,我们将用 Python 和 NumPy 来模拟实现这个损失函数。

首先,我们需要了解 nn.CrossEntropyLoss 的工作原理。给定模型的原始输出(logits)和目标标签(通常是整数),这个损失函数会:

  1. 对 logits 应用 softmax 函数以获取概率分布。
  2. 计算目标类别的负对数概率。
  3. 对所有样本的损失进行平均或求和(取决于 reduction 参数)。

下面是使用 NumPy 模拟 nn.CrossEntropyLoss 的实现:

import numpy as np
import torch
import torch.nn as nndef softmax(x):"""计算 softmax 函数"""e_x = np.exp(x - np.max(x, axis=1, keepdims=True))return e_x / e_x.sum(axis=1, keepdims=True)def cross_entropy_loss(logits, targets, reduction='mean'):"""模拟 PyTorch 的 nn.CrossEntropyLoss参数:- logits: 模型的原始输出,形状为 (batch_size, num_classes)- targets: 目标标签,形状为 (batch_size,)- reduction: 指定损失的计算方式,'mean' 或 'sum'返回:- 损失值"""# 确保 logits 和 targets 都是 numpy 数组logits = np.asarray(logits, dtype=np.float32)print('logits {}'.format(logits))targets = np.asarray(targets, dtype=np.int64)print('targets {}'.format(targets))# 计算 softmaxprobs = softmax(logits)print('softmax {}'.format(probs))# 获取目标类别的概率targets_shape = np.arange(targets.shape[0])print('targets_shape {}'.format(targets_shape))targets_probs = probs[targets_shape, targets]print('targets_probs {}'.format(targets_probs))loss = -np.log(targets_probs)print('loss {}'.format(loss))# 根据 reduction 参数处理损失if reduction == 'mean':return np.mean(loss)elif reduction == 'sum':return np.sum(loss)else:raise ValueError("reduction 必须是 'mean' 或 'sum'")logits = np.array([[2.0, 1.0, 0.1], [1.0, 0.2, 1.5]])
targets = np.array([0, 2])
celoss_self = cross_entropy_loss(logits, targets, reduction='mean')
celoss = nn.CrossEntropyLoss(reduction='mean')
celoss_correct = celoss(torch.Tensor(logits), torch.tensor(targets))
print('compare : celoss_self {} celoss_correct {}'.format(celoss_self, celoss_correct))

在这个示例中,我们首先定义了一个 softmax 函数来计算概率分布,然后定义了 cross_entropy_loss 函数来模拟 nn.CrossEntropyLoss。这个函数首先使用 softmax 将 logits 转换为概率,然后计算目标类别的负对数概率,最后根据 reduction 参数返回损失的平均值或总和。

注意:这个实现是为了教学和演示目的。在实际应用中,直接使用 PyTorch 或 TensorFlow 等深度学习框架提供的损失函数会更方便、更高效。

BCELoss vs CELoss

主要区别

  1. 应用场景:BCEloss专门用于二分类问题,而CrossEntropyLoss既可用于多分类问题,也可用于二分类问题(但在二分类问题中,两者本质上是等价的)。
  2. 计算细节:虽然两者在二分类问题中的计算公式相同,但在多分类问题中,CrossEntropyLoss需要考虑所有类别的预测和真实标签,而BCEloss则只关注两个类别(0和1)。
  3. 使用方式:在PyTorch等深度学习框架中,BCEloss通常与sigmoid激活函数结合使用(因为sigmoid函数可以将输出转换为概率),而CrossEntropyLoss则通常与softmax函数结合使用(softmax函数将输出转换为概率分布)。然而,需要注意的是,在PyTorch中,使用CrossEntropyLoss时,模型输出不需要先经过softmax函数,因为CrossEntropyLoss内部已经包含了softmax操作(实际上是log-softmax,然后与外部的负号结合形成交叉熵损失)。

综上所述,BCEloss和CrossEntropyLoss在定义、应用场景和计算公式上存在一定差异,但在二分类问题中,两者可以视为等价。在实际应用中,应根据具体问题选择合适的损失函数。

Focal Loss(★)

Focal Loss论文指的是《Focal Loss for Dense Object Detection》,该论文由Tsung-Yi Lin、Priya Goyal、Ross Girshick、Kaiming He和Piotr Dollar等人在ICCV 2017会议上提出。以下是关于该论文的详细概述:

一、论文背景与动机

在目标检测领域,主要分为两大类算法:两阶段检测器(Two-stage detector)和单阶段检测器(One-stage detector)。两阶段检测器(如Faster R-CNN)通过先生成候选区域(Region Proposal),再对这些区域进行分类和回归,可以达到较高的准确率但速度较慢。而单阶段检测器(如YOLO、SSD)则直接对图片中的每个可能位置进行密集采样并预测边界框,速度快但准确率相对较低。

作者认为,单阶段检测器在训练过程中遇到的极端前景背景类别不均衡(extreme foreground-background class imbalance)是导致其精度低于两阶段检测器的主要原因。具体来说,在一张图像中生成的成千上万的候选位置中,只有很少一部分是包含目标的,这导致了正负样本数量极不均衡,且大多数负样本都是容易分类的,使得模型在训练过程中无法有效学习。

二、Focal Loss的提出

为了解决上述问题,作者提出了Focal Loss,这是一种在标准交叉熵损失(Cross Entropy Loss)基础上进行改进的损失函数。Focal Loss通过引入两个参数:αt​(平衡因子)和γ(调制因子),来降低易分类样本的权重,使模型更加关注难分类样本。

Focal Loss的公式为:

其中,pt​是模型预测为真实类别的概率。

三、Focal Loss的优势

  1. 解决类别不均衡问题:通过调整αt​和γ的值,Focal Loss可以有效地平衡正负样本的权重,并降低易分类样本的权重,使模型更加关注难分类样本。
  2. 提高模型性能:在实验中,作者使用Focal Loss训练了一个名为RetinaNet的单阶段检测器,该检测器在保持单阶段检测器速度优势的同时,达到了与两阶段检测器相当的精度。
  3. 增强模型的泛化能力:Focal Loss允许模型在预测时承担一些风险,从而增强了模型的泛化能力。在处理小尺寸对象或癌症检测等任务时,这种特性尤为重要。

四、实验验证与结果

作者在COCO数据集上进行了实验,验证了Focal Loss的有效性。实验结果表明,在相同的网络结构和训练设置下,使用Focal Loss训练的RetinaNet在精度上超过了其他单阶段检测器,并与两阶段检测器相当。同时,作者还探索了不同αt​和γ值对模型性能的影响,并发现αt​=0.25和γ=2时效果最佳。

五、结论与展望

Focal Loss的提出为单阶段检测器提供了一种有效的解决方案,使其能够在保持速度优势的同时达到与两阶段检测器相当的精度。未来,随着目标检测技术的不断发展,Focal Loss有望在更多领域得到应用和推广。

参考文献

  • 《Focal Loss for Dense Object Detection》,Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He, Piotr Dollar, ICCV 2017。

yolov5实现focal loss

import torch.nn as nn
import torchclass FocalLoss(nn.Module):# Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)def __init__(self, loss_fcn, gamma=2.0, alpha=0.25):"""Initializes FocalLoss with specified loss function, gamma, and alpha values; modifies loss reduction to'none'."""super().__init__()self.loss_fcn = loss_fcn  # must be nn.BCEWithLogitsLoss()self.gamma = gammaself.alpha = alphaself.reduction = loss_fcn.reductionself.loss_fcn.reduction = "none"  # required to apply FL to each elementdef forward(self, pred, true):"""Calculates the focal loss between predicted and true labels using a modified BCEWithLogitsLoss."""loss = self.loss_fcn(pred, true)# p_t = torch.exp(-loss)# loss *= self.alpha * (1.000001 - p_t) ** self.gamma  # non-zero power for gradient stability# TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.pypred_prob = torch.sigmoid(pred)  # prob from logits# p_t pred_true 预测值贴近于标签真实值的概率,也就是难易样本# 当标签true=1,pred_prob->1,那么p_t->1;当标签true=0,pred_prob->0,那么p_t->1p_t = true * pred_prob + (1 - true) * (1 - pred_prob)# 正负样本系数 提高正样本对loss的贡献 true=1时正样本 alpha_factor=alpha,true=0时负样本,alpha_factor=1-alphaalpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)# 调制系数 难易分类样本 p_t趋于1时属于易分类样本,对loss贡献小,p_t趋于0时属于难分类样本,对loss贡献大modulating_factor = (1.0 - p_t) ** self.gammaloss *= alpha_factor * modulating_factorif self.reduction == "mean":return loss.mean()elif self.reduction == "sum":return loss.sum()else:  # 'none'return lossif __name__ == '__main__':# 假设的模型输出(logits)preds = torch.tensor([[3e-2, 32.1, 6e-4]], requires_grad=True)# 真实的标签true_value = torch.tensor([[0, 1, 0]], dtype=torch.float32)floss = FocalLoss(nn.BCEWithLogitsLoss(pos_weight=torch.tensor(1.0, device='cpu')))loss = floss(preds, true_value)print(loss)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/51026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于GitHub page和Hexo主题搭建个人博客(win)

1.安装git git官网下载地址:Git - Downloads (git-scm.com) (1)下载:进入官网,选择对应版本下载,得到.exe文件 (2)安装:打开.exe文件,进行如下操作 (3)安装好后,右击鼠标,点击显示…

Vue element ui分页组件示例

https://andi.cn/page/621615.html

从单个视频中重建3D场景——开启虚拟现实与数字孪生的新探索

在当今的科技前沿,人工智能与计算机视觉技术正在以前所未有的速度推动着虚拟现实(VR)、增强现实(AR)以及数字孪生(Digital Twin)领域的发展。其中,一项引人注目的研究方向是从单个视频中重建3D场景,这项技术不仅能够捕捉到场景的完整3D动态,还能处理复杂的遮挡问题,…

docker前端部署

挂载,把自己的目录位置,挂载到容器内的HTML

阿里服务器购买与java环境搭建 实践

【云服务器搭建与环境配置】 工作几年了,最近又买了个云服务器搭着玩一玩,在这里记录下搭建云服务器的过程,以及各种基础环境配置,可供初学者学习搭建云服务器的过程。 云服务器购买 这里作者搭建阿里云服务器,搭建…

Servlet1-Servlet程序、请求处理、继承体系

目录 什么是Servlet 手动实现Servlet程序 ​编辑url地址如何定位到Servlet程序去访问 Servlet的生命周期 ​编辑GET和POST请求的分发处理 通过继承HttpServlet类实现Servlet程序 IDEA菜单生成Servlet程序 Servlet类的继承体系 ServletConfig类 ServletContext类 什么…

【彩虹商城】虚拟发卡系统

运行环境: Nginx 1.22.1 Mysql5.7 PHP7.4 直接访问域名即可安装 [呵呵] 彩虹二次开发 拥有供货商系统 多余模板删除 保留一套商城,两套发卡 源码无后门隐患 已知存在的BUG修复 目前适用于卡密类型业务销售。 后续将会慢慢编写数卡权益类的对接&#xf…

神经网络的参数初始化【PyTorch】

文章目录 1、常见初始化方法2、代码2.1、导包:2.2、均匀分布随机初始化2.3、固定初始化2.4、全0初始化2.5、全1初始化2.6、正态分布随机初始化2.7、kaiming 初始化2.8、xavier 初始化2.9、完整代码 3、小节 🍃作者介绍:双非本科大三网络工程专…

科技云报道:算网筑基AI注智,中国联通如何讲出AI时代的“新故事”?

科技云报道原创。 AI从未停止进化,也从未停止给人类带来惊喜。 从ChatGPT代表的文生文、Dall-E代表的文生图,到Sora代表的文生视频,Suno为代表的文生音乐,生成式AI的“暴力美学”持续突破内容生产的天花板,大模型技术…

Pytorch基础:Tensor的view方法(非连续张量也可以使用view)

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 在Pytorch中,view是Tensor的一个重要方法,用于返回一个改变了形状,但数据和数据的顺序与原来一致的新张量,但是新张…

VSCode 解决 pylint 报错 No name QWidget in module PyQt5.QtWidgets

问题 启用了 VSCode 的 Pylint 插件, 即便 Python 环境中安装了 PyQt5, 也无法正确解析 PyQt5 的导入 PyQt5 底层代码是用 C/C 写的, pylint 默认不会深入解析 pylint doesn’t load any C extensions by default, because those can run arbitrary code. 解决 修改 Settings…

Spark实时(六):Output Sinks案例演示

文章目录 Output Sinks案例演示 一、​​​​​​​File sink 二、​​​​​​​​​​​​​​Memory Sink 三、​​​​​​​​​​​​​​Foreach Sink 1、​​​​​​​foreachBatch 2、​​​​​​​​​​​​​​foreach Output Sinks案例演示 当我们对流式…

kotlin协程-- 基础概念 ①|创建和使用

引言 首先先说一些相关概念 1.并发与并行 在操作系统中我们曾经学到过并发与并行 并发: 是同一个时刻只有一条指令在执行,其他指令没有再执行,但是由于CPU的时间片特别短,导致多个指令来回切换的时间间隔特别短,就好像是同一时间多条指令在执行。单核CPU与多核CPU都可以进…

【python】Python常见的面试题解析:深入探索与实践,助你少走弯路

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

若依ruoyi+AI项目二次开发(智能售货机运营管理系统)

(一) 帝可得 - 产品原型 - 腾讯 CoDesign (qq.com)

一些电脑的操作技巧,你知道吗?

我整理了几个电脑使用的实用技巧,能够帮你提升办公效率,一起来看看吧! 技巧一:反方向移动单元格 一般来讲,我们按下【Tab】键、【Enter】键的时候,会切换到右边或者下边的单元格,想要反向移动…

第2章 编译SDK

安装编译依赖 sudo apt-get update sudo apt-get install clang-format astyle libncurses5-dev build-essential python-configparser sconssudo apt-get install repo git ssh make gcc libssl-dev liblz4-tool \ expect g patchelf chrpath gawk texinfo chrpath diffstat …

董宇辉离职,我一点都不意外!只不过感觉来的太快

下面这张图,是我在半年多前写的一段随笔,没想到来的这么快! 碰巧的是今天中午,在开发者群里有两位老铁自曝,本以为能公司干到老,但公司却不给机会,已经不在是公司员工了。 最近,晓衡…

粗解React 和 Vue 的异同

相同点: 1、都使用虚拟 DOM【Virtural DOM】 Vue与React都使用了 Virtual DOM Diff算法, 不管是Vue的Template模板options api 写法, 还是React的Class或者Function写法,最后都是生成render函数,而render函数执行返回VNode(虚拟…

iOS collectionView 滑动出现空白

iOS collectionView 滑动出现空白 一个很常见的 banner 轮播,滑动的时候,有时候会出现空白,检查了下,发现代码没什么问题,上网查了也没啥结果,最后的解决方法是自定义layout解决 interface TMLoopViewLayo…