大模型(LLMs)推理面
来源:AiGC面试宝典 日期:2024年6月18日
一、为什么大模型推理时显存涨的那么多还一直占着?
序列太长,Q/K/V缓存量大:Transformer的自注意力机制需要为每个token计算Query、Key、Value向量,长序列会产生巨大的内存开销
逐个预测next token时,需要缓存K/V加速解码:生成式模型每次预测下一个token时,需要用到之前所有位置的Key和Value矩阵,这些缓存会持续占用显存
📝通俗解释:就像你看书时需要记住前面所有内容才能预测下一个字一样,大模型推理时也要"记住"之前的所有信息。这些"记忆"就是K/V缓存,占用大量显存。而且因为模型不会主动"忘记",所以显存会一直被占着。
二、大模型在GPU和CPU上推理速度如何?
7B量级下:
| 设备 | 推理速度 |
|---|---|
| CPU(8核AMD) | 约10 token/s |
| 单卡A6000 | 约100 token/s |
📝通俗解释:GPU就像高速公路,CPU就像乡间小路。同样跑一个任务,GPU比CPU快大约10倍。所以如果用CPU跑大模型,可能会比较慢,适合对速度要求不高的场景。
三、推理速度上,int8和fp16比起来的怎么样?
根据实践经验,int8模式推理通常会明显变慢(HuggingFace的实现)
📝通俗解释:int8虽然省显存(一个参数只用1个字节),但就像用压缩包存文件——存的时候省空间,解压用的时候反而更麻烦,所以速度反而变慢了。fp16则是"半价"但不失真的版本,速度和效果都比较均衡。
四、大模型有推理能力吗?
大模型确实有推理能力,主要体现在两个方面:
In-Context Correction(上下文修正)能力
- 如果说错了,给出矫正,ChatGPT能"听懂"错在哪儿,并向正确的方向修正
- 这比In-Context Learning难得多:描述越详细,ChatGPT回答得越好
- 越详细的描述,在预训练文本中越难匹配到
超范围理解能力
- 询问ChatGPT互联网上不存在的内容时,能给出较好答案(如用ChatGPT学建模)
- 能通过信息猜你心中的想法
- 可以制定全新游戏规则让ChatGPT和你玩
📝通俗解释:大模型不只是"鹦鹉学舌",它真的能理解你的意思并推理。比如你告诉它"我刚才说的不对,应该是这样",它能理解错在哪里并改正。这种能力叫做"上下文学习"和"上下文修正",是大模型最神奇的地方之一。
五、大模型生成时的参数怎么设置?
生成模型预测调参建议
# 推荐调整的参数
top_p=0.9, # nucleus sampling阈值
num_beams, # beam search数量
repetition_penalty=1.8, # 重复惩罚
temperature=1.0, # 温度参数
do_sample=True, # 是否采样
no_repeat_ngram_size=6 # 不重复n-gram大小调参经验
| 问题 | 解决方案 |
|---|---|
| 数据生成有重复 | 调高repetition_penalty |
| 任务表达单一、样本不多 | 适当调低temperature,生成结果更像训练集 |
| 复现训练集效果 | temperature=0.01 |
📝通俗解释:
- temperature:就像"温度"一样,高温=更随机多样,低温=更保守确定
- repetition_penalty:惩罚那些重复说过的词,让输出更有新意
- top_p:控制生成词汇的多样性,越小越保守,越大越开放
- 这些参数不是固定的,要根据具体任务来调整,就像做菜要调味一样,多试试才知道最佳配比。
六、有哪些省内存的大语言模型训练/微调/推理方法?
6.1 如何估算模型所需的RAM?
首先了解精度对内存的影响:
| 精度 | 每参数所需内存 |
|---|---|
| fp32 | 4 bytes |
| fp16 | 2 bytes |
| int8 | 1 byte |
模型所需内存的三个部分
模型参数 = 参数量 × 每参数所需内存
- fp32 LLaMA-6B: 6B × 4 bytes = 24GB
- int8 LLaMA-6B: 6B × 1 byte = 6GB
梯度 = 参数量 × 每梯度参数所需内存
优化器参数(以AdamW为例,需储存一阶和二阶动量)
- fp32 LLaMA-6B: 6B × 8 bytes = 48GB
- int8 LLaMA-6B: 6B × 2 bytes = 12GB
计算示例
int8精度的LLaMA-6B大致需要:
- 模型参数:6GB
- 梯度:6GB
- 优化器:12GB
- CUDA kernel:约1.3GB
- 总计:约25.3GB
中间变量内存估算
根据LLaMA架构(hidden_size=4096, intermediate_size=11008, num_hidden_layers=32, context_length=2048):
每instance需要:(4096 + 11008) × 2048 × 32 × 1 byte ≈ 990MB📝通俗解释:就像盖房子需要建材、人工、设计图一样,大模型训练需要三部分内存:
- 模型参数=建材(决定房子多大)
- 梯度=施工记录(记录怎么改进)
- 优化器参数=工程师的大脑(记得怎么调整) 一个小小的6B模型,用int8精度光"建材"就要6GB,再加上"工程师"要12GB,一块24GB的显卡根本不够用!所以需要各种压缩技术。
6.2 Fp16-mixed precision(混合精度训练)
流程:
- 前向/反向传播:使用fp16加速
- 参数更新:使用fp32保证精度
实现方式:
# torch推理
model.eval()
model.half() # 转为fp16
# Huggingface训练
# 在TrainingArguments里设置 fp16=True📝通俗解释:混合精度就像用"简写"来加快计算速度。比如计算"1000+2000"时,先用"1+2=3"快速算,最后再补上三个零。fp16计算快,但直接用它更新参数会"四舍五入"丢精度,所以更新时还是用fp32。
6.3 Int8-bitsandbytes
Int8最多只能表示-128~127的数字,精度较低。
bitsandbytes使用两种方法降低误差:
- Vector-wise quantization(向量级量化)
- Mixed precision decomposition(混合精度分解)
📝通俗解释:int8就像用"大概"来代替"精确"。比如精确值是3.14159,int8可能只能存3。虽然有误差,但通过一些技巧(分组量化、混合精度),误差可以控制在可接受范围内,同时省一半内存。
6.4 LoRA(Low-Rank Adaptation)
核心思想:微调时更新矩阵往往是低秩的,将其分解为两个低秩矩阵的乘积。
原参数:W ∈ R^(d×d),参数量 = d²
LoRA后:A ∈ R^(d×r) + B ∈ R^(r×d),参数量 = 2dr(r << d)优势:只训练少量参数,大部分参数保持预训练权重不变
📝通俗解释:LoRA就像给房子装修,不需要重建整个房子,只需要改某些部分。原来的大矩阵W就像整面墙,LoRA把它变成两个小矩阵A和B相乘(比如6×6=36个参数变成6×2+2×6=24个参数),参数量大大减少,但效果却差不多。
6.5 Gradient Checkpointing
原理:用时间换空间,不保存所有中间激活值,需要时重新计算
实现:
# torch
torch.utils.checkpoint.checkpoint(model, input)
# Huggingface
# 在TrainingArguments里设置 gradient_checkpointing=True📝通俗解释:就像考试时不带所有资料进考场,而是把重点记住,需要时现查。这样虽然计算慢一点,但能省很多内存。Gradient Checkpointing就是这个道理——不算出来存着,而是用的时候再算。
6.6 Torch FSDP + CPU Offload
- FSDP(Fully Sharded Data Parallel):将模型参数、梯度、优化器状态分布到多个GPU上
- CPU Offload:将部分数据动态转移到CPU,节省GPU显存
📝通俗解释:FSDP就像把一本大书分给多个人保管,而不是每人手里都有一本完整的。CPU Offload则像把不常用的东西从书架搬到仓库,需要时再拿回来。这样GPU的压力就小多了。
七、如何让大模型输出合规化?
问题:大模型输出内容不可控,可能产生敏感或不当言论
解决方案:
- 内容审核:模型生成内容后,转换为向量查询话术向量库
- 相似度匹配:若相似度低于阈值或查询不到结果,走兜底策略
- 兜底策略:按用户所在对话阶段使用不同话术,或使用万能兜底话术
📝通俗解释:就像餐厅里厨师做好菜后,还要经过服务员检查才能端给客人。大模型生成的"菜"也要经过"安检",合格的才能给用户,不合格的就换备用方案。
八、应用模式变更
案例:机器人销售场景
| 模式 | 特点 | 效果 |
|---|---|---|
| 纯大模型AI | 直接和用户对话,全流程大模型 | 用户说得太发散时不易收敛 |
| AI+大模型AI | 小模型意图识别+话术策略引导,大模型负责深度交互 | 任务引导更明确,更易引导用户成单 |
📝通俗解释:就像4S店卖车,新手销售员(AI小模型)负责接待和了解需求,资深销售(大模型)负责详细介绍和促成交易。分工合作,效果更好。
九、模型输出的分布比较稀疏,怎么处理?
处理方法:
- 调节softmax温度参数:平滑输出分布
- 引入正则化技术(如Dropout):减少对特定类别的过度依赖
📝通俗解释:稀疏分布就像考试时全班都只选A,其他选项没人选。温度参数就像"鼓励"学生多试试其他选项,让答案分布更均匀。Dropout则像随机"抛弃"一些答案,让模型不能只依赖某几个选项。
十、为什么相同prompt用greedy预测5次结果会不一致?
原因:Batch处理时padding导致
- 同一prompt与不同prompt组成batch时,padding数量不同
- 虽然attention中padding位置权重接近零,但深度累加后可能被放大
- Padding部分会对最终预测结果产生影响
📝通俗解释:就像同样的问题,在不同长度的试卷上作答可能不一样。短卷子要填很多空白,长卷子刚好合适。这些"空白"虽然不重要,但会影响整体答题状态,导致结果略有不同。
十一、In Context Learning vs Supervised Fine-tuning
| 方面 | In Context Learning | Supervised Fine-tuning |
|---|---|---|
| 原理 | 将few shot数据加入Prompt,不改变模型参数 | 用few shot数据继续训练,改变模型参数 |
| 对label准确率要求 | 较低,出错仍可凭借模型能力预测 | 较高,label必须准确 |
| 特点 | 临时学习,灵活但不稳定 | 持久学习,稳定但需要更多数据 |
📝通俗解释:ICL就像考试时把参考资料放在旁边,现查现用;SFT就像提前把知识学到脑子里。ICL灵活但容易受干扰,SFT更稳定但需要更多训练数据。
十二、大模型训练OOM问题及性能提升Trick
| 方法 | 说明 |
|---|---|
| 梯度累积 | 多个小batch累加计算梯度 |
| 混合精度训练 | 使用fp16减少内存 |
| 减轻模型参数 | 量化、剪枝、LoRA等 |
| 分布式训练 | 多卡并行 |
| 减少batch_size | 降低单次计算量 |
| 增加硬件资源 | 更多GPU/更大显存 |
| 数据处理优化 | 使用数据流水线并行加载 |
📝通俗解释:训练大模型像同时运行很多程序,内存不够就会崩溃。这些Trick就像:关掉不用的程序(减少batch)、用更省内存的版本(混合精度)、请更多电脑帮忙(分布式)等等。
十三、LLaMA模型输入句子可以无限长吗?
不可以,原因:
- 计算资源受限:显存和算力有上限
- 训练阶段问题:长句子导致梯度消失或梯度爆炸(最大似然估计是连乘形式)
- 推理阶段问题:增加预测错误率
📝通俗解释:就像人的记忆有限,读太长的文章会"忘了前面说什么"。大模型也一样,句子太长计算量爆炸不说,还容易出现梯度问题,预测准确性也会下降。
十四、如何让大模型处理更长的文本?
| 方法 | 说明 |
|---|---|
| 分块处理 | 将长文本分成多个片段,同时重叠保证连贯性 |
| 增加模型参数量 | 复杂化模型架构,提高对更长文本的捕捉与表达能力 |
| 优化位置编码 | 如RoPE、ALiBi等支持更长上下文的编码方式 |
| 扩展上下文窗口 | 特定训练技术扩展模型处理长度 |
📝通俗解释:就像看一本很厚的书,一次看不完,可以分章节读,读完后再拼起来理解。模型也可以这样处理长文本,或者通过"升级大脑"(增加参数)来增强处理能力。
十五、大模型推理时,显存中有那几部分数据?
| 部分 | 说明 |
|---|---|
| 模型参数 | 权重矩阵等 |
| 输入数据 | prompt和上下文 |
| 计算中间结果 | 激活值、注意力矩阵等 |
| K/V缓存 | 加速解码的Key-Value缓存 |
内存管理策略:某些框架采用延迟释放策略,保留显存以备后续使用,提高效率但导致显存持续占用
📝通俗解释:推理时显存就像个工作台,需要放:
- 模型本身(像工具箱)
- 要处理的问题(像原材料)
- 计算过程中的草稿纸(中间结果)
- 方便快速查找的"记忆卡片"(K/V缓存) 有些框架不舍得清空工作台,是为了下次再用时不用重新布置,但代价是显存一直被占着。
整理完成