DeepSeek-LLM模块解析
1. 云端模型转换阶段(PC/服务器)
推荐配置:
- 操作系统:Linux x86_64(如Ubuntu 18.04/20.04)
- CPU:8核及以上(建议16核,转换大模型更快)
- 内存:32GB及以上(大模型建议64GB或更高)
- 硬盘:SSD,剩余空间建议100GB以上
- Python:3.8及以上
- 显卡:可选(部分转换/量化流程可用GPU加速,但不是必须)
说明:
- 转换大模型(如7B、13B、70B参数量)时,内存和CPU越高越快,内存不足会导致转换失败或极慢。
- 量化和导出过程主要依赖CPU和内存。
2. 板端推理阶段(Rockchip NPU开发板)
常见平台:
- RK3588、RK3576、RK3562等瑞芯微NPU芯片开发板
典型配置:
- CPU:4核/8核 ARM Cortex-A系列
- NPU:2T/6T/8T算力(不同芯片型号不同)
- 内存:4GB及以上(推荐8GB,模型越大越需要更大内存)
- 存储:16GB eMMC/TF卡及以上
- 操作系统:Linux(Debian/Ubuntu/自带SDK)
说明:
- 板端主要依赖NPU进行推理,CPU负责调度和数据处理。
- 内存越大,能加载的模型越大,推理更流畅。
首先要知道什么是量化,为什么要量化
量化,就是把神经网络中的“高精度”数据(比如32位浮点数FP32)转换成“低精度”数据(比如8位整数INT8、16位整数INT16等)的过程。
- 权重量化:把模型的参数(权重)从FP32变成INT8/INT4等。
- 激活量化:把模型推理时每一层的输出(激活值)也从FP32变成INT8/INT4等。
二、为什么要做量化?
1. 减少模型体积
- 32位浮点数每个参数占4字节,8位整数只占1字节。
- 量化后模型文件会大大变小,方便在嵌入式、移动端等资源有限的设备上部署。
2. 加速推理速度
- 低精度整数运算比高精度浮点运算快得多,硬件(如NPU、DSP、CPU)对INT8/INT4等支持更高效。
- 量化后模型在推理时能大幅提升速度,降低延迟。
3. 降低能耗
- 低精度计算消耗的电能更少,适合边缘设备、移动设备等对功耗敏感的场景。
4. 降低内存占用
- 激活值和权重都变小,推理时内存占用也随之降低。
原始模型(HuggingFace格式)
↓
模型转换(rkllm.load_huggingface())
↓
RKLLM格式(.rkllm文件)
↓
板端部署运行
如何用RKLLM-Toolkit把大模型转换成瑞芯微NPU能用的.rkllm格式,并进行量化优化?
一、准备工作
- 环境准备
- 推荐在Linux环境下操作(如Ubuntu)。
- 安装Python 3.8~3.12。
- 安装CUDA(如用GPU加速)。
- 安装PyTorch、transformers等依赖。
- 下载并安装RKLLM-Toolkit(通常在瑞芯微官方或GitHub获取)。
- 模型准备
- 从HuggingFace等平台下载你需要的大模型(如DeepSeek、Qwen、Llama等)。
- 确认模型格式为HuggingFace Transformers标准格式。
二、转换与量化流程,编写转换脚本
from rkllm.api import RKLLM
import osos.environ['CUDA_VISIBLE_DEVICES']='0' # 指定GPUmodelpath = '/path/to/DeepSeek-R1-Distill-Qwen-1.5B' # 你的模型路径
llm = RKLLM()# 1. 加载模型
ret = llm.load_huggingface(model=modelpath, model_lora=None, device='cuda', dtype="float32", custom_config=None, load_weight=True)
if ret != 0:print('Load model failed!')exit(ret)# 2. 构建量化参数
dataset = "./data_quant.json" # 量化校准数据,格式见下方说明
quantized_dtype = "W8A8" # 权重8bit,激活8bit,常用还有"W4A16"
quantized_algorithm = "normal" # 量化算法,常用"normal"或"grq"
target_platform = "RK3576" # 目标平台
num_npu_core = 3 # NPU核数# 3. 构建并量化模型
ret = llm.build(do_quantization=True,optimization_level=1,quantized_dtype=quantized_dtype,quantized_algorithm=quantized_algorithm,target_platform=target_platform,num_npu_core=num_npu_core,extra_qparams=None,dataset=dataset,hybrid_rate=0,max_context=4096
)
if ret != 0:print('Build model failed!')exit(ret)# 4. 导出.rkllm模型
ret = llm.export_rkllm(f"./{os.path.basename(modelpath)}_{quantized_dtype}_{target_platform}.rkllm")
if ret != 0:print('Export model failed!')exit(ret)
三. 量化校准数据(data_quant.json)
[
{"input": "Human: 你好!\nAssistant: ", "target": "你好!我是人工智能助手!"},
{"input": "Human: 今天天气怎么样?\nAssistant: ", "target": "今天天气晴朗。"}
]
4. 常用量化参数说明
- quantized_dtype:
- "W8A8":权重8bit,激活8bit,兼容性好,精度高
- "W4A16":权重4bit,激活16bit,压缩率更高,适合极致优化
- quantized_algorithm:
- "normal":普通量化
- "grq":分组量化,适合W4A16
- target_platform:"RK3576"、"RK3588"等
- num_npu_core:NPU核数,建议3
5. 运行脚本
python export_rkllm.py
成功后生成DeepSeek-R1-Distill-Qwen-1.5B_W8A8_RK3576.rkllm的文件。
你是怎么做量化优化的,效果如何?
做法:
下面是效果
实现方式:
ASR模块量化实现方式
# 动态量化实现
quantize_dynamic(model_input=filename,model_output=filename_int8,op_types_to_quantize=["MatMul"], # 只量化矩阵乘法操作weight_type=QuantType.QInt8, # 权重量化为INT8
)
数据说明:
1. 模型
- 这里是大语言模型的名字,比如 DeepSeek-1.5B、Phi-3-3.8B。
- “1.5B”表示参数量大约15亿,“3.8B”表示38亿。
2. 平台
- 指的是运行模型的硬件平台,比如 RK3576(瑞芯微的NPU芯片)。
3. 量化类型
- 这是模型压缩和加速的方法。
- w4a16:权重用4位(w4),激活用16位(a16)存储。
- w8a8:权重和激活都用8位存储。
- 数字越小,模型越小,速度越快,但精度可能略有下降。
4. TTFT(ms)
- “首Token延迟”(Time To First Token),单位是毫秒(ms)。
- 意思是:你输入一句话后,模型多久能给出第一个字/词的回复。
- 数字越小,响应越快。
5. Tokens/s
- “每秒生成Token数”,可以理解为模型每秒能输出多少个字/词。
- 数字越大,生成速度越快。
6. 内存(G)
- 运行模型时需要占用的内存,单位是GB。
- 数字越小,说明模型更省内存,更适合嵌入式设备。
1. 量化数值范围怎么确定?
(1)权重量化的范围
- 统计所有权重的最大值和最小值,比如最大是+5.0,最小是-4.0。
- 计算一个合适的区间,比如[-5.0, +5.0]。
- 把这个区间“均匀分成”256份(如果是8位),每一份用一个整数表示。
(2)激活量化的范围
- 激活值是模型运行时每一层的输出,分布会变化。
- 通常用校准数据(比如几百条真实输入)跑一遍模型,记录每一层激活的最大最小值。
- 也可以用“均值±几倍标准差”来避免极端异常值影响。
量化就是把原本很大的浮点数(比如-10.123到+8.456)压缩到很小的整数范围(比如-128到127)。
2. 量化中的问题:如何把FP32的数值合理地压缩到INT8范围内?
问题本质
- FP32:32位浮点数,能表示很大很小的数,精度高。
- INT8:8位整数,只能表示-128到127之间的整数。
- 目标:把FP32的数值“映射”到INT8的范围内,既不溢出,也尽量保留原始信息。
3. 具体做法(线性量化为例)
步骤一:确定FP32的数值范围
- 假设某一层的FP32权重,最小值是min,最大值是max。
- 比如min = -5.0,max = +5.0。
步骤二:计算缩放因子(scale)和零点(zero point)
- scale = (max - min) / (127 - (-128)) = (max - min) / 255
- zero_point = -128 - min / scale
- 这样可以把[min, max]线性映射到[-128, 127]。
1. 什么是scale(缩放因子)?
- scale就是“放大倍数”。
- 比如:1米 = 100厘米,这里的100就是scale。
- 在量化里,scale告诉你“1个FP32单位等于多少个INT8单位”。
举个例子:
- 如果FP32的范围是[-5.0, +5.0](总共10个单位)
- INT8的范围是[-128, +127](总共255个单位)
- 那么scale = 255 ÷ 10 = 25.5
- 意思是:FP32的1个单位,对应INT8的25.5个单位
- 实际上,ONNX、RKLLM-Toolkit等量化工具会自动帮你统计min/max、计算scale/zero_point,并批量完成所有权重和激活的量化。
- 你只需要提供模型和校准数据,工具会自动完成映射。
2. 什么是zero_point(零点)?
- zero_point就是“零点偏移”。
- 比如:摄氏度0度 = 华氏度32度,这里的32就是zero_point。
- 在量化里,zero_point告诉你“FP32的0对应INT8的哪个数”。
1. 什么是“权重”和“激活”?
- 权重:神经网络模型里“记住知识”的参数,像人的记忆。
- 激活:模型在推理时每一层“中间计算出来的结果”,像人的思考过程。
2. w4a16、w8a8到底是什么意思?
w4a16
- w4:权重用4位来存储(原来通常用32位,现在只用4位,体积变成原来的1/8)。
- a16:激活用16位来存储(原来通常用32位,现在只用16位,体积变成原来的一半)。
w8a8
- w8:权重用8位来存储(体积变成原来的1/4)。
- a8:激活也用8位来存储(体积也变成原来的1/4)。
🎯 量化在项目中的具体应用
1. 权重量化 (Weight Quantization)
- 静态量化: 模型权重在推理前就转换为INT8/INT4
- 内存优化: 显著减少模型文件大小
- 推理加速: 整数运算比浮点运算更快
- 精度保持: 通过量化校准保持模型精度
2. 激活量化 (Activation Quantization)
- 动态量化: 激活值在推理过程中实时量化
- 实时处理: 需要计算激活值的分布参数
- 进一步优化: 与权重量化结合实现更大优化
3. 混合量化策略
- W8A8: 权重8位 + 激活8位(平衡精度和性能)
- W4A16: 权重4位 + 激活16位(更激进的压缩)
- 分组量化: 支持不同组大小的量化(g128, g256, g512)
📊 量化效果总结
- 内存节省:
- ASR模型: 50-75%内存减少
- LLM模型: 4位量化可节省75%内存
- 推理加速:
- 整数运算比浮点运算快2-4倍
- 在RK3576 NPU上优化效果更明显
- 精度保持:
- 通过量化校准和算法优化
- 在可接受的精度损失下实现大幅优化
- 嵌入式友好:
- 适合资源受限的嵌入式设备
- 支持RK3576等NPU硬件加速
怎么设计的方案,基于哪些技术,业界有哪些做法,我怎么实现的,验证方法?
总分阐述项目做了什么事情,分条说明,通俗,