本文讨论了深度学习中常用的损失函数,包括交叉熵损失函数、余弦相似度损失函数和双曲余弦对数损失函数,并对它们在PyTorch中的应用细节进行了介绍,通过MNIST手写体数字识别实验展示它们的应用。损失函数有很多,读者可以在了解基本知识的基础上,要求AI大模型给出相关损失函数的原理细节,并给出相应的应用代码供使用或参考。
本专栏之三中简要讨论了损失函数的概念及最容易理解的损失函数MSE,MSE是基于欧氏距离的损失函数。多层神经网络中常用的损失函数还有KL(Kullback-Leibler Divergence)散度损失函数、交叉熵(Crossentropy)损失函数、余弦相似度损失函数、双曲余弦对数(logarithm of the hyperbolic cosine)损失函数等。
了解不同损失函数对优化的影响,以及它们应用的特点,是设计深度学习模型、指导AI大模型调整模型的重要知识。
本文还进一步讨论了凸函数理论,供想深入研究的读者参考。
1.相对熵损失函数和交叉熵损失函数
交叉熵可以用来衡量两个分布之间的差距,还是以示例入手讨论。
在本专栏之五的讨论误差反向传播学习算法时,使用了一个用神经网络模拟异或运算的例子,其中使用的示例的最后预测输出与实际标签值的对比如下:
a)[ 0.07158904 0.92822515 ] -> [ 0. 1.]
b)[ 0.9138734 0.08633152 ] -> [ 1. 0.]
c)[ 0.91375259 0.08644981 ] -> [ 1. 0.]
d)[ 0.11774177 0.88200493 ] -> [ 0. 1.]
对于a和d两项输出,标签值都是[ 0. 1.],直观来看a的预测应该更准一些。如何形式化地度量它们与标签值的差距呢?
将预测输出值看作概率,如 a 项中,预测为 1 的概率为 0.07158904,预测为 0 的概率为 0.92822515。
信息熵(有关信息熵及其在机器学习领域中的应用,可参考文献[1]中的4.1节)的定义为:H(X)=−∑i=1npilogpiH(X) = -sum_{i=1}^n p_i log p_iH(X)=−∑i=1npilogpi。用pip_ipi表示第 i 个输出的标签值,即真实值,用qiq_iqi表示第 i 个输出值,即预测值。将它们都视为概率值,pip_ipi与qiq_iqi之间的对数差在pip_ipi上的期望值称为相对熵:
DKL(p∣∣q)=Ep(logpi−logqi)=∑i=1npi(logpi−logqi)=∑i=1npilogpiqi(式10-1) D_{KL}(p||q) = E_p(log p_i - log q_i) = sum_{i=1}^n p_i (log p_i - log q_i)=sum_{i=1}^n p_i log frac{p_i}{q_i} ag{式10-1}DKL(p∣∣q)=Ep(logpi−logqi)=i=1∑npi(logpi−logqi)=i=1∑npilogqipi(式10-1)
将上述与熵的定义式进行对比,可见是用logqi−logpilog q_i - log p_ilogqi−logpi代替了logpilog p_ilogpi,用来度量两个分布之间的差异。计算 a 和 d 两项输出的相对熵:
Da=0×log00.07158904+1×log10.92822515=0.07447962 D_a = 0 imes log frac{0}{0.07158904} + 1 imes log frac{1}{0.92822515} = 0.07447962Da=0×log0.071589040+1×log0.928225151=0.07447962
Dd=0×log00.11774177+1×log10.88200493=0.12555622 D_d = 0 imes log frac{0}{0.11774177} + 1 imes log frac{1}{0.88200493} = 0.12555622Dd=0×log0.117741770+1×log0.882004931=0.12555622
式中,0×log00 imes log 00×log0计为 0。
可见,与直接观察的结论相同。相对熵越大的输出与标签值差距越大。如果pip_ipi与qiq_iqi相同,那么DKL(p∣∣q)=0D_{KL}(p||q) = 0DKL(p∣∣q)=0。
值得注意的是,相对熵不具有对称性。相对熵又称为 KL 散度。
将相对熵的定义式 10-1 进一步展开:
DKL(p∣∣q)=∑i=1npi(logpi−logqi) D_{KL}(p||q) = sum_{i=1}^{n} p_i(log p_i - log q_i)DKL(p∣∣q)=i=1∑npi(logpi−logqi)
=∑i=1npilogpi+[−∑i=1npilogqi](式10-2) = sum_{i=1}^{n} p_ilog p_i + left[ -sum_{i=1}^{n} p_ilog q_i ight] ag{式10-2}=i=1∑npilogpi+[−i=1∑npilogqi](式10-2)
=−H(pi)+[−∑i=1npilogqi] = -H(p_i) + left[ -sum_{i=1}^{n} p_ilog q_i ight]=−H(pi)+[−i=1∑npilogqi]
前一项正好是标签分布熵的负值,保持不变,因此一般用后一项作为两个分布之间差异的度量,称为交叉熵:
H(p,q)=−∑i=1npilogqi(式10-3) H(p,q) = -sum_{i=1}^{n} p_ilog q_i ag{式10-3}H(p,q)=−i=1∑npilogqi(式10-3)
如果只有正负两个分类(标签记为 1 和 0),记第iii个输出的标签值为yiy_iyi,记它被预测为正类的概率为pip_ipi,那么上式为:
H(y,p)=−1n∑i=1n[yilogpi+(1−yi)log(1−pi)] H(y,p) = -frac{1}{n}sum_{i=1}^{n} [y_ilog p_i + (1-y_i)log(1-p_i)]H(y,p)=−n1i=1∑n[yilogpi+(1−yi)log(1−pi)]
交叉熵损失函数在梯度下降法中可以改善 MSE 学习速率降低的问题,得到了广泛的应用。
PyTorch中实现的交叉熵损失函数有:多分类交叉熵损失函数torch.nn.CrossEntropyLoss()、 二元交叉熵损失函数torch.nn.BCELoss()和带Sigmoid的二元交叉熵损失函数torch.nn.BCEWithLogitsLoss()等,实现KL散度损失函数的有:torch.nn.KLDivLoss()。使用CrossEntropyLoss()时,不需要提前将标签值转换成独热编码,这是使用它的一个便利特性。
仍然采用MNIST数据集进行手写体数字识别实验示例如代码10-1.1 所示,采用SGD优化方法,三层分别采用relu、relu和softmax激活函数,训练 10 轮,不同的损失函数会有不同的识别率。要注意的是,本示例仅示意各损失函数的差异,并没有严格地定义实验条件,因此结果并不具备广泛性。
代码10-1.1 损失函数应用示例
### 1.导入和设置环境importtorchimporttorch.nnasnnimporttorch.optimasoptimfromtorch.utils.dataimportDataLoader,TensorDatasetimportdatetimefromtorchvisionimportdatasets,transforms# 设置随机种子torch.manual_seed(0)### 2.训练样本和验证样本数据预处理# 数据预处理方式transform=transforms.Compose([transforms.ToTensor(),# 转换为 torch.Tensor])# 加载MNIST数据集train_dataset=datasets.MNIST('./data',train=True,download=True,transform=transform)val_dataset=datasets.MNIST('./data',train=False,transform=transform)# 样本拉平、归一化后X_train=train_dataset.data.float().view(-1,784)/255.0y_train=train_dataset.targets X_val=val_dataset.data.float().view(-1,784)/255.0y_val=val_dataset.targets# 转换为独热编码y_train=torch.nn.functional.one_hot(y_train,num_classes=10).float()y_val=torch.nn.functional.one_hot(y_val,num_classes=10).float()# 创建数据加载器batch_size=200train_loader=DataLoader(TensorDataset(X_train,y_train),batch_size=batch_size,shuffle=True)val_loader=DataLoader(TensorDataset(X_val,y_val),batch_size=batch_size)### 3.定义神经网络模型# relu-relu-softmaxclassMNISTModel(nn.Module):def__init__(self):super(MNISTModel,self).__init__()self.fc1=nn.Linear(784,784)self.fc2=nn.Linear(784,784)self.fc3=nn.Linear(784,10)self.relu=nn.ReLU()self.softmax=nn.Softmax()defforward(self,x):x=self.relu(self.fc1(x))x=self.relu(self.fc2(x))x=self.softmax(self.fc3(x))returnx### 4.采用不同的损失函数进行对比试验criterion=nn.CrossEntropyLoss()# 定义损失函数model=MNISTModel()# 实例化模型类得到模型对象optimizer=optim.SGD(model.parameters(),lr=0.15)# 定义优化器# 训练模型,开始计时start_time=datetime.datetime.now()epochs=10forepochinrange(epochs):# 每轮中的训练model.train()train_loss=0.0forbatch_X,batch_yintrain_loader:optimizer.zero_grad()outputs=model(batch_X)loss=criterion(outputs,batch_y)loss.backward()optimizer.step()train_loss+=loss.item()# 看一下该轮训练后的效果model.eval()correct=0total=0withtorch.no_grad():forbatch_X,batch_yintrain_loader:outputs=model(batch_X)_,predicted=torch.max(outputs.data,1)# 模型预测值的独热编码_,labels=torch.max(batch_y.data,1)# 真实标签值的独热编码total+=labels.size(0)correct+=(predicted==labels).sum().item()# 准确率print(f'Epoch{epoch+1}/{epochs}, 对训练样本进行预测的准确率(Train Acc):{100*correct/total:.2f}%')# 训练结束,终止计时end_time=datetime.datetime.now()print(f"训练用时:{end_time-start_time}")输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 64.97% Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 82.14% Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 83.63% Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 84.34% Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 84.81% Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 91.00% Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 91.88% Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 92.22% Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 93.04% Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 93.51% 训练用时: 0:01:25.518433
通过设置MSE损失函数、多分类交叉熵损失函数、二元交叉熵损失函数、带Sigmoid的二元交叉熵损失函数BCEWithLogitsLoss损失函数、KL散度损失函数进行试验,对训练样本的预测准确率为:89.14%、93.51%、93.23%、68.93%、56.66%,详见本文所附代码文件。
交叉熵系列损失函数中,还可以通过设置weight和pos_weight参数来处理样本类别不平衡的问题。样本类别不平衡问题详见本专栏之九的文章。
2.余弦相似度损失函数
余弦相似度刻画的是两个向量之间的夹角,它适合于与向量方向相关的距离度量。
设特征空间Xmathcal{X}X是nnn维实数向量空间Rnmathbb{R}^nRn,点xi,xj∈Xmathbf{x}_i , mathbf{x}_j in mathcal{X}xi,xj∈X,xi=(xi,1,xi,2,…,xi,m)mathbf{x}_i = (x_{i,1}, x_{i,2}, dots, x_{i,m})xi=(xi,1,xi,2,…,xi,m),xj=(xj,1,xj,2,…,xj,m)mathbf{x}_j = (x_{j,1}, x_{j,2}, dots, x_{j,m})xj=(xj,1,xj,2,…,xj,m)。
点xi,xjmathbf{x}_i, mathbf{x}_jxi,xj的余弦相似度为:
cosθ=xi⋅xj∥xi∥∥xj∥=∑k=1nxi(k)xj(k)∑k=1n(xi(k))2∑k=1n(xj(k))2(式10-4) cos heta = frac{mathbf{x}_i cdot mathbf{x}_j}{|mathbf{x}_i||mathbf{x}_j|} = frac{sum_{k=1}^n x_i^{(k)} x_j^{(k)}}{sqrt{sum_{k=1}^n (x_i^{(k)})^2} sqrt{sum_{k=1}^n (x_j^{(k)})^2}} quad ag{式10-4}cosθ=∥xi∥∥xj∥xi⋅xj=∑k=1n(xi(k))2∑k=1n(xj(k))2∑k=1nxi(k)xj(k)(式10-4)
将标签和预测看作值向量,可用式10-4计算得到余弦相似度作为损失函数(Cosine Similarity Loss)。
余弦相似度损失函数主要用于需要衡量向量方向一致性的任务,特别适用于处理高维特征且关注相对关系的场景,主要有图像分类与人脸识别、文本检索与语义匹配、推荐系统等。
使用余弦相似度损失函数的示例如代码10-1.2所示。
代码10-1.2 余弦相似度损失函数应用示例
### 使用余弦相似度损失函数需要先自定义一个适配器classCosineLossAdapter(nn.Module):def__init__(self,margin=0.5):super(CosineLossAdapter,self).__init__()self.cosine_loss=nn.CosineEmbeddingLoss(margin=margin)defforward(self,predictions,targets):# CosineEmbeddingLoss需要两个输入张量和一个目标张量# 我们将预测视为第一个输入,目标视为第二个输入# 目标标签设为1(表示我们希望它们相似)target_labels=torch.ones(predictions.size(0)).to(predictions.device)# 计算损失loss=self.cosine_loss(predictions,targets,target_labels)returnloss criterion=CosineLossAdapter(margin=0.5)# 使用适配器model=MNISTModel()# 实例化模型类得到模型对象optimizer=optim.SGD(model.parameters(),lr=0.15)# 定义优化器# 训练模型,开始计时start_time=datetime.datetime.now()epochs=10forepochinrange(epochs):# 每轮中的训练model.train()train_loss=0.0forbatch_X,batch_yintrain_loader:optimizer.zero_grad()outputs=model(batch_X)loss=criterion(outputs,batch_y)# 现在只需要两个参数loss.backward()optimizer.step()train_loss+=loss.item()# 看一下该轮训练后的效果model.eval()correct=0total=0withtorch.no_grad():forbatch_X,batch_yintrain_loader:outputs=model(batch_X)_,predicted=torch.max(outputs.data,1)# 模型预测值的独热编码_,labels=torch.max(batch_y.data,1)# 真实标签值的独热编码total+=labels.size(0)correct+=(predicted==labels).sum().item()# 准确率print(f'Epoch{epoch+1}/{epochs}, 对训练样本进行预测的准确率(Train Acc):{100*correct/total:.2f}%')# 训练结束,终止计时end_time=datetime.datetime.now()print(f"训练用时:{end_time-start_time}")输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 89.40% Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 91.37% Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 92.52% Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 93.10% Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 93.67% Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 94.39% Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 94.86% Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 95.37% Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 95.69% Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 96.10% 训练用时: 0:01:13.835299
3. 双曲余弦对数损失函数
双曲余弦对数(Log-Cosh Loss)的计算方法为:
logcosh(p,q)=∑i=1nlog(eqi−pi+e−(qi−pi)2)=∑i=1nlog(eqi−pi⋅(1+e−2(qi−pi))/2)=∑i=1n[log(eqi−pi)+log(1+e−2(qi−pi))−log(2)]=∑i=1n[(qi−pi)+log(1+e−2(qi−pi))−log(2)]=∑i=1n[(qi−pi)+softplus(−2(qi−pi))−log(2)](式10-5) egin{align*} log cosh(p, q) &= sum_{i=1}^n logleft(frac{e^{q_i - p_i} + e^{-(q_i - p_i)}}{2}
ight) \ &=sum_{i=1}^n log(e^{q_i - p_i} cdot (1 + e^{-2(q_i - p_i)})/2) \ &=sum_{i=1}^n [ log(e^{q_i - p_i}) + log(1 + e^{-2(q_i - p_i)}) - log(2)] \ &=sum_{i=1}^n [ (q_i - p_i) + log(1 + e^{-2(q_i - p_i)}) - log(2) ]\ &=sum_{i=1}^n [ (q_i - p_i) + ext{softplus}(-2(q_i - p_i)) - log(2)] end{align*} ag{式10-5}logcosh(p,q)=i=1∑nlog(2eqi−pi+e−(qi−pi))=i=1∑nlog(eqi−pi⋅(1+e−2(qi−pi))/2)=i=1∑n[log(eq
旅游网站建设株洲网站建设
Excalidraw水印功能开启方式在远程协作日益深入的今天,可视化工具早已不只是“画图”那么简单。像 Excalidraw 这样以手绘风格著称的开源白板,正被越来越多的技
山西网站建设网站建设 重庆
网易云音乐NCM格式终极解密:免费解锁你的音乐收藏完整指南【免费下载链接】ncmdump项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump
网站建设广告深圳外贸网站建设
背景与意义大数据旅游数据分析与推荐系统基于Django框架开发,结合大数据技术,旨在解决传统旅游行业信息过载、个性化服务不足等问题。通过整合海量旅游数据(如用
上海外贸网站建设郴州网站建设
目录摘要项目技术支持论文大纲核心代码部分展示可定制开发之亮点部门介绍结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作摘要基于UniApp和SpringBoo
网站的建设襄樊网站建设
手把手教你把 FT5x06 触摸屏“焊”进 LVGL:从底层驱动到丝滑交互你有没有遇到过这种情况——屏幕显示正常,LVGL 界面也跑起来了,可一上手触摸就“抽
网站建设推广涪陵网站建设
第一章:智谱 Open-AutoGLM 本地部署概述Open-AutoGLM 是智谱推出的自动化代码生成与任务推理大模型,具备强大的自然语言理解与代码生成能力。通过在本地环
苏州网站建设app网站建设
MGeo在婚庆公司客户信息管理中的实用价值引言:婚庆行业客户数据治理的现实挑战在婚庆服务行业中,客户信息管理是业务运营的核心环节。每对新人从咨询、预订到婚礼执行
如何建设网站官方网站建设
上拉电阻与信号完整性:从原理到实战的深度拆解你有没有遇到过这样的情况——电路明明没接错,代码也跑通了,但I²C总线就是时不时丢数据?或者按键输入
中国建设银行官方网站网站建设需要
系统性能优化利器:Mem Reduct深度解析与实战配置指南【免费下载链接】memreductLightweight real-time memory management applic