1. 损失函数概念
  2. 损失函数的创建和运行机制
  3. 各种损失函数

在前几篇文章中我们学习了模型模块中一些知识。我们了解了如何构建模型,然后对模型进行一个初始化。今天我们就开始进入下一个模块 损失函数。

一、损失函数

首先我们来看一下什么是损失函数。损失函数是衡量模型输出与真实标签之间的一个差异。
image.png
我们先来看上面这个示意图,就是一元线性回归的拟合过程。图中的绿色点是训练样本,蓝色的线是训练好的一个模型。在图中可以看到模型并没有很好去拟合到每一个数据点,也就是说我们的每一个数据点并没有在模型上。所以数据点会产生一个loss值。

通常我们在谈损失函数、loss的时候经常出现这三个概念。三者之间又有什么关系?他们的区别在哪里呢?

  • 损失函数(Loss Function)
    • 计算一个样本与预测结果的差异
    • 损失函数 - 图2
  • 代价函数(Cost Function)
    • 计算整个样本集Loss的平均值
    • 损失函数 - 图3
  • 目标函数(Objective Function)
    • 代价函数 + 正则项
    • 损失函数 - 图4

在我们继续学习模型训练当中,目标函数是我们最终的一个目标。通常目标函数包含代价函数和正则项。代价函数衡量模型输出与真实标签之间的差异,也是希望模型的输出和真实标签差异要更小一些,要更接近真实标签。那么是不是我们这个代价函数越小越好了。其实并不是,因为有时候会过拟合了。
image.png
假如我们来看上面示意图,假如有这么一个模型很好的拟合每一个数据点,所以代价函数已经很小了,达到最小值是0,但是这个模型并不是个好的模型。这就是模型太复杂,导致模型过拟合。

所以我们在追求模型输出与真实标签之间差异比较小的时候,同时也要对这个模型做一些限制,做一些约束。

而在机器学习中约束的项,我们就称之为正则项 regulation 。通常我们会采用了L1、L2两个正则项加载代价函数之后就构成了我们整个目标函数。所以通常我们的目标函数是包含了两项:一项是我们希望模型的输出与真实标签之间差异要小一些;第二项是这种模型进行一定的约束,常用的约束有L1、L2约束,或是稀疏约束等等。

这就是损失函数,代价函数和目标函数的一个关系。在这里我们不失一般性的,我们后面都会用损失函数来代替代价函数。也就是我们去衡量模型输出与真实标签之间的差异的时候,我们都通通称之为loss称为损失函数。

  1. class _Loss(Module):
  2. def __init__(self, size_average=None, reduce=None,reduction='mean'):
  3. super(_Loss, self).__init__()
  4. if size_average is not None or reduce is not None:
  5. self.reduction = _Reduction.legacy_get_string(
  6. size_average, reduce)
  7. else:
  8. self.reduction = reduction

PyTorch 中的 _Loss类 继承 Module类 ,所以说loss可以相当于是一个网络层。 __init__ 初始化函数当中有3个参数,其中 size_averagereduce 是会被舍弃了两个参数。所以大家千万不要再去使用这两个参数。因为它俩的功能在 reduction 当中完全可以实现 nonesummean 三种模式。首先我们来看一下 __init__函数 的内部实现,其实只是去构建了 self.reductionsize_averagereduce 不需要再去关注。

二、损失函数的创建和运行机制

下面通过代码演示交叉熵损失函数是怎么创建的、及其使用流程和机制。

import os
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
import torch.optim as optim
from matplotlib import pyplot as plt
from model.lenet import LeNet
from tools.my_dataset import RMBDataset
from tools.common_tools import transform_invert, set_seed

set_seed(1)  # 设置随机种子
rmb_label = {"1": 0, "100": 1}

# 参数设置
MAX_EPOCH = 10
BATCH_SIZE = 16
LR = 0.01
log_interval = 10
val_interval = 1

# ============================ step 1/5 数据 ============================
train_dir = "H:/PyTorch_From_Zero_To_One/data/rmb_split/train"
valid_dir = "H:/PyTorch_From_Zero_To_One/data/rmb_split/valid"

norm_mean = [0.485, 0.456, 0.406]
norm_std = [0.229, 0.224, 0.225]

train_transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.RandomCrop(32, padding=4),
    transforms.RandomGrayscale(p=0.8),
    transforms.ToTensor(),
    transforms.Normalize(norm_mean, norm_std),
])

