【Pytorch】大语言模型中的CrossEntropyLoss
文章目录
- 前言
- 什么是CrossEntropyLoss
- 语言模型中的CrossEntropyLoss
- 计算loss的前期准备
- CrossEntropyLoss的输入
- CrossEntropyLoss的输出
- 额外说明
前言
在大语言模型时代,我们常常使用交叉熵损失函数来计算loss,因此,理解该loss的计算流程有助于帮助我们对训练过程有更清晰的认知。本文从以下几个角度介绍nn.CrossEntropyLoss()
- 使用该函数的前期准备:如何组织函数的输入(logits & labels)
- 该函数流程
- 常用参数
- 该文章内容仅为个人理解,如有误解,欢迎讨论
什么是CrossEntropyLoss
这部分并不是本文的重点,我们仅介绍在语言模型的训练过程中,如何利用该loss
- 相关信息可见:本人博客
- 以及官网:CrossEntropyLoss官网
语言模型中的CrossEntropyLoss
计算loss的前期准备
在huggingface-transformers
源码中,我们在语言模型的forward
中总是能看到这样一段函数。我们以LlamaForCausalLM
为例:Llama源码
if labels is not None:# Shift so that tokens < n predict nshift_logits = logits[..., :-1, :].contiguous()shift_labels = labels[..., 1:].contiguous()# Flatten the tokensloss_fct = CrossEntropyLoss()shift_logits = shift_logits.view(-1, self.config.vocab_size)shift_labels = shift_labels.view(-1)# Enable model parallelismshift_labels = shift_labels.to(shift_logits.device)loss = loss_fct(shift_logits, shift_labels)if not return_dict:output = (logits,) + outputs[1:]return (loss,) + output if loss is not None else output
对于Decoder-only
模型,在训练时,我们的目标是next token prediction
,任务流程如下
-
假定我们是常规的问答任务,问题是“where is the capital of China“,label为“The capital is Beijing”。该任务的目标为,当输入为“where is the capital of China“时,
-
我们对question和label进行拼接和tokenize化,一般转化结果 (tokenize忽略) 为:< bos > where is the capital of China < sep > The capital is Beijing < eos >
- < bos>为句子开头的标志
- < sep>用于分隔question和label,本质作用是,当模型看到时就知道:问题结束了,下一个token要输出答案了
- < eos>为生成结束的标志
- 假定每个词算一个token (忽略空格),那么输入一共有13个token
-
这时我们将整个序列输入到模型中,模型在每个token的位置都生成一个向量,我们利用
lm_head
将最后一层的hidden state转化成词表大小的向量logits
,用于后续利用Softmax
确定每个token的概率 -
现在模型有了输出logits,怎么计算loss?
-
对比labels和logits之间的差异来计算loss
-
现在一共有13个token,生成了13个logits,每个logits都是用于生成next token的。那么很直接的,我们来对比该logits生成的next token准不准就好了
-
输入:< bos> where is the capital of China < sep> The capital is Beijing < eos>
-
对比情况为:< sep>->The, The->capital, …, is->Beijing, Beijing->< eos>
- < sep>对应位置要生成The,…, Beijing对应位置要输出< eos>
-
我们可以将输入右移一位作为labels: where is the capital of China < sep> The capital is Beijing
- 可以看到,对于输入来说, < eos>位置没有对应的需要生成的token,因此我们去掉该token
- 对于labels,< bos>不需要生成,因此我们去掉该token
-
因此,我们在计算loss时,对logits去尾,labels是输入掐头且右移一位
-
在代码中对应
shift_logits = logits[..., :-1, :].contiguous()shift_labels = labels[..., 1:].contiguous()
-
-
CrossEntropyLoss的输入
此时还不能直接将shift_logits
和shift_labels
进行对比,来计算loss。因为我们上面的操作只是为了<sep> The capital is Beijing
和The capital is Beijing <eos>
中的token能一一对应起来,对于其他部分生成的token,我们并没有要求(因为不是answer,不需要生成)
CrossEntropyLoss
函数中有一个参数为ignore_idx
,默认值为-100。labels值设置为-100的位置不会计算loss- 因此我们将除了需要计算loss的位置 (最后5个位置)的labels都设置为-100
- 最终,需要输入到
CrossEntropyLoss
中的inputs和labels为- inputs为: [, where, is, the, capital, of, China, < sep>, The, capital, is, Beijing]对应的logits
- 注意:不需要进行Softmax,直接传logits即可,函数内部有更稳定的Softmax计算方式
- labels为: [-100, -100, -100, -100, -100, -100, -100, The, capital, is, Beijing, < eos>]
- 我们在训练时,构造输入和labels要注意构造为这种形式
- inputs为: [, where, is, the, capital, of, China, < sep>, The, capital, is, Beijing]对应的logits
CrossEntropyLoss的输出
默认情况下,输出为mean
,即各个token计算得到loss的平均值(在token-level上平均,分母是token的个数)
import torch
import torch.nn as nn# 假设有 3 个类,logits 形状为 (batch_size=3, num_classes=3)
logits = torch.tensor([[2.0, 1.0, 0.1], [0.5, 2.5, 0.3], [1.5, 0.5, 2.0]])# 标签,其中第二个样本的标签为 ignore_index (-100)
labels = torch.tensor([0, -100, 2])# 定义 CrossEntropyLoss
criterion = nn.CrossEntropyLoss()# 计算损失
loss = criterion(logits, labels)print(f"Loss: {loss}")
>>> Loss: 0.51058030128479
-
常用参数:
-
reduction
:控制loss的输出形式,共三种'none', 'mean', 'sum'
,默认为'mean'
-
mean: 每个token计算得到的loss的平均值
-
none: 直接返回每个token计算得到的loss
-
例子:
import torch import torch.nn as nn# 假设有 3 个类,logits 形状为 (batch_size=3, num_classes=3) logits = torch.tensor([[2.0, 1.0, 0.1], [0.5, 2.5, 0.3], [1.5, 0.5, 2.0]])# 标签,其中第二个样本的标签为 ignore_index (-100) labels = torch.tensor([0, -100, 2])# 定义 CrossEntropyLoss criterion = nn.CrossEntropyLoss(reduction='none')# 计算损失 loss = criterion(logits, labels)print(f"Loss: {loss}") >>> Loss: tensor([0.4170, 0.0000, 0.6041])
-
-
sum: 所有token对应loss求和
-
-
额外说明
对最上面的代码补充说明
shift_logits = shift_logits.view(-1, self.config.vocab_size)shift_labels = shift_labels.view(-1)
- 训练数据往往是按batch组织的,shape为
(batch_size, seq_len, vocab_size)
- 我们将所有batch的token压缩为一个序列,计算整个序列的loss,这样比较方便
相关文章:
【Pytorch】大语言模型中的CrossEntropyLoss
文章目录 前言什么是CrossEntropyLoss语言模型中的CrossEntropyLoss计算loss的前期准备CrossEntropyLoss的输入CrossEntropyLoss的输出 额外说明 前言 在大语言模型时代,我们常常使用交叉熵损失函数来计算loss,因此,理解该loss的计算流程有助…...

