深度学习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()
具体做了什么的一个详细解释:
计算梯度:当你调用
loss.backward()
时,PyTorch会首先计算损失函数loss
关于其所有输入参数的梯度。在神经网络中,这些输入参数通常包括模型的权重和偏置(即模型的可训练参数)。梯度累积:对于每个可训练参数,PyTorch会计算其梯度,并将这些梯度累加到该参数的
.grad
属性中。这意味着,如果你多次调用loss.backward()
(在梯度被清零之前),梯度会被累加。这在你想要累积多个小批量(mini-batches)的梯度时很有用,但通常情况下,你需要在每次迭代后清零梯度,以避免梯度累积。不影响原始数据:
loss.backward()
只计算梯度,并不会改变模型参数(权重和偏置)的值。参数的更新通常是通过优化器(如SGD、Adam等)来完成的,这些优化器使用.grad
属性中的梯度来更新参数。图执行:在PyTorch中,计算图(computation graph)用于跟踪所有操作的顺序和依赖关系。当你调用
loss.backward()
时,PyTorch会遍历这个图,从损失函数开始,反向传播梯度直到到达所有可训练的参数。注意:为了正确计算梯度,你需要确保在调用
loss.backward()
之前,损失函数loss
的所有输入都是requires_grad=True
的。这通常意味着这些输入是模型的输出,而模型的参数(如权重和偏置)在初始化时自动设置为requires_grad=True
。梯度清零:在每次迭代或每个小批量之后,你需要使用
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
的计算过程大致如下:
Sigmoid 激活:首先,对模型的原始输出应用 Sigmoid 激活函数,将其映射到 (0, 1) 区间内,表示每个样本属于正类的概率。
二元交叉熵损失计算:然后,使用二元交叉熵损失函数计算模型预测概率与真实标签之间的差异。二元交叉熵损失函数的公式为:
[
\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 表示样本数量。
参数处理:根据
size_average
、reduce
和reduction
参数(在较新版本的 PyTorch 中,通常只使用reduction
参数),对损失值进行平均或求和操作。三、优点与特性
数值稳定性:由于内部集成了 Sigmoid 函数,
nn.BCEWithLogitsLoss
可以避免直接计算 log(1−p) 时的数值稳定性问题。梯度计算:它能够自动计算 Sigmoid 函数的梯度,减轻了开发者的负担,并有助于梯度在反向传播过程中的正确传递。
联合优化:因为 Sigmoid 函数是包含在损失函数内部的,所以可以与其他层一起进行端到端的联合优化,简化了模型的设计和训练过程。
处理样本不平衡:通过
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.BCEWithLogitsLoss
的pos_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
定义模型:确保你的模型输出层没有应用softmax或log-softmax。输出应该是未经归一化的logits。
定义损失函数:使用
torch.nn.CrossEntropyLoss
作为你的损失函数。前向传播和损失计算:将模型的输出(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)转换为概率分布,以便于进行类别的预测和损失的计算。
特点与优势
- 归一化:Softmax函数能够将任意实数值的向量转换为概率分布,这是其最重要的特点之一。
- 可解释性:由于输出是概率分布,因此Softmax函数的输出具有很好的可解释性,可以直观地表示每个类别的预测概率。
- 稳定性:在处理大数值时,Softmax函数可能会遇到数值稳定性问题(如数值溢出)。然而,通过一些技巧(如减去输入向量中的最大值)可以有效地缓解这个问题。
- 与交叉熵损失函数的结合: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)和目标标签(通常是整数),这个损失函数会:
- 对 logits 应用 softmax 函数以获取概率分布。
- 计算目标类别的负对数概率。
- 对所有样本的损失进行平均或求和(取决于
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
主要区别
- 应用场景:BCEloss专门用于二分类问题,而CrossEntropyLoss既可用于多分类问题,也可用于二分类问题(但在二分类问题中,两者本质上是等价的)。
- 计算细节:虽然两者在二分类问题中的计算公式相同,但在多分类问题中,CrossEntropyLoss需要考虑所有类别的预测和真实标签,而BCEloss则只关注两个类别(0和1)。
- 使用方式:在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的优势
- 解决类别不均衡问题:通过调整αt和γ的值,Focal Loss可以有效地平衡正负样本的权重,并降低易分类样本的权重,使模型更加关注难分类样本。
- 提高模型性能:在实验中,作者使用Focal Loss训练了一个名为RetinaNet的单阶段检测器,该检测器在保持单阶段检测器速度优势的同时,达到了与两阶段检测器相当的精度。
- 增强模型的泛化能力: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)
相关文章:

深度学习loss
pytorch模型训练demo代码 在PyTorch中,模型训练通常涉及几个关键步骤:定义模型、定义损失函数、选择优化器、准备数据加载器、编写训练循环。以下是一个简单的PyTorch模型训练演示代码,该代码实现了一个用于手写数字识别(使用MNIS…...
编写一个Chrome插件,网页选择文字后,右键出现菜单“search with bing”,选择菜单后用bing搜索文字
kimi ai 生成,测试可用,需要自行准备图标文件 创建一个简单的Chrome插件来实现选择文本后的搜索功能,你需要完成以下几个步骤: 创建插件的基础文件夹和文件: 创建一个文件夹用于存放插件的所有文件。在该文件夹中创建以…...
【算法】分割回文串
难度:中等 题目: 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1: 输入:s = “aab” 输出:[[“a”,“a”,“b”],[“aa”,“b”]] 示例 2: 输入:s = “a” 输出:[[“a”]] 提示: 1 <= s.length <…...
lua 游戏架构 之 游戏 AI (三)ai_attack
这段Lua脚本定义了一个名为 ai_attack 的类,继承自 ai_base 类。 lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读119次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的AI组件。例如,可以…...

大数据之Oracle同步Doris数据不一致问题
数据同步架构如下: 出现的问题: doris中的数据条数 源库中的数据条数 总数完全不一致。 出现问题的原因: 在Dinky中建立表结构时,缺少对主键属性的限制 primary key(ID) not enforced 加上如上语句,数据条数解决一致 …...

visual studio 问题总结
一. Visual Studio: 使用简体中文(GB2312)编码加载文件, 有些字节已用Unicode替换字符更换 解决方法:vs 工具-》选项-》文本编辑器...
go-错误码的最佳实践
一、背景 在工程开发中,我们有以下场景可以用错误码解决 我们不太方便直接将内部的错误原因暴露给外部,可以根据错误码得到对应的外部暴露消息通过设定错误码判断是客户端或者服务端的问题,避免不必要的排障浪费方便查找日志,定…...
Python面试题:使用Matplotlib和Seaborn进行数据可视化
使用Matplotlib和Seaborn进行数据可视化是数据分析中非常重要的一部分。以下示例展示了如何使用这两个库来创建各种图表,包括基本的线图、柱状图、散点图和高级的分类数据可视化图表。 安装 Matplotlib 和 Seaborn 如果你还没有安装这两个库,可以使用以…...

模拟实现c++中的vector模版
目录 一vector简述: 二vector的一些接口函数: 1初始化: 2.vector增长: 3vector增删查改: 三vector模拟实现部分主要函数: 1.size,capacity,empty,clear接口: 2.reverse的实现࿱…...
uniapp安卓通过绝对路径获取文件
uniapp安卓通过绝对路径获取文件 在uniapp中,如果你想要访问安卓设备上的文件,你需要使用uniapp提供的plus.io API。这个API允许你在应用内访问设备的文件系统。 以下是一个示例代码,展示了如何使用plus.io API来获取文件: fun…...
Known框架实战演练——进销存业务单据
本文介绍如何实现进销存管理系统的业务单据模块,业务单据模块包括采购进货单、采购退货单、销售出货单、销售退货单4个菜单页面。由于进销单据字段大同小异,因此设计共用一个页面组件类。 项目代码:JxcLite开源地址: https://git…...

解决npm依赖树冲突的方法以及npm ERR! code ERESOLVE错误的解决方案
一、问题描述 在使用ng new myapp --skip-install 构建Angular 项目后,尝试用npm install 安装依赖的时候报了以下错误。 (base) PS C:\Users\Administrator\Desktop\agtest\myapp> npm i npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependenc…...

Spring Boot + Spring Batch + Quartz 整合定时批量任务
博客主页: 南来_北往 系列专栏:Spring Boot实战 前言 最近一周,被借调到其他部门,赶一个紧急需求,需求内容如下: PC网页触发一条设备升级记录(下图),后台要定时批量设备更…...
C++STL简介(二)
目录 1.模拟实现string 1.string基本属性和大体框架 2.基本函数 2.1size() 2.2 [] 2.3 begin() 和end() 2.4capacity() 2.5 reserve 2.6push_back 2.7 append 2.8 2.9insert 2.10find 2.11substr 2.12 2.12 < …...
嵌入式高频面试题100道及参考答案(3万字长文)
目录 解释嵌入式系统的定义和主要特点 描述微处理器与微控制器的主要区别 什么是ARM体系结构?它在嵌入式系统中有哪些优势? 解释GPIO(通用输入输出)的工作原理 什么是ADC和DAC?它们在嵌入式系统中的作用是什么? 解释中断的概念及其在实时系统中的重要性 描述SPI(串…...

python爬虫-事件触发机制
今天想爬取一些政策,从政策服务 (smejs.cn) 这个网址爬取,html源码找不到链接地址,通过浏览器的开发者工具,点击以下红框 分析预览可知想要的链接地址的id有了,进行地址拼接就行 点击标头可以看到请求后端服务器的api地…...
LeetCode-day27-3106. 满足距离约束且字典序最小的字符串
LeetCode-day27-3106. 满足距离约束且字典序最小的字符串 题目描述示例示例1:示例2:示例3: 思路代码 题目描述 给你一个字符串 s 和一个整数 k 。 定义函数 distance(s1, s2) ,用于衡量两个长度为 n 的字符串 s1 和 s2 之间的距…...
C++中的static_cast函数
static_cast 是 C 中的一个类型转换操作符,用于在编译时进行类型转换。它主要用于基本数据类型之间的转换,以及类的指针或引用之间的向上转换(将派生类指针或引用转换为基类指针或引用)和某些情况下的向下转换(将基类指…...

从零开始学习网络安全渗透测试之基础入门篇——(二)Web架构前后端分离站Docker容器站OSS存储负载均衡CDN加速反向代理WAF防护
Web架构 Web架构是指构建和管理Web应用程序的方法和模式。随着技术的发展,Web架构也在不断演进。当前,最常用的Web架构包括以下几种: 单页面应用(SPA): 特点:所有用户界面逻辑和数据处理都包含…...
2679. 矩阵中的和
两种方法: 第一种:先对二维列表的每一列进行排序,然后对每一列的数据进行逐个比较,找出最大值。 class Solution:def matrixSum(self, nums: list[list[int]]) -> int:result0mlen(nums)nlen(nums[0])for i in range(m):nums…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...