valid_transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.ToTensor(),
    transforms.Normalize(norm_mean, norm_std),
])

# 构建MyDataset实例
train_data = RMBDataset(data_dir=train_dir, transform=train_transform)
valid_data = RMBDataset(data_dir=valid_dir, transform=valid_transform)

# 构建DataLoder
train_loader = DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
valid_loader = DataLoader(dataset=valid_data, batch_size=BATCH_SIZE)

# ============================ step 2/5 模型 ============================

net = LeNet(classes=2)
net.initialize_weights()

# ============================ step 3/5 损失函数 ============================
loss_functoin = nn.CrossEntropyLoss()                                                   # 选择损失函数

# ============================ step 4/5 优化器 ============================
optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9)                        # 选择优化器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)     # 设置学习率下降策略

# ============================ step 5/5 训练 ============================
train_curve = list()
valid_curve = list()

for epoch in range(MAX_EPOCH):

    loss_mean = 0.
    correct = 0.
    total = 0.

    net.train()
    for i, data in enumerate(train_loader):

        # forward
        inputs, labels = data
        outputs = net(inputs)

        # backward
        optimizer.zero_grad()
        loss = loss_functoin(outputs, labels)
        loss.backward()

        # update weights
        optimizer.step()

        # 统计分类情况
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).squeeze().sum().numpy()

        # 打印训练信息
        loss_mean += loss.item()
        train_curve.append(loss.item())
        if (i+1) % log_interval == 0:
            loss_mean = loss_mean / log_interval
            print("Training:Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
                epoch, MAX_EPOCH, i+1, len(train_loader), loss_mean, correct / total))
            loss_mean = 0.

    scheduler.step()  # 更新学习率

    # validate the model
    if (epoch+1) % val_interval == 0:

        correct_val = 0.
        total_val = 0.
        loss_val = 0.
        net.eval()
        with torch.no_grad():
            for j, data in enumerate(valid_loader):
                inputs, labels = data
                outputs = net(inputs)
                loss = loss_functoin(outputs, labels)

                _, predicted = torch.max(outputs.data, 1)
                total_val += labels.size(0)
                correct_val += (predicted == labels).squeeze().sum().numpy()

                loss_val += loss.item()

            valid_curve.append(loss_val)
            print("Valid:\t Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
                epoch, MAX_EPOCH, j+1, len(valid_loader), loss_val, correct / total))


train_x = range(len(train_curve))
train_y = train_curve

train_iters = len(train_loader)
valid_x = np.arange(1, len(valid_curve)+1) * train_iters*val_interval # 由于valid中记录的是epochloss,需要对记录点进行转换到iterations
valid_y = valid_curve

plt.plot(train_x, train_y, label='Train')
plt.plot(valid_x, valid_y, label='Valid')

plt.legend(loc='upper right')
plt.ylabel('loss value')
plt.xlabel('Iteration')
plt.show()

# ============================ inference ============================

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.join(BASE_DIR, "test_data")

test_data = RMBDataset(data_dir=test_dir, transform=valid_transform)
valid_loader = DataLoader(dataset=test_data, batch_size=1)

for i, data in enumerate(valid_loader):
    # forward
    inputs, labels = data
    outputs = net(inputs)
    _, predicted = torch.max(outputs.data, 1)

    rmb = 1 if predicted.numpy()[0] == 0 else 100

    img_tensor = inputs[0, ...]  # C H W
    img = transform_invert(img_tensor, train_transform)
    plt.imshow(img)
    plt.title("LeNet got {} Yuan".format(rmb))
    plt.show()
    plt.pause(0.5)
    plt.close()

还是使用二分类模型代码,在58行和83行设置断点。
debug代码,第58行停止,来到 CrossEntropyLoss类 ,是继承的一个 _WeightedLoss类

class CrossEntropyLoss(_WeightedLoss):
    __constants__ = ['ignore_index', 'reduction']

    def __init__(self, weight=None, size_average=None, ignore_index=-100,
                 reduce=None, reduction='mean'):
        super(CrossEntropyLoss, self).__init__(weight, size_average, reduce, reduction)
        self.ignore_index = ignore_index

    def forward(self, input, target):
        return F.cross_entropy(input, target, weight=self.weight,
                               ignore_index=self.ignore_index, reduction=self.reduction)

继续step into,来到了 _WeightedLoss类 ,该类继承了 _Loss类