安全热点问题
安全热点问题 1.DDOS2.补丁管理3.堡垒机管理4.加密机管理 1.DDOS 分布式拒绝服务攻击,是指黑客通过控制由多个肉鸡或服务器组成的僵尸网络,向目标发送大量看似合法的请求,从而占用大量网络资源使网络瘫痪,阻止用户对网络资源的正…...
C++——用选择法对10个数值进行排序。
没注释的源代码 #include <iostream> using namespace std; int main() { int i,j,min,a[11],temp; cout<<"请输入数组a的十个值:"<<endl; for(i1;i<10;i) { cin>>a[i]; } for(i1;i<9;…...

CSP-CCF★★★201909-2小明种苹果(续)★★★
一、问题描述 二、解答 关键:判断是否发生苹果掉落,使用flag[]数组来标记,1为掉落,0为没有掉落,这样也是为了后续比较连续三棵树是否掉落 误区:用最后一次正数(即最后一次统计苹果个数&#x…...

硬件工程师笔试面试——变压器
目录 9、变压器 9.1 基础 变压器原理图 变压器实物图 9.1.1 概念 9.1.2 变压器组成结构 9.1.3 变压器原理 9.1.4 变压器的类型 9.1.5 应用领域 9.2 相关问题 9.2.1 变压器的工作原理是什么? 9.2.2 如何选择合适的变压器类型? 9.2.3 变压器在实际应用中,如何进行…...

Visual Studio Code( VS Code)倍速提高编程工作效率的免费的源代码编辑器
耕耘于编程二十多年,后端、前端、操作系统、数据库、脚本都做过,各种各样的编程工具,IDE开发环境都用过,但是让我感觉比较好用、容易上手、能够提高工作效率的开发工具还是VS Code,下面我就简单的介绍一下这个广泛使用…...

华为SMU02B1智能通信电源监控单元模块简介
华为SMU02B1是一款智能通信电源监控单元模块,专为5G嵌入式机框设计,它在通信电源管理领域扮演着重要角色。以下是对该产品的详细介绍: 一、产品概述 主要功能:华为SMU02B1能够监控和管理通信电源系统,提供站点监控功能…...

【刷题日记】15. 三数之和
15. 三数之和 两数之和可以用巧思也可以用map 三数之和会更加复杂一点,且这道题还需要考虑避免重复答案! 思路: 特判:检如果nums 为 null 或长度小于 3直接返回空数组。排序:使用 sort对数组进行升序排序。就变成了…...

低级编程语言和高级编程语言
一.区分低级编程语言和高级编程语言的方法 1.低级编程语言 低级编程语言,并不是简单的编程语言,而是写起来很费事的编程语言,如所有编程语言的"祖宗":汇编语言,写起来极其麻烦,说不定一个 int a1; 它就得写好几行,甚至十几行 这样麻烦的编程语言为什么还没消失那,因…...
Spring Boot-API网关问题
****### Spring Boot API 网关问题分析与解决方案 在微服务架构中,API 网关扮演着非常重要的角色。它位于客户端和微服务之间,充当所有外部请求的入口,负责请求的路由、聚合、鉴权、限流等功能。Spring Boot 提供了多种方式实现 API 网关&am…...
三 auto占位符
3.1 重新定义的auto关键字 1.当用一个auto关键字声明多个变量的时候,编译器遵从由左往右的推导规则,以最左边的表达式推断auto的具体类型 int n 5; auto *pn &n, m 10;// 这里auto被推导为 int 所以int m 10;合理 auto *pns &n, m 10.0;/…...
tail: inotify 资源耗尽
解决方法: 增加可用的 inotify 监视器数量。可以通过修改系统配置文件来增加监视器数量限制。 临时增加(直到下次重启):执行 echo 1048576 | sudo tee -a /proc/sys/fs/inotify/max_user_instances 和 echo 65536 | sudo tee -a /…...

什么是损失函数?常见的损失函数有哪些?
损失函数 什么是损失函数?损失函数作用如何设计损失函数常见的损失函数有哪些? 什么是损失函数? 损失函数(Loss Function),也称为误差函数,是机器学习和深度学习中的一个重要概念。它用于衡量模…...
Python Web 开发中的国际化与本地化处理
Python Web 开发中的国际化与本地化处理 目录 🌍 Flask中的国际化与本地化处理🌐 Django中的国际化与本地化处理🗣️ 多语言支持与翻译系统实现🕒 时区和日期的本地化处理 1. 🌍 Flask中的国际化与本地化处理 Flask…...
android API、SDK与android版本
随着 Android 系统的不断更新,API Level 也会随之增加。每个新的 API Level 都引入了新的功能、改进旧的功能,或者弃用了旧的 API。开发者在开发应用时,需要指定目标 API Level,也就是应用最低支持的 Android 版本。 API Level 与…...

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【内核通信机制】下
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ 子系统开发内核 轻量系统内核(LiteOS-M) 轻量系统内核&#…...

如何联系真正的开发者而非公司??
🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&am…...

OpenCV运动分析和目标跟踪(1)累积操作函数accumulate()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将一个图像添加到累积图像中。 该函数将 src 或其部分元素添加到 dst 中: dst ( x , y ) ← dst ( x , y ) src ( x , y ) if mask…...
source ~/.bash_profile有什么用
source ~/.bash_profile 是在 Unix/Linux 系统上用来重新加载用户的 Bash 配置文件 ~/.bash_profile 的命令。这条命令的作用是使得当前的 Bash 环境重新读取并应用 ~/.bash_profile 中的设置和变量定义。 作用: 1. 更新环境变量: ~/.bash_profile 是用户…...

【C++笔记】类和对象的深入理解(三)
【C笔记】类和对象的深入理解(三) 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】类和对象的深入理解(三)前言一.日期类的实现1.1声明和定义分离1.2日期类整数1.3日期类整数1.4日期类-整数1.5日期类-日期1.6复用对…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...