llm-optimize-deploy

将transformer层叠以创建大型模型会在各种语言任务中带来更高的准确性、少样本学习能力,甚至接近人类的新兴能力。这些基础模型在训练过程中成本高昂,而在推理过程中(一个经常发生的成本)可能需要大量内存和计算资源。如今最受欢迎的大型语言模型(LLMs)可以达到数百亿到数千亿个参数的规模,并且根据使用情况,可能需要处理长输入(或上下文),这也会增加成本。

本文讨论了LLM推理中最紧迫的挑战,以及一些实用的解决方案。读者应该对transformer架构和注意力机制有基本的理解。理解LLM推理的复杂性至关重要,我们将在接下来的部分进行介绍。

:上篇译文有对 transformer 有相关的介绍,以及相关编码笔记入门;或者深入学习CS25: Transformers United V2 video

LLM 推理的核心指标

想要优化 LLM 推理,首先要了解 LLM 推理的核心指标。

  • Time To First Token (TTFT): 首 Token 延迟,即从输入到输出第一个 token 的延迟。在在线的流式应用中,TTFT 是最重要的指标,因为它决定了用户体验。
  • Time Per Output Token (TPOT): 每个输出 token 的延迟(不含首个Token)。在离线的批处理应用中,TPOT 是最重要的指标,因为它决定了整个推理过程的时间。
  • Latency:延迟,即从输入到输出最后一个 token 的延迟。 Latency = (TTFT) + (TPOT) * (the number of tokens to be generated). Latency 可以转换为 Tokens Per Second (TPS):TPS = (the number of tokens to be generated) / Latency。
  • Throughput:吞吐量,即每秒针对所有请求生成的 token 数。以上三个指标都针对单个请求,而吞吐量是针对所有并发请求的。

我们将 LLM 应用分为两种:

  • 在线流式应用:对 TTFT、TPOT、Latency 敏感,需要尽可能快的生成 token。
  • 离线批量应用:对 Throughput 敏感,需要在单位时间内尽可能多的生成 token。

而实际在某种应用(如在线流式应用),我们也应该在Latency 和 Throughput 之间进行权衡,提高 Throughtput 可以提高单个 GPU 承担的并发数,从而降低推理成本。

理解大语言模型推理 Understanding LLM inference

对于大多数流行的仅解码器型大型语言模型(LLMs)(比如GPT-3),它们通常是基于因果建模目标进行预训练的,基本上是作为下一个单词的预测器。这些LLMs将一系列标记(tokens)作为输入,并自回归地生成后续的标记,直到满足停止条件(比如生成标记的数量限制或停止词列表),或者直到生成特殊的<end>标记来标志生成结束。这个过程包括两个阶段:预填充阶段和解码阶段。

需要注意的是,标记是模型处理的语言的原子部分。一个标记大约相当于四个英文字符。自然语言中的所有输入在输入模型之前都会转换为标记。

预填充阶段或处理输入 Prefill phase or processing the input

在预填充阶段,大型语言模型(LLM)处理输入的标记以计算中间状态(键和值),这些中间状态用于生成“第一个”新标记。每个新标记都依赖于所有先前的标记,但因为知道输入的完整范围,在高层次上,这是一个高度并行化的矩阵-矩阵操作。它有效地充分利用了GPU的利用率。

ChatGPT:预填充阶段是在模型进行生成之前处理输入的阶段。在这个阶段,模型接收到输入数据(通常是一系列标记或者文本),并对其进行预处理。这个阶段的目的是为了将输入转换为模型可以理解和处理的格式。

在处理输入时,通常会进行一些操作,比如将文本分割成标记(tokens),对文本进行编码以便模型能够理解,可能还会进行标准化、清洗或其他预处理操作。预处理的目标是将输入数据转换为模型能够接受并有效处理的形式,以便在解码阶段进行后续的生成任务。

解码阶段或生成输出 Decode phase or generating the output

在解码阶段,大型语言模型(LLM)以自回归的方式逐个生成输出标记,直到达到停止条件为止。每个顺序输出标记都需要了解所有先前迭代的输出状态(键和值)。这类似于一个矩阵-向量操作,与预填充阶段相比,它没有充分利用GPU的计算能力。数据(权重、键、值、激活)从内存传输到GPU的速度决定了延迟,而不是计算的速度。换句话说,这是一个受限于内存的操作。

本文介绍的许多推理挑战及相应的解决方案都涉及优化这个解码阶段:高效的注意力模块、有效管理键和值等等。

不同的LLMs可能使用不同的分词器,因此,直接比较它们之间的输出标记可能并不直观。在比较推理吞吐量时,即使两个LLM的每秒输出的标记数量相似,如果它们使用不同的分词器,它们可能并不等价。这是因为相应的标记可能表示不同数量的字符。

ChatGPT: 解码阶段是大型语言模型(LLM)根据先前生成的部分序列和中间状态,生成最终输出的阶段。在这个阶段,模型使用已经计算得到的中间状态(keys和values)以及先前生成的标记序列,来自回归地生成接下来的标记。

在解码阶段,模型根据先前的上下文和当前生成的标记,预测下一个标记,并将其追加到已生成的序列中。这个过程会一直持续,直到达到设定的停止条件,比如生成了特定数量的标记、达到了预先设定的序列长度,或者遇到了特殊的结束标记。

解码阶段涉及逐步生成输出序列的过程,模型根据先前的部分输出和中间状态,逐步推断和生成接下来的标记,直到生成完整的输出序列为止。

批处理 Batching

批处理是提高GPU利用率和吞吐量的最简单方法。由于多个请求使用相同的模型,权重的内存成本被分摊开来。将较大的批次一次性传输到GPU进行处理将更充分地利用可用的计算资源。

然而,批处理大小只能增加到一定限度,超过这个限度可能会导致内存溢出。要更好地理解为什么会发生这种情况,需要看一下键值(KV)缓存和LLM内存需求。

传统的批处理(也称为静态批处理)是不够优化的。这是因为在批处理中的每个请求中,LLM可能会生成不同数量的完成标记,因此它们具有不同的执行时间。结果是,批处理中的所有请求必须等到最长的请求完成,这可能会加剧生成长度存在较大变化时的等待时间。有一些方法可以缓解这个问题,比如在途批处理(in-flight batching),这将在稍后讨论。

ChatGPT:批处理是在深度学习中一种重要的优化技术,用于同时处理多个样本或数据点。在大型语言模型(LLM)的推理过程中,批处理也起着关键的作用。

通常情况下,批处理允许模型同时处理多个输入序列,从而提高了计算效率。LLMs可以在推理过程中对多个输入序列执行操作,这意味着可以将多个序列的计算合并在一起,利用GPU并行性和计算能力,从而减少总体的推理时间。