class _WeightedLoss(_Loss):
    def __init__(self, weight=None, size_average=None, reduce=None, reduction='mean'):
        super(_WeightedLoss, self).__init__(size_average, reduce, reduction)
        self.register_buffer('weight', weight)

继续step into,来到了 _Loss类 ,该类继承了 Module类,所以loss函数是一个Module,同样拥有8个有序字典

class _Loss(Module):
    def __init__(self, size_average=None, reduce=None, reduction='mean'):
        super(_Loss, self).__init__()
        if size_average is not None or reduce is not None:
            self.reduction = _Reduction.legacy_get_string(size_average, reduce)
        else:
            self.reduction = reduction

step over 到第4行代码,这时候构建了交叉熵损失
image.png
之后一步步step out,就构建完成了一个交叉熵损失
image.png
构建完成交叉熵损失之后,我们是在训练过程中,模型forward得到output之后,采用lossfunction来衡量output和label之间的差异,直接运行到83行代码。继续step into查看交叉熵损失函数的运行机制。

刚从交叉熵损失函数的构建过程中发现,交叉熵损失函数是一个module,一个模型模块必须进行forward操作,所以step into之后,到达 module.py 中的 Module类 中的 __call__函数 来调用 forward 操作。

class Module(object):
    ...
    def __call__(self, *input, **kwargs):
        for hook in self._forward_pre_hooks.values():
            result = hook(self, input)
            if result is not None:
                if not isinstance(result, tuple):
                    result = (result,)
                input = result
        if torch._C._get_tracing_state():
            result = self._slow_forward(*input, **kwargs)
        else:
            result = self.forward(*input, **kwargs)
        for hook in self._forward_hooks.values():
            hook_result = hook(self, input, result)
            if hook_result is not None:
                result = hook_result
        if len(self._backward_hooks) > 0:
            var = result
            while not isinstance(var, torch.Tensor):
                if isinstance(var, dict):
                    var = next((v for v in var.values() if isinstance(v, torch.Tensor)))
                else:
                    var = var[0]
            grad_fn = var.grad_fn
            if grad_fn is not None:
                for hook in self._backward_hooks.values():
                    wrapper = functools.partial(hook, self)
                    functools.update_wrapper(wrapper, hook)
                    grad_fn.register_hook(wrapper)
        return result

运行到13行之后,step into到 CrossEntropyLoss类 中的 forward函数

class CrossEntropyLoss(_WeightedLoss):
    __constants__ = ['ignore_index', 'reduction']

    def __init__(self, weight=None, size_average=None, ignore_index=-100,
                 reduce=None, reduction='mean'):
        super(CrossEntropyLoss, self).__init__(weight, size_average, reduce, reduction)
        self.ignore_index = ignore_index

    def forward(self, input, target):
        return F.cross_entropy(input, target, weight=self.weight,
                               ignore_index=self.ignore_index, reduction=self.reduction)

step into 到 functional.py 文件中的 cross_entropy 函数,在这里进行了交叉熵损失的计算。

def cross_entropy(input, target, weight=None, size_average=None, ignore_index=-100,
                  reduce=None, reduction='mean'):
    if not torch.jit.is_scripting():
        tens_ops = (input, target)
        if any([type(t) is not Tensor for t in tens_ops]) and has_torch_function(tens_ops):
            return handle_torch_function(
                cross_entropy, tens_ops, input, target, weight=weight,
                size_average=size_average, ignore_index=ignore_index, reduce=reduce,
                reduction=reduction)
    if size_average is not None or reduce is not None:
        reduction = _Reduction.legacy_get_string(size_average, reduce)
    return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)

然后一步步的返回,会得到一个loss损失值。
image.png
以上就是Loss Function 的构建和运行过程。

二、各种损失函数

01. nn.CrossEntropyLoss()

nn.CrossEntropyLoss(
    weight=None,
    size_average=None, # 放弃使用
    ignore_index=-100,
    reduce=None,  # 放弃使用
    reduction='mean')

功能:nn.LogSoftmax()nn.NLLLoss() 结合,进行交叉熵计算
主要参数:

  • weight :各类别的loss设置权值
  • ignore_index :忽略某个类别
  • reduction :计算模式,可为 none / sum / mean
    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,返回标量

