1. Введение в функцию потерь
Функция потерь, также известная как целевая функция, представляет собой функцию, используемую для вычисления разницы между истинным значением и прогнозируемым значением, а оптимизатор является важным элементом при составлении модели нейронной сети. Потеря должна быть скаляром, потому что векторы нельзя сравнивать по размеру (сами векторы нужно сравнивать по скалярам, таким как норма). Функции потерь обычно делятся на 4 типа: функция потерь HingeLoss 0-1, функция потерь абсолютного значения, функция квадратичных потерь и функция логарифмических потерь.
Суть функции потерь
у любого естьПотеря, состоящая из отрицательного логарифмического правдоподобияОба являются перекрестной энтропией между эмпирическим распределением, определенным в обучающей выборке, и распределением вероятностей, определенным в модели. Например, среднеквадратическая ошибка — это перекрестная энтропия между эмпирическим распределением и моделью Гаусса.
Сначала мы определяем прогнозируемое значениеsample
и целевое значениеtarget
, а затем использовать различные функции потерь для расчета значения потерь.
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
sample = Variable(torch.ones(2,2))
target = Variable(torch.tensor([[0,1],[2,3]]))
Стоимость выборки:tensor([[1., 1.], [1., 1.]])
.
Значение цели равно:tensor([[0, 1], [2, 3]])
.
2. Потеря абсолютного значения Потеря L1
2.1 nn.L1Loss
L1Loss берет среднее значение абсолютных ошибок прогнозируемых и истинных значений для регрессии.
criterion = nn.L1Loss(reduction='mean')
loss = criterion(sample, target)
print(loss)
оказаться:1
.L1Loss
также поддерживаетreduction=sum
.
2.2 nn.SmoothL1Loss
SmoothL1Loss также называется Huber Loss, ошибка представляет собой квадрат потери на (-1,1), в противном случае это потеря L1, применяемая к регрессии.
criterion = nn.SmoothL1Loss()
loss = criterion(sample, target)
print(loss)
Окончательный результат:0.625
.
Зачем использовать потерю Хубера?
Результатом квадрата потерь L2 является несмещенная оценка среднего арифметического, а результатом функции потерь L1 является несмещенная оценка медианы.
Однако на квадрат потерь легко влияют выбросы. Потери Хьюбера сильно выпуклы вблизи 0, сочетая в себе преимущества квадратичных потерь и потерь абсолютного значения.
3. Квадрат потери MSE Loss
3.1 nn.MSELoss
Функция квадрата потерь, вычисляющая среднее значение суммы квадратов между прогнозируемым и истинным значениями, используемая для регрессии.
criterion = nn.MSELoss(reduction='mean')
loss = criterion(sample, target)
print(loss)
Окончательный результат:1.5
.
4. Потеря журнала — перекрестная энтропия
4.1 nn.CrossEntropyLoss
Функция потерь перекрестной энтропии описывает расстояние между фактическим выходом (вероятностью) и ожидаемым распределением выхода (вероятности), то есть чем меньше значение перекрестной энтропии, тем дваЧем ближе распределение вероятностей.
Потеря CE используется для классификации.
Определение класса CrossEntropyLoss
import numpy as np
class CrossEntropyLoss():
def __init__(self, weight=None, size_average=True):
"""
初始化参数,因为要实现 torch.nn.CrossEntropyLoss 的两个比较重要的参数
:param weight: 给予每个类别不同的权重
:param size_average: 是否要对 loss 求平均
"""
self.weight = weight
self.size_average = size_average
def __call__(self, input, target):
"""
计算损失
这个方法让类的实例表现的像函数一样,像函数一样可以调用
:param input: (batch_size, C),C是类别的总数
:param target: (batch_size, 1)
:return: 损失
"""
batch_loss = 0.
for i in range(input.shape[0]):
numerator = np.exp(input[i, target[i]]) # 分子
denominator = np.sum(np.exp(input[i, :])) # 分母
# 计算单个损失
loss = -np.log(numerator / denominator)
if self.weight:
loss = self.weight[target[i]] * loss
# 损失累加
batch_loss += loss
# 整个 batch 的总损失是否要求平均
if self.size_average == True:
batch_loss /= input.shape[0]
return batch_loss
Формула для CE:
в,вес разных классов, по умолчанию 1.
должен быть в курсе,входитьinput
Требование логит (вывод модели без softmax),target
Категория, соответствующая образцу, тензор длинного типа (int64 бит).
import torch
sample = torch.tensor([[2.0,3],[1,3]])
target = torch.tensor([0,1])
criterion = nn.CrossEntropyLoss(reduction='mean')
loss = criterion(sample, target)
print(loss)
Вывод:tensor(0.7201)
Приведенная выше целевая информация CEloss используется в качестве индекса, который не совпадает с общеизвестной перекрестной энтропией:
Следующий вывод доказывает, что CELoss иОба эквивалентны. Использование numpy для этого:
import numpy as np
def labelEncoder(y):
nClass = max(y)+1
tmp = np.zeros(shape = (y.shape[0], nClass))
for i in range(y.shape[0]):
tmp[i][y[i]] = 1
return tmp
def softmax(x):
print('exp',np.exp(x))
print('sum',np.sum(np.exp(x),axis=1,keepdims=True))
return np.exp(x)/np.sum(np.exp(x),axis=1,keepdims=True)
def crossEntropy(pred_logit, target):
'''
需要注意,这里只是计算一个样本的CE,如果样本数不为1,一般是需要除于样本数的.
'''
target = labelEncoder(target)
pred = softmax(pred_logit)
H = np.mean(np.sum(-target*np.log(pred),axis=1))
return H
pred_logit = np.array([[2.0,3],[1,3]])
target = np.array([0,1])
H = crossEntropy(pred_logit, target)
print("H",H)
вывод:
H 0.7200948492805976
Правильно! Оглядываясь назад, формула
Здесь класс является индексом (вызовnn.CrossEntropyLoss
Примечание), здесьSoftmax
попрошайничествоp
иylog(p)
Я написал это вместе, но я не ответил сначала.
4.2 nn.BCELoss
Двоичная перекрестная энтропияВ случае двух распределений расчетная потеря больше, чем перекрестная энтропия (поскольку включена перекрестная энтропия положительного и отрицательного классов). Формула расчета:
интерфейс:torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
Определение класса потерь BCE:
class BCELoss(_WeightedLoss):
r"""
Examples::
>>> m = nn.Sigmoid()
>>> loss = nn.BCELoss()
>>> input = torch.randn(3, requires_grad=True)
>>> target = torch.empty(3).random_(2)
>>> output = loss(m(input), target)
>>> output.backward()
"""
__constants__ = ['reduction', 'weight']
def __init__(self, weight=None, size_average=None, reduce=None, reduction='mean'):
super(BCELoss, self).__init__(weight, size_average, reduce, reduction)
def forward(self, input, target):
return F.binary_cross_entropy(input, target, weight=self.weight, reduction=self.reduction)
input
Ввод представляет собой значение логита после сигмоида;target
является вектором, а элементы вектора принимают значение 0 или 1, здесьнетГорячая форма, конкретное понимание того, принадлежит ли образец к определенной этикетке. Например, есть только два типа,target
возможно[[1],[0]]
, что означает, что первая выборка является положительным классом, вторая выборка — антиклассом, а соответствующийinput
размерность(2,1)
.target
возможно[[1,0],[0,0]]
, что означает, что первый образец принадлежит первой метке, но не принадлежит второй метке, а второй образец не принадлежит ни первой, ни второй метке.
BCE можно применять для задач классификации с несколькими метками.
Пример: В качестве примера возьмем две этикетки, то есть образец может состоять из двух этикеток.
sample = torch.tensor([[2.0,3.0],[1,3]])
target = torch.tensor([0,1])
one_hot_target = torch.zeros(target.shape[0], max(target)+1)
one_hot_target[torch.arange(target.shape[0]), target] = 1
sigmoid_input = torch.sigmoid(sample)
print('sigmoid_input',sigmoid_input)
print('one_hot_target',one_hot_target)
criterion = nn.BCELoss()
loss = criterion(sigmoid_input, one_hot_target)
print('bce',loss)
результат операции:
sigmoid_input:
tensor([[0.8808, 0.9526],
[0.7311, 0.9526]])
one_hot_target:
tensor([[1., 0.],
[0., 1.]])
bce tensor(1.1343)
Ручной расчет: Каждая выборка BCE Loss будет усреднена; наконец, потеря должна быть в количестве выборок.
a = -(1*np.log(sigmoid_input[0][0]) + np.log(1-sigmoid_input[0][1]))/2
b = -(np.log(1-sigmoid_input[1][0]) + 1*np.log(sigmoid_input[1][1]))/2
print('cal bce',(a+b)/2)
результат:cal bce tensor(1.1343)
4.3 nn.NLLLoss
Функция потери отрицательного логарифмического правдоподобия (отрицательное логарифмическое правдоподобие), также используемая для классификации. Определение потери NLL:
По сравнению с CrossEntropy Loss, потеря NLL требует вводаinput
даlogit
проходить черезLogSoftmax
Обработанное значение, вход потери CElogit
; обаtarget
все скалярные значения.
LogSoftmax
определяется как:
Пример:
# NLL loss
torch.manual_seed(0)
input = torch.randn(3, 5)
target = torch.tensor([1, 0, 4])
print("input", input)
m = nn.LogSoftmax(dim=1)
loss = nn.NLLLoss()
output = loss(m(input), target)
print("NLL loss", output)
# CE loss
loss = nn.CrossEntropyLoss()
output = loss(input, target)
print("CE loss", output)
результат:
input tensor([[ 1.5410, -0.2934, -2.1788, 0.5684, -1.0845],
[-1.3986, 0.4033, 0.8380, -0.7193, -0.4033],
[-0.5966, 0.1820, -0.8567, 1.1006, -1.0712]])
NLL loss tensor(2.7184)
CE loss tensor(2.7184)
API потерь NLL и CE потерь только встроеныLogSoftmax
разница.
Если убыток NLL рассчитывается вручную:
def LogSoftmax(x):
return torch.log(torch.exp(x)/torch.sum(torch.exp(x),axis=1,keepdims=True))
log_softmax_input = LogSoftmax(input)
print("cal NLL loss", -(log_softmax_input[0][target[0]] +
log_softmax_input[1][target[1]] + log_softmax_input[2][target[2]])/3)
результат:cal NLL loss tensor(2.7184)
4.4 nn.NLLLoss2d
Подобно приведенному выше, но с еще несколькими размерами, обычно используемыми в изображениях.
input, (N, C, H, W)
target, (N, H, W)
Например, при использовании полностью сверточной сети для классификации каждая точка на конечном изображении будет предсказывать метку класса.
criterion = nn.NLLLoss2d()
loss = criterion(sample, target)
print(loss)
4.5 BCEWithLogitsLoss
BCEWithLogitsLossопределение:
иBCELossпо сравнению с,input x
Выходной логит для модели без сигмоидальной обработки. обаtarget t
Все в одном горячем виде.
Пример:
# BCELoss
sigmoid = nn.Sigmoid()
torch.manual_seed(0)
input = torch.randn(3,2)
torch.manual_seed(3)
# target one-hot type,such as tensor([0., 1.]).
target = torch.empty(3,2).random_(2)
sigmoid_input = sigmoid(input)
criterion = nn.BCELoss()
print('bce',criterion(sigmoid_input,target))
#BCE_logit Loss
criterion = nn.BCEWithLogitsLoss()
print('BCE_logit',criterion(input,target))
результат операции:
bce tensor(0.9232)
BCE_logit tensor(0.9232)
4.6 MultiLabelSoftMarginLoss
MultiLabelSoftMarginLoss и BCEWithLogitsLoss имеют тот же эффект.
Зачем нужны мягкие потери краев для мультиэтикеток?
Поскольку он поддерживает сэмпл с несколькими метками, такими какtarget = [1,0,1]
, что означает, что образец принадлежит к классу 0 и классу 2.
# MultiLabelSoftMarginLoss
import torch
from torch import nn
torch.manual_seed(0)
x = torch.randn(10, 3)
y = torch.FloatTensor(10, 3).random_(2)
bce_criterion = nn.BCEWithLogitsLoss(weight=None, reduce=False)
multi_criterion = nn.MultiLabelSoftMarginLoss(weight=None, reduce=False)
bce_loss = bce_criterion(x, y)
multi_loss = multi_criterion(x, y)
print('weight=None, bce_loss:\n',torch.mean(bce_loss, dim = 1))
print('weight=None, multi_loss:\n', multi_loss)
результат операции:
weight=None, bce_loss:
tensor([1.1364, 0.8481, 1.2125, 0.5471, 0.5923, 0.7981, 0.9105, 0.4012, 0.5593,
0.6012])
weight=None, multi_loss:
tensor([1.1364, 0.8481, 1.2125, 0.5471, 0.5923, 0.7981, 0.9105, 0.4012, 0.5593,
0.6012])
При добавлении весов классов или добавлении весов на выборку:
# the loss for class 1
class_weight = torch.FloatTensor([1.0, 2.0, 1.0])
# the loss for last sample
element_weight = torch.FloatTensor([1.0]*9 + [2.0]).view(-1, 1)
element_weight = element_weight.repeat(1, 3)
bce_criterion_class = nn.BCEWithLogitsLoss(weight=class_weight, reduce=False)
multi_criterion_class = nn.MultiLabelSoftMarginLoss(weight=class_weight, reduce=False)
bce_criterion_element = nn.BCEWithLogitsLoss(weight=element_weight, reduce=False)
multi_criterion_element = nn.MultiLabelSoftMarginLoss(weight=element_weight, reduce=False)
bce_loss_class = bce_criterion_class(x, y)
multi_loss_class = multi_criterion_class(x, y)
bce_loss_element = bce_criterion_element(x, y)
multi_loss_element = multi_criterion_element(x, y)
print("class weight, BCE loss:\n", torch.mean(bce_loss_class,dim=1))
print("class weight, multi loss:\n",multi_loss_class)
print("element weight, BCE loss:\n", torch.mean(bce_loss_element,dim=1))
print("element weight, multi loss:\n",multi_loss_element)
результат операции:
class weight, BCE loss:
tensor([1.6121, 1.2497, 1.9556, 0.7249, 0.6772, 1.1468, 1.1855, 0.5207, 0.6838,
0.9306])
class weight, multi loss:
tensor([1.6121, 1.2497, 1.9556, 0.7249, 0.6772, 1.1468, 1.1855, 0.5207, 0.6838,
0.9306])
element weight, BCE loss:
tensor([1.1364, 0.8481, 1.2125, 0.5471, 0.5923, 0.7981, 0.9105, 0.4012, 0.5593,
1.2023])
element weight, multi loss:
tensor([1.1364, 0.8481, 1.2125, 0.5471, 0.5923, 0.7981, 0.9105, 0.4012, 0.5593,
1.2023])
Расширение: функция потерь, соответствующая TensorFlow и BCE.
питорчBCEWithLogitsLoss
и ТензорФлоуsigmoid_cross_entropy_with_logits
тот же эффект.
# BCE
from torch import nn
bce_criterion = nn.BCEWithLogitsLoss(weight = None, reduce = False)
logits = torch.tensor([[12,3,2],[3,10,1],[1,2,5],
[4,6.5,1.2],[3,6,1]],dtype=torch.float64)
target = torch.tensor([[1,0,1],[0,1,0],[0,0,1],[1,1,0],
[0,1,0]],dtype=torch.float64)
print("BCE",bce_criterion(logits, target))
# sigmoid_cross_entropy_with_logits
import tensorflow as tf
sess =tf.Session()
sigmoid_CE = sess.run(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits,labels=target))
print('sigmoid_CE',sigmoid_CE)
результат:
BCE tensor([[6.1442e-06, 3.0486e+00, 1.2693e-01],
[3.0486e+00, 4.5399e-05, 1.3133e+00],
[1.3133e+00, 2.1269e+00, 6.7153e-03],
[1.8150e-02, 1.5023e-03, 1.4633e+00],
[3.0486e+00, 2.4757e-03, 1.3133e+00]], dtype=torch.float64)
sigmoid_CE [[6.14419348e-06 3.04858735e+00 1.26928011e-01]
[3.04858735e+00 4.53988992e-05 1.31326169e+00]
[1.31326169e+00 2.12692801e+00 6.71534849e-03]
[1.81499279e-02 1.50231016e-03 1.46328247e+00]
[3.04858735e+00 2.47568514e-03 1.31326169e+00]]
Судя по результатам, они эквивалентны.
Расширение: функция потерь, соответствующая Keras и BCE
Keras binary_crossentropy
называетсяTf sigmoid_cross_entropy_with_logits
.
исходный код keras binary_crossentropy;
# binary_crossentropy
import keras.backend as K
def loss_fn( y_true, y_pred):
bce_loss = (K.binary_crossentropy(y_true, y_pred,from_logits=True))
return bce_loss
logits = K.variable([[12,3,2],[3,10,1],[1,2,5],[4,6.5,1.2],[3,6,1]])
target = K.variable([[1,0,1],[0,1,0],[0,0,1],[1,1,0],[0,1,0]])
loss = loss_fn(target,logits)
print("keras bce loss",K.get_value(loss))
Результаты также одинаковы:
keras bce loss [[6.1441933e-06 3.0485873e+00 1.2692802e-01]
[3.0485873e+00 4.5398901e-05 1.3132617e+00]
[1.3132617e+00 2.1269281e+00 6.7153485e-03]
[1.8149929e-02 1.5023102e-03 1.4632825e+00]
[3.0485873e+00 2.4756850e-03 1.3132617e+00]]
Примечательно, что интерфейс Keras:binary_crossentropy(target, output, from_logits=False)
, если вход логит, установитьfrom_logits=True
.
Расширение: softmax_cross_entropy_with_logits
тензорный поток иsoftmax_cross_entropy_with_logitsниже сравнивается разница между ней и BCE Loss (реализованной здесь с помощью sigmoid_cross_entropy_with_logits):
# sigmoid_cross_entropy_with_logits
import tensorflow as tf
logits =tf.constant([[12,3,2],[3,10,1],[1,2,5],[4,6.5,1.2],[3,6,1]],dtype=tf.float64)
target = tf.constant([[1,0,1],[0,1,0],[0,0,1],[1,1,0],[0,1,0]],dtype=tf.float64)
sess =tf.Session()
sigmoid_CE = sess.run(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits,
labels=target))
print('sigmoid_CE', np.mean(sigmoid_CE,axis=1))
# softmax CE with logits
softmax_CE = sess.run(tf.nn.softmax_cross_entropy_with_logits(
logits=logits,labels=target))
print("softmax_CE",softmax_CE)
результат операции:
sigmoid_CE [1.05850717 1.45396481 1.14896835 0.49431157 1.45477491]
softmax_CE [1.00003376e+01 1.03475622e-03 6.58839038e-02 2.66698414e+00
5.49852354e-02]
Два результата отличаются, обратите внимание, что параlogit
выполнить сигмовидную операцию; выполняетсяsoftmax
работать.
Как работает Софтмакс:
def log_softmax(x):
return -np.log(np.exp(x)/np.sum(np.exp(x),axis=1,keepdims=True))
logits = np.array([[12,3,2],[3,10,1],[1,2,5],[4,6.5,1.2],[3,6,1]])
target = np.array([[1,0,1],[0,1,0],[0,0,1],[1,1,0],[0,1,0]])
softmax_logit = log_softmax(logits)
loss = np.sum(softmax_logit*target,axis=1)
print("cal softmax loss",loss)
результат операции:
cal softmax loss [1.00003376e+01 1.03475622e-03 6.58839038e-02 2.66698414e+00
5.49852354e-02]
(Добро пожаловать в публичный аккаунт: Путь машинного обучения и алгоритмов)
Ссылаться на:
- Pytorch Форум;
- Сообщество Тьюринга;
- заметки sshuair Функция потери в PyTorch;
- Difference of implementation between tensorflow softmax_cross_entropy_with_logits and sigmoid_cross_entropy_with_logits;
- Использование tf.nn.softmax_cross_entropy_with_logits;
- функция потери pytorch, включая BCELoss;
- рекомендовать! блог Роль кросс-энтропии в нейронных сетях;
- stack exchange Cross Entropy in network;
- Cs231 softmax потери и перекрестная энтропия;
- Pytorch nn.CrossEntropyLoss ;
- Разница между NLLLoss и CrossEntropyLoss cnblog;
- обратное распространение функции потерь;
- книга глубокое обучение глубокое обучение;
- Функция потерь в машинном обучении (2) Функция потерь для задач регрессии;