一、模型蒸馏
-
一些概念
(1)模型蒸馏定义
模型蒸馏是一种压缩深度学习模型的技术,它通过将大型、复杂模型(称为“教师模型”)的知识转移到更小、更高效的模型(称为“学生模型”)中来实现。这种方法旨在使小模型能够达到或接近大模型的性能,同时减少计算资源消耗和提高推理速度。模型蒸馏通常通过以下几个步骤进行:
训练教师模型:首先通过大量数据训练一个大型但性能优异的教师模型。
转移知识:然后使用教师模型的输出来训练学生模型。这个过程中,不仅仅是复制教师模型的预测结果,更重要的是传递教师模型关于数据的"软知识",例如输出层的概率分布。比起硬标签(直接的分类结果),这些软标签能提供更多关于类别之间相对差异的信息。
训练学生模型:学生模型在训练过程中尽可能地模拟教师模型的行为和决策过程,从而学习到教师模型的知识。在某些情况下,学生模型同时也会使用原始的训练数据进行训练,以避免过度依赖教师模型可能的错误。
模型蒸馏的好处包括:
效率提升:使部署在资源受限的设备上的模型更加高效,例如移动设备和嵌入式系统。
减少计算成本:更小的模型通常意味着更低的计算成本和更快的推理速度。
保持性能:尽管减小了模型的规模,但通过模型蒸馏,学生模型仍然可以达到或接近教师模型的性能。
模型蒸馏是深度学习领域中一个非常有实用价值的研究方向,广泛应用于各种需要轻量级模型的场景,比如移动设备上的人脸识别、语音识别等。
(2)模型蒸馏的优势(相较于直接训练小模型)
模型蒸馏与直接使用有监督数据训练小模型之间的选择主要取决于几个关键因素和目标。以下是使用模型蒸馏而非直接训练的一些优势:
捕获教师模型的复杂性:大型教师模型通常能够捕获数据中的复杂模式和关系,因为它拥有更多的参数和深度。这种复杂性往往难以直接通过小模型来学习,特别是当有限的训练数据时。模型蒸馏可以帮助将这些复杂知识以更简洁的形式迁移到小模型中。
软标签提供的额外信息:在模型蒸馏中,教师模型的输出(通常是概率分布)被用作训练数据。这些输出被称为“软标签”,它们提供了比硬标签(即标准的单一类别标签)更丰富的信息。软标签展示了不同类别之间的相对关系和不确定性,有助于小模型更有效地学习数据的内在结构。
表现的提升:有研究表明,通过模型蒸馏得到的小模型在某些情况下能够超过直接使用相同数据和相同架构训练的小模型的表现。这是因为教师模型可能已经从原始训练数据中学到了有用的隐性知识,并且这些知识可以通过蒸馏过程传递给学生模型。
训练数据的限制:在一些情况下,可能原始的标注数据难以获得或成本高昂,而现存的大型模型已经在之前的大规模标注数据上进行了训练。通过模型蒸馏,可以利用已有的庞大模型而无需直接访问大量的标注数据。
降低过拟合风险:小型模型因为参数较少,直接在复杂或大规模数据集上训练时可能面临过拟合的风险。通过模型蒸馏,教师模型可以在一定程度上提供一种“正则化”的效果,帮助学生模型学习到更泛化的特征。
综上所述,模型蒸馏不仅可以帮助保留大模型的性能优势,同时还提供一种有效的方式来训练更小、更快、更适合部署的模型。这使得模型蒸馏成为一个在实际应用中非常有价值的策略。
二、vllm批量推理加速
-
简介
vLLM是伯克利大学LMSYS组织开源的大语言模型高速推理框架,旨在极大地提升实时场景下的语言模型服务的吞吐与内存使用效率。vLLM是一个快速且易于使用的库,用于 LLM 推理和服务,可以和HuggingFace 无缝集成。vLLM利用了全新的注意力算法「PagedAttention」,有效地管理注意力键和值。
其主要用于离线批量推理。
-
安装
vLLM 是一个 Python 库,还包含预编译的 C++ 和 CUDA(12.1)二进制文件。vLLM 的二进制文件默认使用 CUDA 12.1 和公共 PyTorch 发行版本进行编译。还提供使用 CUDA 11.8 和公共 PyTorch 发行版本编译的 vLLM 二进制文件,为了提高性能,vLLM 必须编译许多 cuda 内核。不幸的是,编译会导致与其他 CUDA 版本和 PyTorch 版本的二进制不兼容。python版本要求3.8以上。
也即是说使用vllm强要求cuda11.8或者12.1
三、模型量化(AWQ量化)
-
简介
-
安装
https://github.com/casper-hansen/AutoAWQ
注意直接用pip install 安装的时候会自带装上2.3.1的pytorch,这个torch的版本可能跟其他版本不兼容,所以安装完awq之后再重新安装一下pytorch
-
使用示例
(1)前期准备
注意模型做量化的时候用的是safetensors文件,如果是其他格式的文件需要先转换一下,例如从bin文件转化为safetensors文件的方式是先加载模型,然后直接保存
(2)量化模型:
注意这里的model_path文件夹包含safetensors文件,tokenizer文件夹包含tokenizer文件(这俩一般在一起,这里是我在保存的时候另外建了一个文件夹)
报错AttributeError: 'FieldInfo' object has no attribute 'required'
可以通过降级 pydrantic 版本或升级 deepspeed 版本来解决
降级pydrantic 版本会跟vllm的要求冲突: outlines 0.0.46 requires pydantic>=2.0, but you have pydantic 1.10.13 which is incompatible.
vllm 0.5.4 requires pydantic>=2.0, but you have pydantic 1.10.13 which is incompatible.
升级deepspeed版本可能会导致其他报错: 这个是最开始调试stanford_alpaca时出现的问题:
先尝试降级 pydrantic 版本:pip install pydantic==1.10.13
降级后问题解决,后面再看使用vllm会不会有问题
出现新的报错: out = awq_ext.gemm_forward_cuda(
RuntimeError: CUDA error: no kernel image is available for execution on the device
尝试之后无法解决,考虑换个量化的方法
研究GPTQ之后觉得问题可能是没有安装上kernel,需要从源安装试试
四、模型量化(GPTQ量化)
-
简介
Pass
-
安装
https://github.com/AutoGPTQ/AutoGPTQ
(1)直接使用pip list安装的话推理的时候会报错:
WARNING - Exllamav2 kernel is not installed, reset disable_exllama 2 to True. This may because you installed auto_gptq using a pre-build wheel on Windows, in which exllama kernels are not compiled. To use exllama_kernels to further speedup inference, you can re-install auto_gptq from source.
然后推理速度会变得很慢
(2)选择从源安装
注意这里的cuda版本有要求,如果用pytorch2.4+cu12.1会报错:
RuntimeError: The detected CUDA version (11.7) mismatches the version that was used to compile PyTorch (12.1). Please make sure to use the same CUDA versions.
服务器上面装的pytorch版本为11.7,因此这里需要安装pytorch2.4+cu118
auto-gptq 0.8.0.dev0+cu118
选择从源安装之后模型会找不到这个包,需要在执行的时候先导入路径,也可以添加环境变量
在文件开头加上,这里路径替换为文件路径
import sys
sys.path.append('/mlx/users/xujinghao.9941/playground/AutoGPTQ')
安装后成功
注:据说llama.cpp效果也不错,可以尝试一下
五、模型训练加速和显存计算
一文搞懂大模型在多GPU环境的分布式训练!_gpu对大语言模型执行-优快云博客
-
数据并行(DP)
数据并行 (Data Parallelism): 每张卡包含完整的模型副本,不同卡上的模型使用不同的数据集子集进行训练。在这种情况下,显存的需求与单卡上的需求几乎一致,但您可以增加批处理大小,因为现在可以将其跨多个GPU分配。
数据并行是最常用的并行训练方式,主要分为DataParallel(DP)和DistributedDataParallel(DDP)两种。
(1)DataParallel(DP)
DP核心思想是将一个大的batch数据分割成多个子batch,并将子batch分配给不同的GPU进行并行计算。DP里面只有一个优化器Optimizer,这个优化器Optimizer只在Master GPU上进行参数更新。
DataParallel采用的是Parameter Server并行架构,在实现多GPU或多节点并行训练时,存在一些固有的局限性:
通信开销大:每个**「计算节点」**在每次迭代中都需要与参数服务器进行多次通信,以获取最新的参数更新并将计算的梯度发送回去。这种频繁的通信会导致网络带宽成为瓶颈,尤其是当模型参数量大且GPU数量众多时,通信延迟和带宽消耗会显著影响整体训练速度。
负载不均衡:其中一个GPU被指定为Master GPU,负责汇总梯度和广播更新等,Master GPU可能会承担额外的通信和计算负担,导致负载不均衡。这不仅会影响该GPU的计算效率,也可能拖慢整个训练过程的速度。同时导致GPU利用率不足。
「仅支持单机多卡模式,无法实现多机多卡训练。」
(2)DistributedDataParallel(DDP)
DDP采用多进程架构,赋予了每个GPU更多的自由,支持多机多卡分布式训练。每个进程都拥有自己的优化器Optimizer,可独立优化所有步骤。每个进程中在自己的GPU上计算loss,反向计算梯度。
在DDP中,不存在所谓的Master GPU,所有GPU节点地位平等,共同参与训练过程的每一个环节。每个GPU都会计算loss和梯度,然后通过高效的通信协议(如AllReduce)与其它GPU同步梯度,确保模型参数的一致性。
总结:数据并行可以加快训练速度,但是每块显卡需要承担的计算资源都是全量模型,且还会增加通信的开销
-
模型并行(MP)
模型并行(Model Parallelism)通常用于解决单节点内存不足的问题。模型并行从计算图的切分角度,分为流水线并行和张量并行两种:
(1)流水线并行
按模型的「layer层切分」到不同设备,即「层间并行或算子间并行」(Inter-operator Parallelism),也称之为「流水线并行」(Pipeline Parallelism,PP)。流水线并行,就是由于模型太大,无法将整个模型放置到单张GPU卡中,因此,将模型的不同层放置到不同的计算设备,降低单个计算设备的显存消耗。
-
朴素流水线并行:一层一层的传输数据,同一时间只有一个GPU在工作。
-
GPipe流水线并行:将一个大的mini-batch进一步细分为多个更小的、相等大小的微批次(microbatches),并在流水线并行的框架下独立地对每个microbatch执行前向传播和反向传播。然后将每个mircobatch的梯度相加,就能得到整个batch的梯度。
(2)张量并行
将计算图层内的「参数切分」到不同设备,即「层内并行或算子内并行」(Intra-operator Parallelism),也称之为「张量并行」(Tensor Parallelism,TP)。张量并行旨在通过将模型参数和中间张量在多个设备(如GPU)之间进行切分,以克服单个设备内存限制的问题。
张量并行要解决的两个核心问题:如何合理地将参数切分到不同设备,以及如何确保切分后的计算结果在数学上保持一致。大语言模型都是以Transformer结构为基础,Transformer结构主要由以下三种算子构成:
-
嵌入式表示(Embedding)
-
矩阵乘法(MatMul)
-
交叉熵损失(Cross Entropy Loss)
这三种类型的算子均需要设计对应的张量并行策略,才可以将参数切分到不同设备。
-
嵌入式表示
将Embedding层的参数按词维度切分,每个计算设备只存储部分词向量,然后通过汇总各个设备上的部分词向量,从而得到完整的词向量。
-
矩阵乘法
矩阵乘的张量模型并行充分利用矩阵分块乘法的原理。包括按列切块和按行切块两种。
按列切块:
按行切块:
-
交叉熵损失
同嵌入层
-
训练所需显存计算
(1)显存占用计算
以llama13b为例:设模型参数量为 Φ
训练所需显存=模型权重+优化器参数+梯度+激活参数+其他参数(可忽略不计)
模型权重=存储类型/8 * 模型参数量,如13B模型,半精度bf16,需要2Φ = 26G
梯度=模型权重 = 2Φ
优化器以adamW为例,需要保存原始参数,一阶动量和二阶动量,同时要求只能是fp32的精度,需要显存(4*3)Φ = 12Φ = 156G
激活参数等跟token长度,batch_size等有关,且是相乘的关系,例如当batch_size为1,token长度为256大概需要2G左右,512则需要4G,以此类推。
所以总的显存 = 16Φ + 激活参数 = 210G
(2)模型并行的方案:deepspeed之zero
zero分为1,2,3三种,每一种都是在前面的基础之上增加并行度
zero-1是优化器分区
zero-2加上梯度分区
zero-3加上模型权重分区
deepspeed还提供了一种offload的方案,将一部分数据放到内存中,使用cpu来计算,从而节省显存