下面我们来详细的学习 CrossEntropyLoss 。我们首先来看一下它的功能是怎么样的。功能:nn.LogSoftmax()nn.NLLLoss() 结合,进行交叉熵计算。这里需要注意的是,这一个函数呢并不是真正意义上的一个交叉熵函数计算,而是有一些不同之处。不同之处就是在于他采用了一个 softmax 对我们的数据进行了归一化,把我们的数据值归一化到一个概率输出的形式0~1分布。这是因为交叉熵损失函数常用于分类任务当中,分类任务当中我们的输出通常是以概率值为主的。所以我们交叉熵其实他是衡量两个概率分布之间的差异,所以交叉熵值越低,也就是表示两个分布越近。

那为什么交叉熵值越低,这两个概率越相似呢?这就要从他与相对熵之间的关系说起。要提到相对熵与交叉熵,那就不得不提到信息熵。下面我们来分析交叉熵、相对熵和信息熵这三者之间的关系。这三者之间关系是:交叉熵 = 信息熵 + 相对熵。

下面我们一步步来看 交叉熵 = 信息熵 + 相对熵。首先我们先来看最基本的熵的概念,熵准确来说应该叫做信息熵。他是由信息论之父香农是从热力学的概念当中借鉴而来的一个名词。熵是用来描述一个事件的不确定性。有个事件越不确定他熵值越大,比如说 明天会下雨 这个事件的熵就会比 明天太阳会升起 这个事件的熵要大。下面我们来看信息熵的计算公式是这样的:
熵:损失函数 - 图9
它是自信息的一个期望。所以我们再来了解什么是自信息。自信心是用于衡量单个输出单个事件的不确定性。它的公式如下:
自信息:损失函数 - 图10
所以他是对概率取 负的log() 。明天下雨的概率是 0.3 ,那么明天下雨的自信息就是 -log0.3

而信息熵是整个概率分布的一个不确定性,它是用来描述整个概率的分布,所以要对自信息损失函数 - 图11求期望。我们看到信息熵公式如下:
熵:损失函数 - 图12

为了更好理解一个信息熵的大小的关系与事件不确定性的关系,我们来看一个示意图。
image.png
这是一个伯努利两点分布的一个信息熵。当事件的概率值是 0.5 的时候,其信息熵最大。也就是在概率是 0.5 的时候,他的不确定性是最大的,最大值应该是在 0.69 。如果训练过二分类模型的同学应该知道 0.69 这个数字,会在loss值中经常碰到该数字。因为有时候模型训练坏了的时候,我们的模型不管怎样去迭代loss值都恒定在 0.69 。还有在模型第一次初始化,第一个 iteration 的时候, loss 值也很可能就是 0.69 。该值表示模型当前是不具备任何判别能力的,因为该模型对任意输入,输出概率值都为0.5。这就是信息熵的一个概念,用来描述信息的不确定性,事件越不确定,熵值就越大。

下面我们来看相对熵,又被称为KL散度,它是用来衡量两个分布之间的差异,也就两个分布之间的距离。但是我们需要注意,它虽然是可以计算两个分布之间的距离,但它不是一个距离的函数,距离函数他有一个对称性。比如是p到q的距离,要等于q到p的距离,这才是一个距离函数。但是我们的相对熵不具备这个对称性。我们可以看一下它的公式。
损失函数 - 图14
P 是真实的分布,而 Q 是模型输出的分布。这个我们需要用 Q 的分布去拟合、去逼近 P 的真实分布,所以它这是不具备一个对称性的。

而现在我们来看一下交叉熵的公式
交叉熵:损失函数 - 图15
下面我们对相对熵的公式进行推导变化。
损失函数 - 图16
损失函数 - 图17
我们再来观察这一个公式。 P 是真实的一个概率分布,也就是训练集中我们的样本的分布;而 Q 是模型输出的一个分布。所以在机器学习模型当中,优化交叉熵等价于优化相对熵。为什么呢?我们看到等号右边这个损失函数 - 图18也就是 P 的信息熵,因为训练集是固定的,所以 P 的信息熵是一个常数,因为这个概率分布是固定的,所以他的信息熵是一个常数,所以我们在做优化的时候,常数是可以忽略掉的。所以等号两边做优化,优化交叉熵等价于优化相对熵。

公式如下:
交叉熵 = 信息熵 + 相对熵
交叉熵:损失函数 - 图19
自信息:损失函数 - 图20
熵:损失函数 - 图21
相对熵:损失函数 - 图22
损失函数 - 图23
损失函数 - 图24
损失函数 - 图25