在推理阶段,合理设置批处理大小可以有效地提高模型的性能。较大的批处理大小通常会带来更高的吞吐量和更高效的GPU利用率,但同时也可能增加内存占用和计算复杂度。因此,在选择批处理大小时需要权衡这些因素,以便在保持高性能的同时避免资源浪费。

KV缓存 Key-value caching

KV(键值)缓存是解码阶段常见的一种优化技术。在解码阶段,每个时间步生成一个标记,但每个标记都依赖于之前所有标记的键和值张量(包括预填充时计算的输入标记的KV张量,以及直到当前时间步计算的任何新KV张量)。

为了避免在每个时间步重新计算所有这些张量的值,可以将它们缓存到GPU内存中。在每次迭代中,当新的元素被计算出来时,它们被简单地添加到正在运行的缓存中,以便在下一次迭代中使用。在某些实现中,模型的每一层都可能有一个KV缓存。

通过使用KV缓存,可以避免重复计算先前时间步骤中生成的中间状态,提高了解码阶段的效率。这样做可以减少计算成本,加快推理速度,并有效利用GPU的内存和计算资源。

ChatGPT:键值(key-value)缓存是指在处理大型语言模型(LLMs)推理过程中对中间状态(键和值)进行缓存以提高效率的方法。在LLMs中,注意力机制的实现依赖于键值对的存储和检索,而这些键和值通常是在输入序列处理过程中计算得到的。

通过缓存键和值,可以避免在每次生成新标记时都重新计算它们,从而节省计算资源和时间。当处理多个请求时,如果某些键值对在不同请求中重复出现,通过缓存这些中间状态,可以减少冗余计算,提高推理效率。

:但是对于参数量比较大的模型,kv cache成为瓶颈, 常使用MQA, GQA来避免,在llama2模型参数34B/70B中使用GQA来缓解。

在图示中,可以将KV缓存的作用在预填充(Prefill)和解码(Decode)阶段进行说明。

图1. 键值缓存机制的示例

在图示中,可以将KV缓存的作用在预填充(Prefill)和解码(Decode)阶段进行说明。

预填充阶段(Prefill Phase)

  • 高度并行化的操作: 在预填充阶段,模型同时计算所有输入标记的KV张量。这是一个高度并行化的操作,可以在GPU上同时进行计算。每个输入标记都经过处理,其对应的键值对被计算并存储在KV缓存中。
  • KV张量计算: 图示中展示了多个输入标记(token),每个标记经过模型处理后产生对应的键(keys)和值(values)张量。这些张量在计算后被缓存,以备后续解码阶段使用。

解码阶段(Decode Phase)

  • 自回归生成新标记: 在解码阶段,模型逐步生成新的输出标记。对于每个时间步,模型根据先前生成的标记、前一个时间步的KV张量以及先前缓存的KV张量来计算新的输出标记。这个过程是自回归的,每个新的标记都依赖于先前的计算结果。
  • KV缓存的利用: 在解码阶段,模型会使用之前缓存的KV张量,这样就避免了在每个时间步重新计算所有先前的中间状态。随着每个时间步的计算,新的KV张量也被生成并添加到缓存中,以备下一个时间步骤的使用。

这种KV缓存的使用方式有助于减少重复计算,提高了解码阶段的效率。通过缓存已经计算过的中间状态,模型能够更有效地利用GPU的计算资源,加速推理过程。

大语言模型内存要求 LLM memory requirement

实际上,影响 GPU 大型语言模型(LLM)内存需求的两个主要因素是模型权重和 KV 缓存。

  • 模型权重 Model weights:内存被模型参数所占用。举例来说,一个包含 70 亿个参数的模型(比如 Llama 2 7B),以 16 位精度(FP16 或 BF16)加载,大约需要 70 亿 * sizeof(FP16) ~= 14 GB 的内存。

  • KV 缓存 KV caching:内存被自注意力张量的缓存所占用,以避免重复计算。

在批处理中,批处理中每个请求的 KV 缓存仍然需要单独分配,并且可能具有较大的内存占用。下面的公式描述了适用于今天大多数常见LLM架构的KV缓存大小。

每个标记的KV缓存大小(以字节为单位)= 2 * (层数) * (头数 * 头尺寸) * 字节精度

Size of KV cache per token in bytes = 2 * (num_layers) * (num_heads * dim_head) * precision_in_bytes

第一个因子2代表K和V矩阵。通常,(头数 * 头尺寸)的值与transformer的隐藏大小(或模型的维度,d_model)相同。这些模型属性通常可以在模型卡片或关联的配置文件中找到。

这个内存大小适用于批量输入序列中的每个标记。假设半精度,KV缓存的总大小由下面的公式给出。

KV缓存的总大小(以字节为单位)= (批量大小) * (序列长度) * 2 * (层数) * (隐藏大小) * sizeof(FP16)

Total size of KV cache in bytes = (batch_size) * (sequence_length) * 2 * (num_layers) * (hidden_size) * sizeof(FP16)

例如,使用 16 位精度的 Llama 2 7B 模型和批量大小为 1,KV 缓存的大小将是 1 * 4096 * 2 * 32 * 4096 * 2 字节,约为 2 GB。

有效管理这个KV缓存是一个具有挑战性的任务。随着批处理大小和序列长度线性增长,内存需求会迅速扩大。因此,它限制了可以提供的吞吐量,并对长上下文输入提出了挑战。这正是本文中介绍的几种优化的动机所在。

ChatGPT:大型语言模型(LLMs)在推理过程中需要大量的内存。其内存需求取决于多个因素:

  1. 模型大小: LLM的规模越大,其内存需求也就越高。模型包含的参数数量和层数会直接影响到内存的消耗。
  2. 输入序列长度: 如果需要处理较长的输入序列或上下文,LLM也会需要更多的内存。较长的输入序列可能导致更多的中间状态(例如,键值对)需要被存储和处理。
  3. 中间状态的存储需求: 在推理过程中,LLMs需要存储并管理生成的中间状态,如键值对缓存。这些中间状态的存储消耗也会影响到内存需求。
  4. 推理批处理大小: 较大的推理批处理可能需要更多的内存,因为同时处理多个序列需要额外的内存来存储每个序列的状态。
  5. 硬件平台: 不同的硬件平台对内存的使用方式和限制可能有所不同。LLMs在不同的GPU或TPU上可能表现出不同的内存需求。

由于这些因素的综合影响,LLMs在推理过程中通常需要大量内存来存储参数、中间状态以及处理输入和输出数据。优化内存使用和管理对于提高推理效率和减少资源消耗非常重要。

利用模型并行化扩展LLMs (Scaling up LLMs with model parallelization)

