大型语言模型从训练到推理的介绍
参考论文:https://arxiv.org/pdf/2401.02038v1
一、训练方面
1、数据预处理
(1)除噪音
a.去除离群值:使用统计方法(如 z-score、IQR)识别并移除异常数据点。
import numpy as np from scipy import stats data = np.array([10, 12, 12, 13, 12, 100]) # 100 是离群值 # 计算 z-score z_scores = np.abs(stats.zscore(data)) # 设置阈值,通常是 3 threshold = 3 # 过滤离群值 filtered_data = data[z_scores < threshold] print(filtered_data) # 输出 [10 12 12 13 12]
b.平滑数据:使用移动平均或其他平滑技术减少噪音。
import pandas as pd data = pd.Series([10, 12, 13, 12, 15, 12, 16, 18, 20, 22]) # 移动平均 smoothed_data = data.rolling(window=3).mean() print(smoothed_data) # 输出平滑后的数据
c.滤波器应用:如高斯滤波,针对图像或时间序列数据。
import numpy as np from scipy.ndimage import gaussian_filter1d data = np.array([10, 12, 13, 12, 15, 12, 16, 18, 20, 22]) # 高斯滤波 smoothed_data = gaussian_filter1d(data, sigma=1) print(smoothed_data) # 输出平滑后的数据
(2)规范化文本格式
a.转换为小写,将所有文本转换为小写字母,以确保大小写不影响分析
b.去除标点符号,移除文本中的标点符号,通常使用正则表达式或字符串方法
c.去除多余的空白字符,去除文本中的多余空格,包括首尾的空白以及连续的空格
d.替换或移除特殊字符,替换特殊字符(如换行符、制表符)或移除不必要的字符
e.标准化拼写和缩写,替换常见缩写词或拼写错误以保持一致性
f.词形还原和词干提取,词形还原(Lemmatization)和词干提取(Stemming)是将词汇规范化到其基本形式
from nltk.stem import WordNetLemmatizer from nltk.tokenize import word_tokenize import nltk nltk.download('punkt') nltk.download('wordnet') lemmatizer = WordNetLemmatizer() text = "The cats are running and playing." tokens = word_tokenize(text) lemmatized_tokens = [lemmatizer.lemmatize(token) for token in tokens] lemmatized_text = ' '.join(lemmatized_tokens) print(lemmatized_text) # 输出 "The cat are running and playing."
对于词干提取,可以使用 NLTK 的 PorterStemmer
from nltk.stem import PorterStemmer stemmer = PorterStemmer() text = "The cats are running and playing." tokens = word_tokenize(text) stemmed_tokens = [stemmer.stem(token) for token in tokens] stemmed_text = ' '.join(stemmed_tokens) print(stemmed_text) # 输出 "the cat are run and play."
(3)处理缺失值
a.删除缺失值
如果缺失值很少且删除不会影响分析结果,可以直接删除包含缺失值的行。
如果某些列的缺失值非常多,可以选择删除这些列。
b.用统计量填充缺失值
用该列的均值填充缺失值,适用于数值型数据。
用中位数填充缺失值,适用于数值型数据,尤其当数据分布不对称时。
c.使用插值法填充缺失值
通过线性插值法填充缺失值,适用于时间序列数据或有序数据。
d.使用特定值填充缺失值
用一个常量值填充缺失值,例如填充“未知”或“0”。
e.使用机器学习模型填充缺失值
使用回归模型等预测缺失值,适用于数据中存在足够的相关性时。
2、训练架构
目前所有的大型语言模型(LLM)都基于Transformer架构构建,这使得这些模型能够扩展到数十亿甚至万亿参数级别。典型的预训练语言模型(PLM)架构可以分为三类:Encoder-only、Encoder-decoder和Decoder-only架构。Encoder-decoder架构是由Encoder和Decoder两个主要组件构成的。Encoder由多层Transformer的多头自注意力层组成,用于编码输入序列。Decoder则利用跨注意力机制对Encoder的输出进行自回归式生成目标序列。这种架构是T5、flan-T5和BART等著名LLM的基础。
3、预训练任务
预训练任务是训练大型语言模型(LLM)的关键步骤。在预训练过程中,这些模型利用大量的文本数据,通过自监督学习的方式学习丰富的语言表示。语言建模是最常见的自监督学习任务之一。在这个任务中,模型需要预测给定上下文中的下一个词。通过这个任务,模型可以学习到与词汇、语法、语义和文本结构相关的信息,从而获得对语言的深入理解。具体来说,语言建模的目标是最大化文本数据的似然概率。对于给定的文本序列w1, w2, ..., wT,模型需要预测每个位置t的词wt,条件概率为P(wt|w1, w2, ..., wt-1)。这个过程可以用交叉熵损失函数来表示。除了语言建模,还有一些其他的预训练任务,如自动回归式地恢复被随机替换的词。这些预训练任务都有助于模型学习到丰富的语言知识,为后续的微调和应用任务奠定基础。
4、并行训练
(1)数据并行
把数据分成多个小块,每个块在不同的处理单元(如GPU)上进行计算。每个处理单元计算自己的数据块,然后把结果合并。假设你有一个大数据集和多个GPU。你把数据集分成几个部分,每个GPU处理其中一部分,最后把每个GPU的计算结果汇总起来。
(2)流水线并行
把模型的不同层分配到不同的处理单元上,每个处理单元按顺序处理数据。数据流动通过这些处理单元,就像生产线上的产品一样。把神经网络的不同层分配到不同的GPU上。输入数据从第一层经过,然后依次流经后续的每一层,每一层的计算可以并行进行。
(3)张量并行
把模型的张量(即模型参数)分成多个部分,在不同的处理单元上进行计算。每个处理单元只处理张量的一部分,并在计算中协调合作。如果你的模型非常大,你可以把模型的权重矩阵分成几块,每个GPU处理权重的一部分,多个GPU协作计算整个模型的前向和反向传播。
5、模型微调
模型微调(Fine-Tuning)是训练大型语言模型的重要步骤之一。主要包括以下三种类型:
(1)监督式微调(Supervised Fine-Tuning, SFT)
在大规模预训练的基础上,通过有标签的数据集对模型进行进一步调整,使其更好地适应目标任务。指令微调(Instruction Tuning)是SFT的一种常见形式,通过(指令,输出)对的数据集来增强模型的能力和可控性17。
(2)对齐微调(Alignment Tuning)
由于预训练数据的局限性,模型可能会产生违背人类意图的行为,如生成虚假信息、带有偏见或误导性内容等。对齐微调旨在使模型更加有益、诚实和无害。一种常用的方法是基于强化学习与人类反馈(RLHF)的方式,训练一个奖励模型来指导模型的微调。
(3)参数高效微调(Parameter-efficient Tuning)
与SFT和对齐微调不同,这种方法只微调模型的一小部分参数,而保持大部分预训练参数不变,从而显著降低计算和存储成本。常见的方法包括低秩适应(LoRA)、前缀微调(Prefix Tuning)和P-Tuning等。这些方法使得即使在资源受限的环境下,也能进行高效的模型微调。
二、推理方面
1、模型压缩
模型压缩是提高大型语言模型推理效率的重要方法之一。主要包括以下几种技术:
(1)知识蒸馏(Knowledge Distillation)
将知识从一个大型(教师)模型转移到一个更小(学生)模型,通过拟合两个模型的软目标来实现。这种方法可以让学生模型从教师模型的多个中间层中学习到更多合适的中间表示。
(2)模型剪枝(Model Pruning)
从大型模型的参数矩阵中移除冗余部分。分为无结构剪枝和有结构剪枝两种方式。有结构剪枝可以在不影响模型普适性的情况下,删除30-40%的权重。
(3)模型量化(Model Quantization)
将浮点运算转换为定点运算,从而降低存储和计算成本。但过度量化会导致模型性能下降,需要采用诸如BinaryBERT等方法来优化低精度量化。
(4)权重共享(Weight Sharing)
在模型的不同部分使用相同的参数集,从而减少需要学习的参数数量,提高计算效率。ALBERT就采用了跨层参数共享的策略。
(5)低秩近似(Low-rank Approximation)
通过低秩分解来创建更紧凑的模型,在部署到资源受限设备时特别有用。DRONE就是一种基于低秩分解的方法,可以在保证推理性能的同时,实现超过1.3倍的加速比。
2、并行计算
3D并行
3、内存调度
内存调度是在部署大型语言模型时解决硬件内存限制的重要策略。它涉及到在推理或推断阶段有效组织和管理内存访问模式,优化中间表示、模型参数和激活值的检索和存储,确保推理过程既准确又低延迟。例如,BMInf[182]利用虚拟内存的原理,通过智能调度每一层的参数在GPU和CPU之间实现了大模型的高效推理23。另外,FlexGen[186]提出了一种基于GPU的大语言模型高吞吐推理方法,通过动态内存管理和推理优化实现了单GPU上的高效推理53。
4、结构优化
结构优化是提高大型语言模型推理效率的另一个重要方法。它主要包括以下几个方面:
(1)注意力头剪枝(Attention Head Pruning)
Michel等人发现,通过剪枝注意力头可以提高BERT在WMT和BERT任务上的性能,他们提出了一种基于梯度的重要性评估指标来增强剪枝的效果。
(2)层剪枝(Layer Pruning)
Fan等人在训练过程中随机丢弃层,在测试时选择合适深度的子网络,从而实现了较好的推理性能。
(3)低秩分解(Low-rank Approximation)
低秩分解方法可以有效压缩模型大小,Chen等人22提出的DRONE方法不仅保证了大模型的推理性能,还实现了1.3倍以上的加速比。