交叉熵是衡量两个分布之间这个距离一个差异。所以我们就应该知道为什么要采用 softmax 。因为 softmax 可以将输出值,将数据值转换、归一化到一个概率取值范围,也就是0到1之间。然后再通过 log 以及 NLLLoss 来计算的交叉熵。下面我们来看一下这个交叉熵中的计算公式是这样的。
image.png
loss接受的是x(输出的概率值)和 class 类别值。第二行公式中的第二个括号中就是softmax操作,将这一个神经元的输出值归一化到0~1的概率取值区间,然后在取负号进行log操作,完成交叉熵损失计算。

对比上图中第一行公式(交叉熵定义),还应该有损失函数 - 图27,在公式计算的时候却没有。因为我们这个样本已经取出来的,所以我们样本的概率为1,损失函数 - 图28这一项是等于1的,就可以省略计算。

我们在训练过程中只是计算一个样本的loss,所以损失函数 - 图29也不需要计算。所以最终我们公式就变成了损失函数 - 图30。因为我们的模型输出不会服从概率分布的形式,所以我们需要用一个 softmax 把输出值归一化到0~1的概率取值区间。

主要参数:

  • weight :设置各类别的loss设置权值

image.png

02. nn.NLLLoss()

nn.NLLLoss(
    weight=None,
    size_average=None,
    ignore_index=-100,
    reduce=None,
    reduction='mean')

功能:实现负对数似然函数中的负号功能
主要参数:

  • weight :各类别的loss设置权值
  • ignore_index :忽略某个类别
  • reduction :计算模式,可为 none / sum / mean
    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean -加权平均,返回标量

03. nn.BCELoss()