分布模型到多个GPU上是减少模型权重每个设备内存占用的一种方式。将内存和计算负载分散开来,可以运行更大规模的模型或更大规模的输入批次。模型并行化是训练或推理一个需要比单个设备可用内存更多的模型的必要手段,并且使得针对某些用例的训练时间和推理指标(延迟或吞吐量)合适。根据如何划分模型权重,有几种模型并行化的方式。

需要注意的是,在提到以下列出的方法时,数据并行化(data parallelism)通常也是一个经常提及的技术。在数据并行化中,模型的权重被复制到多个设备上,并且输入的(全局)批次被分片到每个设备上形成微批次。通过处理更大批次的数据,它可以减少总体执行时间。但是,在推理过程中它是一个相对不那么相关的训练时间优化技术

ChatGPT:将大型语言模型(LLMs)进行模型并行化是一种扩展模型以处理更大规模问题的方法。这种技术涉及将模型的不同部分分配到多个设备或处理单元上进行并行处理。

在模型并行化中,模型的不同部分(通常是层或模块)被分配到不同的设备上进行计算。这样做有助于克服单个设备的内存限制,使得可以处理更大规模的模型和数据。

以下是模型并行化的一些关键考虑因素和实施方法:

  1. 层级划分: 模型被划分为较小的部分,每个部分分配到不同的设备。这种划分可能需要根据模型结构和计算需求进行优化,以便确保各个部分能够平衡地分配到不同设备上。
  2. 通信和同步: 在模型并行化中,不同设备上的部分需要进行通信和同步,以确保它们协同工作。有效的通信和同步机制是确保模型并行化有效性的关键因素。
  3. 跨设备优化: 需要考虑到不同设备之间数据传输和计算的效率。一些技术,比如模型裁剪、精简数据传输、异步训练等,可用于优化跨设备之间的通信和计算效率。
  4. 扩展性: 模型并行化需要考虑到可扩展性,以便能够适应不断增长的模型和数据规模。随着模型规模的增加,确保并行化方案仍然有效是至关重要的。

通过模型并行化,可以利用多个设备的计算资源来处理大型语言模型,从而实现更大规模的模型训练和推理。这对于处理大规模数据和复杂任务非常有益,但同时需要有效的管理和优化以确保整体效率。

流水线并行 Pipeline parallelism

流水线并行涉及将模型(垂直方向)分成多个部分,每个部分包含一部分层,这些层在不同的设备上执行。图2a展示了四路流水线并行的示意图,模型被顺序分割,所有层的四分之一子集在每个设备上执行。在一个设备上的一组操作的输出传递到下一个设备,继续执行后续的部分。$F_n$和$B_n$分别表示设备n上的前向传播和反向传播。在每个设备上存储模型权重所需的内存被有效地分成四等分。

这种方法的主要局限性在于,由于处理的顺序性质,一些设备或层可能会在等待前一层输出(激活activations、梯度gradients)时保持空闲。这导致了前向和后向传播中的低效或“流水线气泡”。在图2b中,白色的空白区域表示朴素流水线并行中的大型流水线气泡,设备空闲和资源利用不足。

微批处理可以在一定程度上缓解这个问题,如图2c所示。输入的全局批次大小被分成子批次,逐个处理,梯度在最后累积。请注意,$F_{n,m}$和$B_{n,m}$分别表示设备n上微批m的前向传播和反向传播。这种方法缩小了流水线气泡的大小,但并没有完全消除它们。

四向管道并行

图2. 四路管道并行

来源:GPipe: Easy Scaling with Micro-Batch Pipeline Parallelism

描述四路流水线并行的示意图:

(图2 a)在四路流水线并行中,模型被划分成四个部分,每个部分包含模型的四分之一层,每个子集在不同的设备上执行。

(图2 b)朴素的流水线并行导致大型流水线气泡和GPU资源低效利用。图中白色的空白区域代表这些大型的流水线气泡,这意味着一些设备或层在等待前一层的输出时保持空闲。

(图2 c)微批处理减小了流水线气泡的大小,提高了GPU资源利用率。输入的全局批次被分割成子批次,逐个处理,梯度在最后汇总。这种方法虽然减小了流水线气泡的大小,但并没有完全消除。

ChatGPT:流水线并行(Pipeline Parallelism)用于将模型的不同部分并行化,使得这些部分可以同时运行,以加快整体计算速度。不同于模型并行和数据并行,流水线并行主要关注在模型的不同层或模块之间建立计算流水线。

在流水线并行中,模型被划分为多个阶段(或称为管道),每个阶段负责处理模型的一个部分。输入数据经过各个阶段时,分别在不同阶段上进行处理,而不是等待整个模型在一个设备上完成处理。这种并行化方式有效地利用了设备间的并行处理能力,提高了整体计算速度。

流水线并行的实施涉及以下关键步骤:

  1. 模型划分: 模型被分成多个阶段或模块,每个阶段独立进行计算。
  2. 数据流动: 输入数据在各个阶段之间流动,并在每个阶段上进行处理。每个阶段的输出成为下一个阶段的输入。
  3. 并行计算: 不同阶段的计算是同时进行的,这使得整个处理过程可以更快地完成。
  4. 协同工作: 各个阶段之间需要进行协同和同步,以确保数据的正确流动和处理。

流水线并行可以帮助解决模型太大而无法容纳在单个设备内存中的问题,同时也能提高计算效率。它是一种有效的并行化技术,尤其适用于处理大型模型和大规模数据时,以加速训练和推理过程。

张量并行 Tensor parallelism

张量并行涉及将模型的各个层水平切分成更小、独立的计算块,这些块可以在不同设备上执行。注意力块(Attention block)和多层感知器(MLP)层是transformer中可以利用张量并行的主要组件。在多头注意力块(multi-head attention blocks)中,每个注意力头或一组注意力头可以分配到不同的设备上,这样它们可以独立且并行地计算。这有助于提高计算效率,并充分利用不同设备的计算资源。

多层感知器(MLP)和自注意层中张量并行性

图3. 多层感知器(MLP)和自注意层中张量并行性

来源: Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism

图3a 展示了一个双向张量并行在一个两层MLP中的示例,其中每一层由一个圆角框表示。在第一层内部,权重矩阵$A$被分割成$A_1$和$A_2$。计算$XA_1$和$XA_2$可以独立地在两个不同的设备上执行相同批次($f$是一个恒等操作)的输入$X$。这有效地减半了在每个设备上存储权重的内存需求。在第二层中,一个合并操作$g$结合这两个输出。

图3b 展示了自注意力层中双向张量并行的示例。多个注意力头天然地是并行的,可以分配到不同的设备上。每个注意力头可以独立地处理输入,并在计算过程中不需要与其他注意力头交互。

