待测试更新

大模型学习之资源占用

资源:在本文中主要指的是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个权重。
  • 变体
    • image-20241213160742078
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)*参数量