nn.BCELoss(
    weight=None,
    size_average=None,
    reduce=None,
    reduction='mean’)

功能:二分类交叉熵
计算公式:
损失函数 - 图32
注意事项:输入值取值在[0,1]
主要参数:

  • weight :各类别的loss设置权值
  • ignore_index :忽略某个类别
  • reduction :计算模式,可为 none / sum / mean
    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,返回标量

04. nn.BCEWithLogitsLoss()

nn.BCEWithLogitsLoss(
    weight=None,
    size_average=None,
    reduce=None, reduction='mean',
    pos_weight=None)

功能:结合Sigmoid与二分类交叉熵
计算公式:
损失函数 - 图33
注意事项:网络最后不加sigmoid函数
主要参数:

  • pos_weight :正样本的权值
  • weight :各类别的loss设置权值
  • ignore_index :忽略某个类别
  • reduction :计算模式,可为 none / sum / mean

    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,返回标量

      05. nn.L1Loss()nn.MSELoss()

      nn.L1Loss(size_average=None, reduce=None, reduction='mean’)
      nn.MSELoss(size_average=None, reduce=None, reduction='mean’)
      
      nn.L1Loss() 功能: 计算inputs与target之差的绝对值
      nn.MSELoss() 功能: 计算inputs与target之差的平方
      主要参数:
  • reduction :计算模式,可为 none / sum / mean

    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,返回标量

      06. nn.SmoothL1Loss()

      nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean’)
      
      功能:平滑的L1Loss
      计算公式:
      损失函数 - 图34
      损失函数 - 图35
      image.png
      主要参数:
  • reduction :计算模式,可为 none / sum / mean

    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,

      06. nn.PoissonNLLLoss()

      nn.PoissonNLLLoss(
      log_input=True, full=False,
      size_average=None, eps=1e-08, reduce=None,
      reduction='mean')
      
      功能:泊松分布的负对数似然损失函数
      主要参数:
  • log_input :输入是否为对数形式,决定计算公式

    • True:loss(input, target) = exp(input) - target * input
    • False:loss(input, target) = input - target * log(input+eps)
  • full :计算所有loss,默认为False
  • eps :修正项,避免log(input)为nan

07. nn.KLDivLoss()

nn.KLDivLoss(size_average=None, reduce=None, reduction='mean'

功能:计算KLD(divergence),KL散度,相对熵
注意事项:需提前将输入计算log-probabilities,如通过nn.logsoftmax()
计算公式:
损失函数 - 图37
损失函数 - 图38
主要参数:

  • reduction :none/sum/mean/batchmean

    • batchmean :- batchsize维度求平均值
    • none - 逐个元素计算
    • sum - 所有元素求和,返回标量
    • mean - 加权平均,返回标量

      08. nn.MarginRankingLoss()

      nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')
      
      功能:计算两个向量之间的相似度,用于排序任务
      特别说明:该方法计算两组数据之间的差异,返回一个n*n 的 loss 矩阵
      计算公式:
      损失函数 - 图39
      主要参数:
  • margin :边界值,x1与x2之间的差异值

  • reduction :计算模式,可为none/sum/mean

当y = 1时,希望x1比x2大,当x1>x2时,不产生loss
当y = -1时,希望x2比x1大,当x2>x1时,不产生loss

09. nn.MultiLabelMarginLoss()

nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean')

功能:多标签边界损失函数
举例:四分类任务,样本x属于0类和3类, 标签:[0, 3, -1, -1] , 不是[1, 0, 0, 1]
计算公式:
损失函数 - 图40
损失函数 - 图41
主要参数:

  • reduction :计算模式,可 none / sum / mean

    10. nn.SoftMarginLoss()

    nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')
    

    功能:计算二分类的logistic损失
    计算公式:
    损失函数 - 图42
    主要参数:

  • reduction :计算模式,可为 none / sum / mean

    11. nn.MultiLabelSoftMarginLoss()

    nn.MultiLabelSoftMarginLoss(weight=None, size_average=None, reduce=None, reduction='mean')
    

    功能:SoftMarginLoss多标签版本
    计算公式:
    损失函数 - 图43
    主要参数:

  • weight :各类别的loss设置权值

  • reduction :计算模式,可为 none / sum / mean

    12. nn.MultiMarginLoss()

    nn.MultiMarginLoss(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction='mean')
    

    功能:计算多分类的折页损失
    计算公式:
    损失函数 - 图44
    损失函数 - 图45
    主要参数:

  • p :可选1或2

  • weight:各类别的loss设置权值
  • margin:边界值
  • reduction :计算模式,可为 none / sum / mean

    13. nn.TripletMarginLoss()

    nn.TripletMarginLoss(
      margin=1.0, p=2.0, eps=1e-06,
      swap=False, size_average=None, reduce=None,
      reduction='mean')
    

    功能:计算三元组损失,人脸验证中常用
    image.png
    计算公式:
    损失函数 - 图47
    损失函数 - 图48
    主要参数:

  • p :范数的阶,默认为2

  • margin :边界值
  • reduction :计算模式,可为 none / sum / mean

    14. nn.HingeEmbeddingLoss()

    nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction='mean’)
    

    功能:计算两个输入的相似性,常用于非线性embedding和半监督学习
    特别注意:输入x应为两个输入之差的绝对值
    计算公式:
    损失函数 - 图49
    主要参数:

  • margin:边界值

  • reduction :计算模式,可为 none / sum / mean

    15. nn.CosineEmbeddingLoss()

    nn.CosineEmbeddingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')
    

    功能:采用余弦相似度计算两个输入的相似性
    计算公式:
    损失函数 - 图50
    损失函数 - 图51
    主要参数:

  • margin :可取值[-1, 1] , 推荐为[0, 0.5]

  • reduction :计算模式,可为 none / sum / mean

    16. nn.CTCLoss()

    ```python torch.nn.CTCLoss(blank=0, reduction=’mean’, zero_infinity=False)

``` 功能:计算CTC损失,解决时序类数据的分类 Connectionist Temporal Classification
主要参数:

  • blank :blank label
  • zero_infinity :无穷大的值或梯度置0
  • reduction :计算模式,可为 none / sum / mean

    参考文献: A. Graves et al.: Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks

总结

  1. nn.CrossEntropyLoss
  2. nn.NLLLoss
  3. nn.BCELoss
  4. nn.BCEWithLogitsLoss
  5. nn.L1Loss
  6. nn.MSELoss
  7. nn.SmoothL1Loss
  8. nn.PoissonNLLLoss
  9. nn.KLDivLoss
  10. nn.MarginRankingLoss
  11. nn.MultiLabelMarginLoss
  12. nn.SoftMarginLoss
  13. nn.MultiLabelSoftMarginLoss
  14. nn.MultiMarginLoss
  15. nn.TripletMarginLoss
  16. nn.HingeEmbeddingLoss
  17. nn.CosineEmbeddingLoss
  18. nn.CTCLoss