在MLPs(多层感知器) 和 Self-Attention layers(自注意力层)中,张量并行的实现方式有所不同:

在MLP中:

MLP中的权重矩阵可以被分割到多个设备上,使得每个设备上可以处理权重的不同部分。这意味着针对输入批次的计算可以同时在这些设备上进行,并利用分割后的权重进行并行计算。例如,如果一个MLP层包含多个神经元,那么其中一部分神经元的计算可以分配给一个设备,另一部分分配给另一个设备,以此类推。

在 Self-Attention中:

自注意力层中的多个注意力头天然地是并行的,并且可以被分配到不同的设备上进行计算。每个注意力头都可以独立地关注不同的部分,并且不需要在计算过程中依赖其他注意力头的输出。这意味着对于一个给定的输入批次,不同的注意力头可以在不同设备上并行计算,每个设备处理自己负责的部分,而无需等待其他设备的输出。

在MLP和自注意力层中,张量并行方式不同,但都利用了并行计算的优势,使得不同部分或组件的计算可以在多个设备上同时进行,从而提高整体的计算效率。

ChatGPT:张量并行(Tensor Parallelism)用于在多个设备上同时处理张量计算,以加速模型训练和推理。与模型并行和流水线并行不同,张量并行主要关注在同一模型的不同部分或不同数据维度上进行并行计算。

在张量并行中,模型的不同部分或不同维度的张量被分配到多个设备上进行计算。这种并行化方式使得每个设备负责处理模型中的特定部分或特定维度的张量运算,从而加速整个模型的计算速度。

张量并行的实施涉及以下关键步骤:

  1. 张量划分: 模型的不同部分或不同维度的张量被划分到多个设备上。

  2. 并行计算: 每个设备上的张量并行运算是同时进行的,以便在不同设备上并行处理数据。

  3. 通信和同步: 不同设备上的张量计算需要进行通信和同步,确保计算结果的正确性和一致性。

  4. 效率和负载均衡: 需要考虑到不同设备之间数据传输和计算的效率,以及负载均衡问题,确保并行化计算的效率和平衡性。

张量并行通常用于处理大型模型和大规模数据,它可以帮助解决单个设备内存不足的问题,并加速模型的训练和推理过程。这种并行化技术对于处理大规模的深度学习模型和复杂任务非常有用。

序列并行 Sequence parallelism

在大型模型中,张量并行存在一些局限性,因为它要求层被划分为独立、可管理的块。这种方法并不适用于诸如LayerNorm和Dropout等操作,而是将这些操作在张量并行组中复制。虽然LayerNorm和Dropout在计算上不那么昂贵,但它们确实需要大量内存来存储(冗余的)激活值。

正如Reducing Activation Recomputation in Large Transformer Models所示,这些操作在输入序列中是独立的,可以沿着“sequence-dimension(序列维度)”对它们进行分割,从而使它们更加内存高效。这就是所谓的序列并行。

一个Transformer层中,可以同时应用张量并行和序列并行

图4. 一个Transformer层中,可以同时应用张量并行和序列并行

来源: Reducing Activation Recomputation in Large Transformer Models

在一个Transformer层中,可以同时应用张量并行和序列并行。如下:

张量并行:

  • 自注意力层中的多头注意力机制: 在自注意力层中,多个注意力头可以利用张量并行进行处理。每个注意力头可以被分配到不同的设备上进行并行计算,因为它们天然地是并行的,可以独立处理输入序列的不同部分。

  • 前馈神经网络(FFN)层中的权重矩阵: 在FFN层(MLP是FFN的一种实现方式)中,权重矩阵可以被切分和分配到不同的设备上,允许每个设备独立处理部分权重的计算。这利用了张量并行的概念,使得计算可以在多个设备上同时进行。

序列并行:

  • LayerNorm和Dropout等操作: 对于LayerNorm和Dropout等操作,它们可能并不适合使用张量并行。相反,序列并行可以更有效地处理这些操作。这是因为这些操作可以在输入序列的不同部分独立进行,并沿着序列维度分割,这降低了存储冗余激活值的内存需求。

这种组合利用了两种并行化技术的优势,既能够利用张量并行进行权重计算的并行处理,又能够使用序列并行来更有效地处理某些不适合张量并行的操作,从而提高了整个Transformer层的计算效率和内存利用率。

模型并行技术并不是相互排斥的,它们可以同时使用。这些技术有助于扩展和减少大型语言模型(LLMs)每个 GPU 的内存占用,但同时也有针对注意力模块的专门优化技术。

ChatGPT: 序列并行用于同时处理模型输入序列中的不同部分或片段,以提高计算效率。这种方法特别适用于处理长序列或大批量的数据,在处理大型语言模型等任务时尤其有用。

在序列并行中,输入序列被划分成多个片段或子序列,并在多个设备上同时处理这些片段。每个设备负责处理输入序列的一个部分,而不需要等待整个序列的处理结果。这种并行化技术允许模型同时处理多个序列片段,从而提高了处理长序列的效率。

序列并行的实施涉及以下关键步骤:

  1. 序列划分: 输入序列被分割成多个子序列或片段。
  2. 并行计算: 不同设备上的模型同时处理这些序列片段,每个设备独立地进行计算。
  3. 序列关联: 在一些情况下,可能需要在处理过程中对处理结果进行关联或整合,以获得最终的输出结果。

序列并行常用于处理长序列数据,例如自然语言处理中的长文本、语音识别中的长音频片段等。通过将长序列划分成多个部分,在多个设备上并行处理这些部分可以提高处理效率,并降低处理长序列数据时的计算负担。

优化注意力机制 Optimizing the attention mechanism

SDPA (scaling dot-product attention)操作将查询和键值对映射到输出,如attention Is All You Need所述。

多头注意力机制 Multi-head attention

这种方法是对自注意力机制(SDPA)的一种增强,它使得注意力层能够并行执行多次,每次使用不同的、经过学习的投影矩阵作用于Q、K和V矩阵。这样的设计让模型能够同时关注来自不同表示子空间的信息,并应用于不同的位置。这些表示子空间是独立学习的,为模型提供了对输入中不同位置更丰富的理解。

正如图5所示,多个并行的注意力操作的输出被串联并进行线性投影以合并它们。每个并行的注意力层被称为一个“头”,这种方法被称为多头注意力(MHA)。

在最初的工作中,每个注意力头作用于模型的降维维度(例如,当使用八个并行注意力头时,降至 $d_{model}/8$)。这样做可以保持计算成本与单头注意力相似的水平。

缩放点积注意和多头注意

图 5. 缩放点积注意(左)和多头注意(右)的说明,多个SDPA头部并行

来源:Attention Is All You Need

