损失函数
说明:
一般来说,监督学习的目标函数由损失函数和正则化项组成。(Objective = Loss + Regularization)
Pytorch中的损失函数一般在训练模型时候指定。
注意Pytorch中内置的损失函数的参数和tensorflow不同,是y_pred在前,y_true在后,而Tensorflow是y_true在前,y_pred在后。
对于回归模型,通常使用的内置损失函数是均方损失函数nn.MSELoss 。
对于二分类模型,通常使用的是二元交叉熵损失函数nn.BCELoss (输入未经过sigmoid激活函数之后的结果需要对y_pred加sigmod激活) 或者 nn.BCEWithLogitsLoss (y_pred自动经过nn.Sigmoid激活函数) 。
对于多分类模型,一般推荐使用交叉熵损失函数 nn.CrossEntropyLoss。 (y_true需要是一维的,是类别编码。y_pred自动经过nn.Softmax激活。)
此外,如果多分类的y_pred经过了nn.LogSoftmax激活,可以使用nn.NLLLoss损失函数(The negative log likelihood loss)。 这种方法和直接使用nn.CrossEntropyLoss等价。
一.内置损失函数
import numpy as np
import pandas as pd
import torch
from torch import nn
import torch.nn.functional as F
y_pred = torch.tensor([[10.0,0.0,-10.0],[8.0,8.0,8.0]])
y_true = torch.tensor([0,2])
#直接使用交叉熵损失函数
loss_1 = nn.CrossEntropyLoss()(y_pred,y_true)
print('CrossELOSS',loss_1)
#等价于先计算nn.logsoftmax激活,再调用NLLLoss
y_pred_logsoftmax = nn.LogSoftmax(dim = 1)(y_pred)
loss_2 = nn.NLLLoss()(y_pred_logsoftmax,y_true)
print('NLLLoss',loss_2)
输出:
CrossELOSS tensor(0.5493)
NLLoss tensor(0.5493)
import torch.nn as nn
m = nn.Sigmoid()
loss = nn.BCELoss()
inputt = torch.randn(3,requires_grad = True)
target = torch.empty(3).random_(2)
loss_3 = loss(m(inputt), target)
print(loss_3)
loss1 = nn.BCEWithLogitsLoss()
loss_4 = loss1(inputt, target)
print(loss_4)
tensor(1.0520, grad_fn=<BinaryCrossEntropyBackward>)
tensor(1.0520, grad_fn=<BinaryCrossEntropyWithLogitsBackward>)
常用的一些内置损失函数说明如下。
nn.MSELoss(均方误差损失,也叫做L2损失,用于回归)
nn.L1Loss (L1损失,也叫做绝对值误差损失,用于回归)
nn.SmoothL1Loss (平滑L1损失,当输入在-1到1之间时,平滑为L2损失,用于回归)
nn.BCELoss (二元交叉熵,用于二分类,输入没有经过nn.Sigmoid激活,对不平衡数据集可以用weigths参数调整类别权重)
nn.BCEWithLogitsLoss (二元交叉熵,用于二分类,输入经过nn.Sigmoid激活)
nn.CrossEntropyLoss (交叉熵,用于多分类,要求label为稀疏编码类别号,输入经过nn.Softmax激活,对不平衡数据集可以用weigths参数调整类别权重)
nn.NLLLoss (负对数似然损失,用于多分类,要求label为稀疏编码类别号,,输入未经过nn.LogSoftmax激活)
二.自定义损失函数
自定义损失函数接收两个张量y_pred,y_true作为输入参数,并输出一个标量作为损失函数值。
正则化描述:
L1正则化是指权值向量w中各个元素的绝对值之和;
L2正则化是指权值向量w中各个元素的平方和然后再求平方根;
一般都会在正则化项之前添加一个系数,这个系数需要用户设定,系数越大,正则化作用越明显。
正则化作用:
L1正则化可以产生稀疏权值矩阵,即产生一个稀疏模型,可以用于特征选择,一定程度上,L1也可以防止过拟合;
L2正则化可以防止模型过拟合(overfitting);
正则化策略的目的就是降低反差,减少过拟合的发生
import numpy as np
import pandas as pd
from matplotlib import as plt
import torch
from torch import nn
import torch.nn.functional as F
from torch.utils.data import Dataset,DataLoader,TensorDataset
import torchkeras
%matplotib inline
%config InlineBackend.figure_format = 'svg'
n_postive, n_negative = 200,6000
#生成正样本,小圆环分布
r_p = 5.0 + torch.normal(0.0,1.0,size = [n_positive,1])
theta_n = 2*np.pi*torch.rand([n_positive,1])
Xp = torch.cat([r_p*torch.cos(theta_p),r_p*torch.sin(thrta_p)],axis = 1)
Yp = torch.ones_like(r_p)
#生成负样本,大圆环分布
r_p = 5.0 + torch.normal(0.0,1.0,size = [n_positive,1])
theta_n = 2*np.pi*torch.rand([n_negative,1])
Xn = torch.cat([r_n*torch.cos(theta_n),r_n*torch.sin(theta_n)],axis = 1)
Yn = torch.zeros_like(r_n)
#汇总样本
X = torch.cat([Xp,Xn],axis = 0)
Y = torch.cat([Yp,Yn],axis = 0)
#可视化
plt.figure(figsize = (6,6))
plt.scatter(Xp[:,0],Xp[:,1],c = "r")
plt.scatter(Xn[:,0],Xn[:,1],c = "g")
plt.legend(["positive","negative"]);