做网站必须有框架么,手机网站 自适应屏幕,手机网站开发下拉刷新,网络技术服务pytorch模型训练demo代码 在PyTorch中#xff0c;模型训练通常涉及几个关键步骤#xff1a;定义模型、定义损失函数、选择优化器、准备数据加载器、编写训练循环。以下是一个简单的PyTorch模型训练演示代码#xff0c;该代码实现了一个用于手写数字识别#xff08;使用MNIS… 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, trainTrue, transformtransform, downloadTrue)
train_loader DataLoader(datasettrain_dataset, batch_size64, shuffleTrue) # 实例化模型、损失函数和优化器
model Net()
criterion nn.CrossEntropyLoss() # 多分类交叉熵损失
optimizer optim.SGD(model.parameters(), lr0.01, momentum0.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 (i1) % 100 0: print(fEpoch [{epoch1}/{num_epochs}], Step [{i1}/{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_gradTrue的。这通常意味着这些输入是模型的输出而模型的参数如权重和偏置在初始化时自动设置为requires_gradTrue。 梯度清零在每次迭代或每个小批量之后你需要使用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 个样本的预测概率。这个公式实际上是对每个样本的损失进行平均当 reductionmean 时也可以选择不平均当 reductionnone 时或求和当 reductionsum 时。 二元交叉熵适合作为损失函数来最小化它的值。对于输出概率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(reductionmean) # 默认reduction为mean # 模型预测结果需要经过sigmoid函数处理确保值在0到1之间
# 这里为了示例直接给出实际中应该是模型的输出
y_hat torch.tensor([0.2, 0.8, 0.6, 0.3], requires_gradTrue) # 真实标签
y torch.tensor([0, 1, 1, 0], dtypetorch.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_{i1}^{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_gradTrue) # 假设有10个样本每个样本的输出是一个实数
targets torch.randint(2, (10, 1), dtypetorch.float) # 目标标签0或1
print(inputs.view(1,-1))
print(targets.view(1,-1))
# 定义损失函数
criterion nn.BCEWithLogitsLoss() # 计算损失
loss criterion(inputs, targets) # 反向传播
loss.backward()
print(fLoss: {loss.item()})print(fGradients: {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_gradTrue)# 真实的标签注意这些应该是介于 0 和 1 之间的概率但在二元分类中我们通常使用 0 和 1
targets torch.tensor([[1, 0, 1], [0, 1, 0]], dtypetorch.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(reductionmean)(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_size10, num_classes3) # 定义损失函数
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, axis1, keepdimsTrue))return e_x / e_x.sum(axis1, keepdimsTrue)def cross_entropy_loss(logits, targets, reductionmean):模拟 PyTorch 的 nn.CrossEntropyLoss参数:- logits: 模型的原始输出形状为 (batch_size, num_classes)- targets: 目标标签形状为 (batch_size,)- reduction: 指定损失的计算方式mean 或 sum返回:- 损失值# 确保 logits 和 targets 都是 numpy 数组logits np.asarray(logits, dtypenp.float32)print(logits {}.format(logits))targets np.asarray(targets, dtypenp.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, reductionmean)
celoss nn.CrossEntropyLoss(reductionmean)
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和γ值对模型性能的影响并发现αt0.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(), gamma1.5)def __init__(self, loss_fcn, gamma2.0, alpha0.25):Initializes FocalLoss with specified loss function, gamma, and alpha values; modifies loss reduction tonone.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 预测值贴近于标签真实值的概率,也就是难易样本# 当标签true1,pred_prob-1,那么p_t-1;当标签true0,pred_prob-0,那么p_t-1p_t true * pred_prob (1 - true) * (1 - pred_prob)# 正负样本系数 提高正样本对loss的贡献 true1时正样本 alpha_factoralpha,true0时负样本alpha_factor1-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: # nonereturn lossif __name__ __main__:# 假设的模型输出logitspreds torch.tensor([[3e-2, 32.1, 6e-4]], requires_gradTrue)# 真实的标签true_value torch.tensor([[0, 1, 0]], dtypetorch.float32)floss FocalLoss(nn.BCEWithLogitsLoss(pos_weighttorch.tensor(1.0, devicecpu)))loss floss(preds, true_value)print(loss)