ChatGPT: 多头注意力(Multi-head Attention)是Transformer模型中的一个关键组件,用于处理输入序列中的不同特征与位置之间的交互关系。它允许模型同时关注序列中不同位置的信息,并在多个表示子空间上进行注意力计算。

这个机制的核心思想是将输入通过线性变换(通常是矩阵乘法)分为多个头(即多个子空间),然后在每个头中计算注意力权重。每个头得到的注意力输出会被拼接或合并,经过另一个线性变换后,形成最终的多头注意力输出。

多头注意力具有以下特点和优势:

  1. 并行计算: 多头机制允许不同头并行计算注意力权重,提高了计算效率。
  2. 学习不同的表示子空间: 不同的头学习到不同的表示子空间,使得模型能够捕捉输入序列中不同方面的信息。
  3. 减少过度关注: 多头注意力机制有助于减少模型过度关注序列中某些特定位置或特征,提高了模型的泛化能力。

通过多头注意力,Transformer模型能够在输入序列中更好地捕捉全局和局部信息,为模型的语义理解和语言建模提供了强大的建模能力。

:常规方案

多查询注意力 Multi-query attention

多查询注意力(MQA)是对多头注意力(MHA)的一种推理优化方法,如Fast Transformer Decoding中所提出的。MQA共享了多个注意力头之间的键(keys)和值(values),但查询向量仍然会像以前一样被多次投影。

尽管MQA中的计算量与MHA相同,但从内存中读取的数据量(键和值)却只是之前的一部分。当受到内存带宽的限制时,这样做有助于更好地利用计算资源。它还减少了内存中KV缓存的大小,为更大的批处理大小腾出了空间

减少键值头部可能会带来潜在的准确性下降。此外,需要在推理阶段利用这种优化的模型需要使用MQA进行训练(或者至少用MQA启用进行fine-tuned(微调),相当于全量训练数据的约5%)。

ChatGPT: 多查询注意力(Multi-query Attention)是一种注意力机制的变体,允许模型同时使用多个查询向量来计算对输入序列中不同位置的注意力权重。

在传统的自注意力(self-attention)中,每个查询向量(通常是输入序列中的一个位置)用于计算其与所有其他位置的注意力权重。而在多查询注意力中,模型可以使用多个查询向量,每个查询向量都会产生一组注意力权重。这样的设计可以让模型在同一时间关注多个不同的、重要的查询。

这种方法对于某些任务或情况下可能会有所帮助,特别是当模型需要同时关注多个重要信息时。例如,在语言理解任务中,可以同时关注多个关键词或上下文,从而提高模型对输入序列的理解能力。

: 过渡方案

组查询注意力 Grouped-query attention

“Grouped-query attention”(GQA)在多头注意力(MHA)和多查询注意力(MQA)之间取得了平衡,通过将键(keys)和值(values)投影到少数查询头组中(见图6)。在每个组内部,它的行为类似于多查询注意力。

图6显示了多头注意力有多个键-值头(左侧)。而组查询注意力(中间)的键-值头比一个要多,但比查询头的数量少,这是在内存需求和模型质量之间取得的平衡。而多查询注意力(右侧)只有一个键-值头,有助于节省内存。

不同注意机制的比较。左:多头注意有多个键值头。右:多查询注意有一个键值头,这减少了内存需求。中:分组查询注意有几个键值头,平衡内存和模型质量

图6. 不同注意机制的比较

来源:GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints

这种新的训练方法可以在使用少量原始训练计算资源的情况下,将最初采用多头注意力(MHA)训练的模型进行“上训练”(uptraining),转换为采用组查询注意力(GQA)。这种方法可以使模型在保持接近多头注意力(MHA)的质量的同时,保持更接近多查询注意力(MQA)的计算效率。Llama 2 70B就是一个采用组查询注意力(GQA)的模型的例子。

像多查询注意力(MQA)和组查询注意力(GQA)这样的优化方法有助于通过减少存储的键和值头的数量来减少键值(KV)缓存所需的内存。但在如何管理这种KV缓存方面可能仍存在一些低效性。在优化注意力模块本身之外,下一节将介绍一种更高效的KV缓存管理技术。

ChatGPT: 组查询注意力 (Grouped-query attention) 是注意力机制的一种变体,它进一步扩展了多查询注意力(MQA)的概念。在组查询注意力中,查询向量被分组,每个查询组产生一组注意力权重。这种方法允许模型以更高级别的方式进行查询,将查询分组,从而更有效地处理注意力计算。

与多查询注意力类似,组查询注意力也可以让模型同时考虑多个查询,以便更有效地捕获输入序列中的相关信息。通过将查询向量分组,模型可以在更高级别上对输入进行关注,这在某些任务和场景下可能有助于提高模型性能和效率。

这种方法的实施可能会在计算效率和模型表现之间寻找一种平衡,因为它涉及到对查询向量进行组织和处理,有时可能会牺牲一些精确性以换取更高的计算效率。

: 折中方案,长使用在参数量大的模型上。

Flash attention

优化注意力机制的另一种方式是修改某些计算的顺序,以更好地利用GPU的内存层次结构。神经网络通常以层(layers)的形式进行描述,大多数实现也是按照这种方式进行排列,即一次按顺序对输入数据进行一种计算。然而,这并不总是能够实现最佳性能,因为在已经被带入更高、性能更好的内存层次的值上进行更多计算可能是有益的。

在实际计算过程中将多个层融合在一起可以最大程度地减少GPU需要读取和写入其内存的次数,并将需要相同数据的计算分组在一起,即使它们属于神经网络中的不同层。

其中一个非常受欢迎的融合技术是FlashAttention,这是一种IO感知的确切注意力算法,详细介绍在FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness中。确切注意力(Exact attention) 意味着它在数学上与标准的多头注意力完全相同(提供了多查询和组查询注意力的变体),因此可以无需修改地替换到现有的模型架构甚至是已经训练好的模型中。

IO感知(I/O aware) 意味着它在合并操作时考虑了先前讨论的一些内存移动成本。具体而言,FlashAttention使用“tiling”一次性完全计算并写出最终矩阵的一小部分,而不是分步在整个矩阵上进行部分计算,并在其中间写入中间值。

图7展示了瓦片化(tiling)的FlashAttention计算模式和40GB GPU上的内存层次结构。右侧的图表显示了通过融合和重新排序注意力机制的不同组件而获得的相对加速度。

描述记忆层次和FlashAttention计算的图表

图7. 平铺式FlashAttention计算模式和40gb GPU上的内存层次结构

来源: FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness

ChatGPT: FlashAttention是一种针对注意力机制的优化技术,旨在提高模型的计算效率和内存利用率。它专注于减少多头自注意力机制中的内存移动成本,并优化计算操作,特别是针对大规模语言模型的推理过程。

