大模型学习之资源占用
待测试更新
大模型学习之资源占用
资源:在本文中主要指的是cpu内存和gpu显存。
首先要分两种场景模型推理和模型训练进行讨论,针对不同的场景显存所需要加载的内容也不一样
0.预备知识
模型参数1B 代表10亿个参数;1byte(字节)=8bit(位)
参数精度 | fp32 | fp16/bp16 | int8/fp8 | Int4 |
---|---|---|---|---|
所占内存 | 4byte | 2byte | 1byte | 0.5byte |
eg:fp32 1B:4byte * 10亿 / 1024^3(kb mb gb) 约等于 3.725GB
量化
量化一般指的降低参数所占的内存空间,比如一个参数本来占4字节32位,现在为了节省空间,需要将其量化到int8也就是只允许参数占8位,量化的过程并不是简单的抹除小数位!
在神经网络模型导出的时候我们才会去做量化,以提高模型的推理速度以及模型所占显存大小,但量化同时会导致模型精度的下降。
量化方法的分类:
- QAT(Quant-Aware Training)也可以称为在线量化(On Quantization),它需要利用额外的训练数据,在量化的同时反向传播对模型权重进行调整,意在确保量化模型的精度不掉点。
- PTQ(Post Training Quantization)也可以称为离线量化(off Quantization),它是在已训练的模型上,使用少量或不使用额外数据,对模型量化过程进行校准,可能伴有模型权重的缩放。
常见的量化方式包括GPTQ,AWQ,GGUF,GGML,PTQ,QAT,AQLM
- GPTQ:是一种针对4位量化的训练后量化(PTQ)方法,主要关注GPU推理和性能。
- GPU推理,量化级别2-8bit,性能无明显下降,AUTO-GPTQ版本大于0.4.2可进行cpu推理,支持使用peft基于量化模型微调(LoRA方式)
- 该方法的思想是通过将所有权重压缩到4位量化中,通过最小化该权重的均方误差来实现。在推理过程中,它将动态地将权重解量化为float16,以提高性能,同时保存所占内存空间较低。
- 步骤:将输入张量*缩放因子scale?
- AWQ:类似GPTQ,但AWQ假设并非所有的权重对LLM对性能都同等重要。
- GPU推理,量化级别2-8bit,暂不支持cpu与微调
- 在量化过程中,不会对所有权重进行量化,相反只会量化对于模型保持有效性不重要的权重
- 步骤
- 校准:向预训练的LLM传递样本数据,以确定权重和激活的分布
- 确定重要的激活和相应的权重
- 缩放:将这些关键词实体放大,同时将其余权重量化为较低精度
- GGUF|GGML:GGUF是GGML的新版本,针对cpu进行优化。
- llama.cpp:gguf格式,支持多架构,可进行cpu,GPU混合推理,量化级别2-8bit,每个级别还有细分,支持基于量化模型finetune微调(LoRA)
- GGUF同样是一种量化方法,是LLM库的C++复制品,支持多种LLM。它允许用户在cpu上运行LLM,同时将其余部分层次转移到GPU上以加速运行。
- BnB(bit sand bytes):GPU推理,量化级别8bit,4bit,transformers,支持可将模型部分层挂载到cpu上,不进行量化,混合推理(仅8bit),支持使用peft基于4bit或者8bit微调(QLoRA)
推理框架
- Llama.cpp(c++ base) Arm 安卓 支持几乎所有模型 用户量大
- 特点:请求槽+动态批处理的机制+cpu/GPU混合推理
- n_gpu_layes是一个配置参数,用于指定神经网络中有多少层应该被加载到GPU(图形处理单元)上进行加速计算,通常情况下,将更多的层放到GPU上可以加快模型的推理速度
- vllm(python base)
- PagedAttention高效管理注意力键和值内存
- 连续(动态)批处理
- 量化:GPTQ,AWQ,SqueezeLLM等支持
- LightLLM(python base)
- 三进程异步协作
- 动态批处理
- FlashAttention
- TokenAttention
- 高性能Router
- fastLLM(c++ base) 国产
- Arm平台支持NEON指令集加速,x86平台支持AVX指令集加速,NVIDIA平台支持CUDA加速与llama.cpp很多功能类似。
- Ollama
- 不推理不占显存
TEMPLATE
- llama.cpp在做量化导出模型的时候需要预先设置
- 作用:定义模型的输出格式或交互逻辑,通常用于控制输入输出的结构和内容
- 详细结构说明:
- 系统消息(system):当有.system或.Tools信息时,插入<|im_start|>system标签,显示系统提示或工具签名。
- 消息处理逻辑:
- 用户消息(user):用户输入的内容标记为<|im_start|>user开头,<|im_end|>结尾。
- 助手消息(assistant):
- 如果有内容(.content)直接生成响应;
- 如果调用了工具(Toolcalls),生成工具调用结构化Json
- 工具响应(tool):如果工具返回结果,直接标记为用户的输入
- 提示消息(prompt):当.prompt存在时,直接标记为用户的输入
- 默认响应(Response):如果没有其他消息,直接生成助手回应。
常见的国产大模型:百川 千问 GLM Moss
模型权重:
优化器:
梯度:
激活状态:
推理框架:
1.推理
在实际应用的推理中,我们需要考虑的不仅是模型的精度,还要考虑模型的推理速度以及是否支持高并发。
推理时的显存消耗主要分成两部分:
- 模型权重:根据不同的参数精度进行计算
- 前向传播(根据经验一般占模型权重的20%左右):
- KV cache (注意力机制)
- 其他(输入的batch size以及缓冲区)
但实际运用中,我们还要根据我们设置的max token以及选用的推理框架进行区分,这里只记录的几种框架
测试设备:技嘉4090 24GB显存 模型为qwen2.5-instruct
说明:17756-19183 中17756为静态 19183为长文本推理时显存;
普通长文本占字符3k;特殊符号文本占10k
transformers | vllm | |
---|---|---|
7b pytorch 4 bit | 6684-7830 | \ |
7b pytorch 8 bit | 9757-12510(20000 有个瞬间撑大的现象 时间很短暂) | \ |
7b pytorch none | 15963-17233(基本占满24G) | 18391-20300 |
14b awq int4 | 10866-18966 | 17778-21760 |
14b gptq int4 | 10920-16861 | 17695-19194 |
14b gptq int8 | 17357-18234 | oom |
使用数据测试回复效果
普通长文本 | transformers | vllm |
---|---|---|
7b pytorch 4bit | 回复速度比14b快 正常回复 | \ |
7b pytorch 8 bit | 无异常 | \ |
7b pytorch none | 无异常 | 正常 |
14b awq int4 | 回复速度很慢 | 正常回复,模型的阅读理解没问题,但是逻辑分析能力(比大小,问最大最小值)欠佳 |
14b gptq int4 | 回复速度慢 | 乱码 |
14b gptq int8 | 回复速度慢 | \ |
多特殊符号 | transformers | vllm |
---|---|---|
7b pytorch int4 | 回复速度比14b快 正常回复 | |
7b pytorch 8 bit | 无异常 | |
7b pytorch none | 无异常 | 后半部分乱码 |
14b awq int4 | 未发生乱码,但回复速度很慢 | 乱码 |
14b gptq int4 | 回复速度慢,内容正常(上下文窗口似乎不大) | 输出效果不佳, |
14b gptq int8 | oom | \ |
llama.cpp
Llama.cpp的测试要稍微麻烦一点,因为量化版本可选项太多了,而且N GPU layers的自由度太高了
当N GPU layers设置为0,模型初始不占显存,但缺点是推理速度很慢
主要类型:
- Q8_k:8位量化。仅用于量化中间结果。与现有的Q8_0不同之处在于块大小为256。
- Q6_k:6位量化。超级块中有16个块,每个块包含16个权重。缩放因子使用8位进行量化。
- Q5_k:5位量化。与Q4_k具有相同的超级块结构,每个块中有32个权重,相应地使用了5.5位(bpw)
- Q4_k:4位量化。超级块中有8个块,每个块包含32个权重。
- Q3_k:3位量化。超级块中有16个块,每个块包含16个权重。
- Q2_k:2位量化。超级块中有16个块,每个块包含16个权重。
- 变体
llama.cpp|ggufv2 | 7b | 14b | 32b | 72b |
---|---|---|---|---|
q8_0 | ||||
q6_k | ||||
2.训练
Link
训练阶段的显存消耗主要分为:
- 模型权重
- 输入数据
- 激活值
- 在进行大模型训练时,GPU受限的往往是显存大小,而不是算力的问题。因此,激活重计算(也称为激活检查点)变得非常流行,它是一种以计算力为代价来减少内存使用的方法。激活重计算的主要思路是在反向传播的时候重新计算某些层的激活,代替前向计算后需要保存占用显存的操作,从而降低GPU显存的使用。具体来说,减少内存使用的方法。激活重计算的主要思路是在反向传播的时候重新计算某些层的激活,代替前向计算后需要保存占用显存的操作,从而降低GPU显存的使用。具体来说,减少显存的多少取决于我们选择重新计算那些层的激活
- 假设激活数据类型为fp16,没有使用序列并行:
- 无重计算的激活内存(sbh*l)
- 梯度
- 1.梯度一般可以存储fp32或fp16,梯度数据类型通常与模型数据类型匹配。混合精度训练中,梯度类型一般为fp16.
- 2.对fp32训练,梯度显存为4*参数量(byte)
- 3.对fp16/混合训练,梯度显存为2*参数量(byte)
- 优化器
- 1.Adam和AdamW:训练时需要主权重、动量和二阶动量,因此优化器的参数量为模型权重参数的3倍,而且由于优化器采用fp32形式保存参数,因此优化器参数所占显存为34参数量(byte)
- 2.BnB Bit sand Bytes类的8位优化器:主权重采用fp32,动量和二阶动量采用int8,所以显存(4+1+1)*参数量
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 廾匸!