范围:该问题影响所有使用梯度累计的库,包括hf的等。(hf的人在修复中了)
10.18日更新:
感谢评论区的大佬赐教,补充下他们的观点。
@Quokka 提供了一种对描述的实验现象(梯度累积越大,最终 loss 就越大的猜测)的解释:
短序列因为上下文短,信息不足,所以不容易预测,loss 偏大(梯度累积再给他加权),于是观测到的现象就是“梯度累积 loss 偏大”。其实它是偏向了短序列的 loss,而不是往大的方向偏。
@Ethan Yan
一般情况下,loss 计算会经历三次平均:
- micro batch 维度,分母是这个 micro batch 中的所有 label 不是 -100 的 token 数(不同 token 之间 loss 的平均)
- DP 维度,分母是 DP size (和 GPU 数量相关,不同机器之间 loss 的平均)
- 梯度累加维度,分母是梯度累加数。(不同 batch 之间的 loss 的平均)
我们要做的就是,不要让 DP 以及梯度累积维度影响原本 token 级别等权的 loss。
因此计算完,所有的目标 token 的 loss,加和之后,再除以实际目标 token 总数,这样,在 token 维度都是等权的,不受长度影响。
10.17日更新:
Hugging Face 在 10.16 日写了篇博客介绍修复问题。
https://huggingface.co/blog/gradient_accumulation
他们的方法是:交叉熵改为 reduction=sum
,再除总的实际目标 token。(他们的 loss 都在模型里面,要改无数个模型文件。。。)
def ForCausalLMLoss(logits, labels, vocab_size, **kwargs):
# Upcast to float if we need to compute the loss to avoid potential precision issues
logits = logits.float()
# Shift so that tokens < n predict n
shift_logits = logits[..., :-1, :].contiguous()
shift_labels = labels[..., 1:].contiguous()
# Flatten the tokens
shift_logits = shift_logits.view(-1, vocab_size)
shift_labels = shift_labels.view(-1)
# Enable model parallelism
shift_labels = shift_labels.to(shift_logits.device)
num_items = kwargs.pop("num_items", None)
+ loss = nn.functional.cross_entropy(shift_logits, shift_labels, ignore_index=-100, reduction="sum")
+ loss = loss / num_items
- loss = nn.functional.cross_entropy(shift_logits, shift_labels, ignore_index=-100)
return loss
Qwen2 的计算 loss 的方式:
https://github.com/huggingface/transformers/blob/v4.45.2/src/transformers/models/qwen2/modeling_qwen2.py#L855
他们的 PR:
https://github.com/huggingface/transformers/pull/34191 https://github.com/huggingface/transformers/pull/34198
重新安装后,即可正常使用:pip install git+
https://github.com/huggingface/transformers
整体结论(太长不看版):
- 理论上,梯度累计在数学上应该等同于全批量训练,但实际发现 loss 并不匹配。
https://github.com/huggingface/trl/issues/2175
-
研究者通过公式和实验证明,罪魁祸首是基于平均(mean)交叉熵损失和梯度累计,结合后会比全批量的平均交叉熵损失更大。
-
loss大,会对什么有影响呢?
-
- 模型泛化性:梯度累计加上基于平均(mean)交叉熵损失,会导致 bsz=1,ga=16 之间的 L2 范数比 bsz=16 的 10 倍。可以理解为:导致模型泛化性不足。
- 梯度累积后,过度重视短的序列长度,而忽略长的序列长度。
问题描述:
实验发现1:之前的研究者发现,在总的 batch_size * gradient accumulation
相同的情况下,梯度累积越大,最终 loss 就越大。研究者对此提了一个 issue:
https://github.com/huggingface/trl/issues/2175
实验发现2:最近的研究者通过实验发现,在相同的 batch_size * gradient accumulation
下,除了 loss 会更大,梯度累积越大,最终会导致 L2 范数越大。L2 范数越大,说明权重越大,进而影响模型的泛化性。
下面我们推导下 full batch 和 gradient accumulation 在计算 loss 上到底是否相等?
实例推导:
假设我们是在 SFT 任务中,输入的维度是 [batch_size, seq_len]
,假设这个 batch 内:实际需要计算的 target token 的总数为 I:
那么,交叉熵 loss 会先为 batch 内每一个 target token 计算一个 loss,然后相加,最后除以这个 batch 内所有 target token 的总数 I。
交叉熵 loss 的默认设定是 reduction=mean
。
我们举例说明:
- 第一种情况(full batch):
batch_size = 2
,gradient accumulation = 1
; - 第二种情况(gradient accumulation):
batch_size = 1
,gradient accumulation = 2
。
序列等长的情况(每个 batch 的 target token 数量一样):
首先,假设两个序列等长,都是 m;
full batch 情况:
gradient accumulation 情况:
两种 loss 是相等的。
序列不等长的情况(每个 batch 的 target token 数量不一样):
假设两个序列不等长(训练过程中十分常见),一个是 一个是 ;
full batch 情况:
gradient accumulation 情况:
其实本质上就是比较 和 谁大谁小的情况了。
四个变量,已知 和 不相等,可以对 loss 做些假设,数学证明下两者的大小。
从目前的公式,我们能得出的结论是,相比 full batch 下不同序列的 target token 等权,在 gradient accumulation 情况下:
- 如果一个序列 target token 越短,那么其 loss 权重越大;(因为分母小)
- 如果一个序列 target token 越长,那么其 loss 权重越小。(因为分母大)
如何学习大模型
现在社会上大模型越来越普及了,已经有很多人都想往这里面扎,但是却找不到适合的方法去学习。
作为一名资深码农,初入大模型时也吃了很多亏,踩了无数坑。现在我想把我的经验和知识分享给你们,帮助你们学习AI大模型,能够解决你们学习中的困难。
我已将重要的AI大模型资料包括市面上AI大模型各大白皮书、AGI大模型系统学习路线、AI大模型视频教程、实战学习,等录播视频免费分享出来
,需要的小伙伴可以扫取。
一、AGI大模型系统学习路线
很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,我下面分享的这个学习路线希望能够帮助到你们学习AI大模型。
二、AI大模型视频教程
三、AI大模型各大学习书籍
四、AI大模型各大场景实战案例
五、结束语
学习AI大模型是当前科技发展的趋势,它不仅能够为我们提供更多的机会和挑战,还能够让我们更好地理解和应用人工智能技术。通过学习AI大模型,我们可以深入了解深度学习、神经网络等核心概念,并将其应用于自然语言处理、计算机视觉、语音识别等领域。同时,掌握AI大模型还能够为我们的职业发展增添竞争力,成为未来技术领域的领导者。
再者,学习AI大模型也能为我们自己创造更多的价值,提供更多的岗位以及副业创收,让自己的生活更上一层楼。
因此,学习AI大模型是一项有前景且值得投入的时间和精力的重要选择。