这项技术通过引入I/O感知(IO-Aware)的确切注意力算法来解决这些问题。它利用“tiling”技术,在计算和一次性写入最终矩阵的小部分时进行完全计算,而不是分步骤在整个矩阵上进行部分计算并在中间写入中间值。

FlashAttention的优点之一是它的确切注意力意味着可以无需修改现有的模型架构或已经训练好的模型即可进行替换。此技术考虑了内存移动成本,特别是在将操作组合在一起时采用了“tiling”方法,从而减少了内存访问和计算的复杂性,提高了计算效率。

使用paging有效管理KV缓存 (Efficient management of KV cache with paging)

在某些情况下,KV缓存可能会静态地“超额配置”,以考虑可能的最大输入(支持的序列长度),因为输入的大小是不可预测的。例如,如果模型支持的最大序列长度为2,048,那么不管请求中的输入大小和生成的输出大小如何,都会在内存中预留2,048大小的空间。这个空间可能是连续分配的,但通常大部分空间都未被使用,导致内存浪费或碎片化。这种保留的空间将被绑定在请求的生命周期中。

在KV缓存过度配置和管理不当的情况下,可能会出现内存浪费和碎片化的问题

图8. 由于过度供应和低效的KV缓存管理导致的内存浪费和碎片

来源: Efficient Memory Management for Large Language Model Serving with PagedAttention

在KV缓存过度配置和管理不当的情况下,可能会出现内存浪费和碎片化的问题:

  1. “保留”(Reserved):表示为未来使用而保留的内存,这段内存在整个请求持续时间内都被保留。这种情况会导致整块内存一直被一个请求占用,即使它只在请求中的某些时间点被使用,而其他时间段则处于闲置状态。
  2. “内部碎片”(Internal Fragmentation):由于难以预测生成文本的长度,内存通常被过度配置以适应最大序列长度。这会导致在某些请求中只使用了部分预留的内存空间,而其余空间被浪费掉了。
  3. “外部碎片”(External Fragmentation):因为批处理中的请求可能需要不同预分配大小的内存空间,这种情况下会出现效率低下。如果每个请求需要的预留内存大小不同,可能会导致已分配的内存大小不适应当前请求的情况,从而产生碎片化。

PagedAttention算法受操作系统中分页技术的启发,它使连续的键和值能够以非连续的方式存储在内存中。该算法将每个请求的KV缓存划分为表示固定数量标记的块,并可以非连续地存储这些块。

在注意力计算过程中,根据块表(block table)的记录,按需获取这些块。随着生成新的标记,会进行新的块分配。这些块的大小是固定的,消除了由于不同请求需要不同分配而产生的效率低下的问题。这极大地限制了内存浪费,使得可以使用更大的批处理大小(因此提高了吞吐量)。

ChatGPT: KV(键-值)缓存的高效管理对于大型语言模型的性能至关重要。其中一种方法是使用“paging”技术,类似于计算机中的页面文件管理。这种技术允许模型动态地加载和卸载不同部分的KV缓存,以便将内存中的空间分配给最相关的部分。

当处理较长的输入序列时,KV缓存可以变得非常庞大,超出了GPU内存的限制。因此,将KV缓存划分成页面(或块),并根据需要在内存中加载和卸载这些页面,有助于最大程度地减少内存使用,并优化模型的推理过程。

通过页面化KV缓存,模型可以有效地管理内存,并根据当前处理的部分动态地调整其大小,从而最大限度地提高模型的效率和性能。

模型优化技术 Model optimization techniques

到目前为止,我们已经讨论了大语言模型(LLM)消耗内存的不同方式,以及如何在多个不同的GPU上分配内存,还有优化注意力机制和KV缓存的几种方法。还有一些模型优化技术,可以通过对模型权重本身进行修改来减少每个GPU上的内存使用。GPU还拥有专门的硬件来加速对这些修改后的值进行操作,为模型提供了更多的加速。

ChatGPT: 模型优化技术指的是对神经网络模型进行修改或改进,以提高其性能、效率和适用性。这些技术通常用于减少模型的计算资源需求、提升模型的推理速度、降低模型的存储空间占用,并使其更适应特定的应用场景。

以下是一些常见的模型优化技术:

  1. 权重剪枝(Weight Pruning): 通过将模型中接近于零的权重值设为零来减少模型的参数数量,以减少计算和存储需求。
  2. 量化(Quantization): 降低模型参数和激活值的精度,以减小模型的存储需求和计算开销。通常,将浮点数表示为较低位的整数或定点数。
  3. 稀疏性(Sparsity): 将模型中的部分参数设为零,生成稀疏矩阵,从而减少计算和存储成本。
  4. 知识蒸馏(Knowledge Distillation): 通过训练较小的“学生”模型来模拟较大的“教师”模型,以获取相似的预测能力,同时减少模型规模。
  5. 并行化(Parallelization): 将模型分布式运行在多个设备上,以提高计算效率和速度。
  6. 前馈优化(Feedforward Optimization): 优化模型结构以减少层之间的冗余,减少计算时间和内存占用。
  7. 特定硬件优化(Hardware-Specific Optimization): 针对特定硬件(如GPU、TPU等)进行模型调整,以充分利用硬件设备的性能。

这些技术通常用于不同的组合和情境中,目的是使神经网络模型在推理和训练阶段具有更好的性能和效率。

量化 Quantization

量化是减少模型权重和激活值精度的过程。大多数模型使用32位或16位的精度进行训练,其中每个参数和激活元素占用32位或16位的内存,即单精度浮点数。然而,大多数深度学习模型可以用8位甚至更少的位数来有效表示。

图9展示了一种量化方法前后数值的分布。在这种情况下,一些精度会因四舍五入而丢失,并且一些动态范围会因剪裁而丢失,使得数值可以用更小的格式表示。

两个分布图,一个显示高精度时的全范围值,另一个显示低精度时的压缩和四舍五入范围

图9. 一种量化前后数值的分布

降低模型的精度可以带来多种好处。如果模型在内存中占用空间更小,您可以在相同硬件上容纳更大的模型。量化还意味着您可以在相同的带宽下传输更多的参数,这有助于加速受带宽限制的模型。

对于大型语言模型(LLM),有许多不同的量化技术,涉及降低激活值、权重或两者的精度。量化权重要简单得多,因为它们在训练后就是固定的。然而,这可能会牺牲一些性能,因为激活值保持在较高的精度。GPU没有专门的硬件来执行INT8和FP16数值的乘法运算,因此权重必须转换回更高的精度进行实际操作。

也可以对激活值进行量化,即转换Transformer块和网络层的输入,但这会带来自己的挑战。激活向量通常包含异常值,有效地增加了它们的动态范围,并且以比权重更低的精度表示这些值更具挑战性。

一个选项是通过将代表性数据集传递到模型中来确定异常值可能出现的位置,并选择以比其他激活值更高的精度表示特定的激活值(LLM.int8())。另一个选项是借用权重的动态范围(易于量化),并将该范围重用于激活值。

ChatGPT: 量化是一种减少神经网络模型参数和激活值精度的技术。通常情况下,神经网络模型使用32位或16位的浮点数表示参数和激活值,每个数值占用32或16位的内存空间。而量化技术通过将这些数值表示为更低位数的整数或定点数,有效地降低了存储和计算成本。

量化可以分为权重量化和激活值量化两种:

  1. 权重量化: 减少模型的参数精度,将参数表示为较低位数的整数或定点数。例如,从32位浮点数压缩到8位整数。

  2. 激活值量化: 减少神经网络中每个层的激活值精度,将激活值表示为较低位数的整数或定点数。

量化可以降低模型存储需求和计算成本,有助于将更大的模型加载到相同的硬件上,或者加速对带宽受限的模型的推理过程。虽然权重量化相对较为简单,但激活值量化更为复杂,因为激活值经常包含异常值,这可能需要额外的技术来处理。

稀疏 Sparsity

类似于量化,已经证明许多深度学习模型对剪枝是具有鲁棒性的,或者说可以将接近0的某些值替换为0本身。稀疏矩阵是指其中许多元素为0的矩阵。这些矩阵可以用比完整的密集矩阵占用更少空间的压缩形式表示出来。

用压缩格式表示的稀疏矩阵

图10. 用压缩格式表示的稀疏矩阵,由非零数据值及其对应的两位索引组成

特别是GPU在某种结构化稀疏性方面拥有硬件加速,其中每四个值中有两个是零。稀疏表示法还可以与量化相结合,以实现更大的执行加速。寻找以稀疏格式表示大型语言模型的最佳方式仍然是一个活跃的研究领域,并为未来提升推断速度提供了一个有前景的方向。

ChatGPT: 稀疏性是指在神经网络中的某些权重或激活值中有很多零值。稀疏矩阵是指其中许多元素为零的矩阵,这种矩阵的紧凑表示占用的空间比完整的密集矩阵小。

在 GPU 中,有针对一定结构的稀疏性的硬件加速,例如结构化稀疏性,即每四个数中有两个是零。这种稀疏表示方式能够有效减少存储和计算需求,进而提高模型的执行速度。

研究人员正在探索如何在大型语言模型中更好地利用稀疏性。将稀疏性与量化等技术相结合,可以进一步提高执行效率,但是最佳的稀疏性表示方式仍然是一个活跃的研究方向。

蒸馏 Distillation

缩减模型尺寸的另一种方法是通过一种称为蒸馏(distillation)的过程将其知识转移到一个较小的模型。该过程涉及训练一个较小的模型(称为学生)来模仿一个较大模型(即老师)的行为。

成功的蒸馏模型包括DistilBERT,它将一个BERT模型压缩了40%,同时保留了97%的语言理解能力,速度提升了60%。

虽然在大型语言模型中进行蒸馏是一个活跃的研究领域,但这一通用方法最早是在Distilling the Knowledge in a Neural Network中为神经网络描述的:

  • 学生网络被训练以模拟较大的老师网络的性能,使用一个衡量它们输出差异的损失函数。这个目标除了可能包含匹配学生输出和地面真实标签的原始损失函数之外。
  • 被匹配的老师输出可以是最后一层(称为logits)或中间层激活。

图11展示了知识蒸馏的一般框架。老师的logits是学生优化的软目标,使用了蒸馏损失。其他蒸馏方法可能使用其他损失度量来从老师那里“蒸馏”知识。

图中描述了利用教师和学生逻辑之间的蒸馏损失进行知识蒸馏的一般框架图11. 知识提炼框架

来源: Knowledge Distillation: A Survey

这种替代蒸馏的方法是利用老师模型合成的数据,对学生LLM进行监督训练,特别是在人类注释稀缺或不可得时尤为有用Distilling Step by Step! Outperforming Larger Language Models with Less Training Data and Smaller Model Sizes 除了作为地面真实标签的标签外,还从老师LLM中提取了基于原理的理由。这些原理作为中间推理步骤,以数据高效的方式训练较小的学生LLM。

需要注意的是,如今许多最先进的LLM都有限制性的许可证,禁止使用它们的输出来训练其他LLM,这使得找到合适的老师模型变得具有挑战性。

:貌似当前其他模型使用GPT4来训练,GPT4 是现在比较好的大模型老师~,那天老师发飙了,不让学生来学了。

ChatGPT: 蒸馏是一种将大型模型的知识传递给较小模型的方法。通常,较小的模型(称为学生)通过模仿大型模型(称为教师)的行为来学习。这个过程通常包括以下步骤:

  1. 教师模型的准备:使用已经训练好的大型模型作为教师,该模型拥有很高的性能。

  2. 学生模型的初始化:初始化一个较小的模型,被称为学生模型。

  3. 知识传递:将教师模型的知识传递给学生模型。这通常通过让学生模型尝试模拟教师模型的输出来实现,同时利用教师模型的输出作为参考。

  4. 训练优化:学生模型可能会使用教师模型的输出作为辅助目标进行训练,以最大程度地模拟教师模型的行为。这样可以更好地指导学生模型学习复杂模式和特征。

  5. 性能评估:对学生模型进行评估,以确定它是否成功地学习了教师模型的知识,并且在某种程度上保持了教师模型的性能水平。

通过蒸馏,较小的学生模型可以获得与教师模型相似的性能,但在计算资源和内存占用上消耗更少,从而更适合于资源受限或需要较低延迟的应用场景。

模型服务技术 Model serving techniques

模型执行经常受制于内存带宽,特别是受到权重方面的带宽限制。即使在应用了先前描述的所有模型优化之后,仍然很可能受到内存限制。因此,当加载模型权重时,希望尽可能地进行多项操作。换句话说,尝试并行处理。可以采取两种方法:

  • 在途批处理(In-flight batching)涉及同时执行多个不同的请求。
  • 推测性推理(Speculative inference)涉及并行执行序列的多个不同步骤,以尝试节省时间。

ChatGPT: 模型服务涉及将训练好的模型部署到生产环境以进行推理或预测。以下是一些常见的模型服务技术:

  1. 模型部署:将训练好的模型部署到服务器、云端或边缘设备上。这通常需要选择适合目标环境的部署方式和技术栈。

  2. RESTful API:使用RESTful API提供对模型推理功能的访问。通过API端点可以发送请求,并接收模型预测的响应。

  3. 模型容器化:将模型封装在容器中,例如Docker容器,以便轻松地在不同环境中部署和管理模型。

  4. 多模型管理:管理多个模型的并发部署和服务。这可能涉及模型版本控制、负载均衡和资源管理。

  5. 实时和离线服务:根据需求提供实时或离线推理服务。实时服务要求低延迟,而离线服务则更侧重于处理大量数据批量推理。

  6. 模型监控和更新:监控模型的性能和健康状况,并在必要时更新模型。这包括模型版本控制、性能跟踪和重新训练。

  7. 边缘计算:将模型部署到边缘设备,例如传感器、智能手机或IoT设备,以便在本地进行推理,减少与云的通信延迟。

这些技术可以根据特定的业务需求和环境进行组合和定制,以实现高效、可扩展和可靠的模型服务。

在途批处理 In-flight batching

LLMs的执行特性使得在实践中有效地对请求进行批处理变得困难。单个模型可以同时用于各种看似截然不同的任务。从聊天机器人中简单的问答响应到文档摘要或生成大量代码块,工作负载高度动态化,输出大小相差数个数量级。

这种多功能性可能会使得对请求进行批处理并有效地并行执行变得具有挑战性,而这是为神经网络提供服务的常见优化。这可能导致某些请求比其他请求提前完成。

为了管理这些动态负载,许多LLM服务解决方案包括一种优化的调度技术,称为连续或在途批处理。这利用了一个事实,即LLM的整体文本生成过程可以分解为对模型的多次执行迭代。

使用在途批处理,服务器运行时不等待整个批次完成,而是立即从批次中清除已完成的序列。然后,它开始执行新的请求,而其他请求仍在进行中。因此,在途批处理可以大大提高实际使用情况下的GPU利用率。

ChatGPT: In-flight batching 是一种用于优化模型推理过程的方法,特别是针对语言模型等动态工作负载。这种方法允许在推理过程中不断执行多个请求,而不必等待整个批次的请求完成。

通常,在模型推理期间,一组输入会被组织成一个批次,模型会一次性处理整个批次的请求。然而,在动态工作负载下,请求的大小和完成时间可能差别很大,有些请求可能会比其他请求更快完成。在这种情况下,In-flight batching 可以确保及时地释放已完成请求的资源,并同时开始执行新的请求,而无需等待整个批次的请求全部完成。

这种方法有助于提高 GPU 利用率,尤其是对于语言模型等动态工作负载,因为不同请求的生成长度可能差别很大,有些请求可能完成得更快。通过及时释放完成的请求并立即开始新的推理请求,可以更有效地利用 GPU 资源,减少资源空闲时间。

投机式推理 Speculative inference

也被称为投机式抽样(Speculative sampling)、辅助生成或分块并行解码,投机式推理是LLM执行的一种不同方式。通常,类似GPT的大型语言模型是自回归模型,逐个生成文本标记。

生成的每个标记都依赖于之前的所有标记提供的上下文。这意味着在常规执行中,不可能并行地生成同一序列中的多个标记——你必须等待第n个标记生成后才能生成n+1。

图12显示了投机式推理的示例,在这种情况下,草稿模型暂时预测多个未来步骤,这些步骤会并行进行验证或拒绝。在这种情况下,草稿中的前两个预测标记被接受,而最后一个被拒绝并在继续生成之前被移除。

根据提示“我看到一只狗在骑车”,草图模型预测“在公交车上”。验证模型并行预测“在车里”,因此我们拒绝“车”toke

图12. 投机式推理示例

根据提示“I saw a dog ride”,草图模型预测“in the bus”。验证模型并行预测“in the car”,因此我们拒绝“car” token。

来源: Blockwise Parallel Decoding for Deep Autoregressive Models

Speculative sampling 提供了一种变通方法。这种方法的基本思想是使用一些“更廉价”的过程生成一个长度为数个标记的草稿延续。然后,在多个步骤中并行执行主要的“验证”模型,将廉价的草稿作为执行步骤所需的“推测”上下文。

如果验证模型生成与草稿相同的标记,那么你就知道应该接受这些标记作为输出。否则,你可以丢弃第一个不匹配标记后的所有内容,并用新的草稿重复该过程。

有许多不同的选项可以生成草稿标记,每种选项都伴随着不同的权衡。你可以训练多个模型,或者在单个预训练模型上对多个头部进行微调,以预测未来数步的标记。或者,你可以将小型模型用作草稿模型,将更大、功能更强大的模型用作验证器。

ChatGPT: Speculative inference(推测推理)是一种用于优化语言模型等自回归模型推理过程的技术。在通常的自回归模型中,生成文本是逐标记进行的,每个标记都依赖于之前生成的所有标记。因此,在传统推理中,无法同时生成同一序列的多个标记,需要等待前一个标记生成后才能继续下一个标记。

推测推理提供了一种替代方案。它采用一种“廉价”的方法生成一个多标记的草稿,然后并行地对这个草稿的不同步骤进行验证。如果验证模型生成的标记与草稿一致,那么就可以确认这些标记,并将其用作输出。如果出现不匹配的标记,就可以放弃这些标记并丢弃不匹配标记之后的部分,然后重新生成新的草稿。

这种方法的优点在于可以充分利用并行处理的优势,在某种程度上以牺牲一些准确性为代价,加快了推理过程的速度。它使用了“草稿”的概念,允许在一定程度上预测多个标记,然后在验证模型的帮助下进行选择性确认。

总结

这篇文章概述了许多优化和高效提供大型语言模型(LLMs)的最流行解决方案,无论是在数据中心还是在个人电脑边缘。其中许多技术都经过优化,并通过 NVIDIA TensorRT-LLM 提供支持。TensorRT-LLM 是一个开源库,包括 TensorRT 深度学习编译器、优化内核、预处理和后处理步骤,以及用于 NVIDIA GPU 的多GPU/多节点通信原语,可实现突破性的性能。

: 推理优化相关的解决方案关键字,使用ChatGPT 询问答案,可以作为对比,相对模板化,用来提炼一篇文章知识点是非常有效的

参考

  1. https://developer.nvidia.com/blog/mastering-llm-techniques-inference-optimization/
  2. https://developer.nvidia.com/blog/search-posts/?q=Mastering+LLM+Techniques
  3. https://lilianweng.github.io/posts/2023-01-10-inference-optimization/ (早期文章,介绍比较全)
  4. https://kipp.ly/transformer-inference-arithmetic/
  5. https://github.com/vllm-project/vllm
  6. https://github.com/microsoft/DeepSpeed-MII
  7. https://github.com/NVIDIA/TensorRT-LLM
  8. https://github.com/ninehills/llm-inference-benchmark/blob/main/LLM%E6%8E%A8%E7%90%86%E4%BC%98%E5%8C%96.md