对话式人工智能

聚焦:NAVER Place 利用 NVIDIA TensorRT-LLM 优化 SLM 基础的垂直服务

NAVER 是一家韩国热门搜索引擎公司,提供 Naver Place ,这是一项基于地理的服务,可提供有关韩国数百万家企业和兴趣点的详细信息。用户可以搜索不同的地点、发表评论,以及实时进行预订或下单。

NAVER Place 垂直服务基于小语言模型 (SLMs) 来提高可用性,并专门针对 Place、Map 和 Travel。本文分享了 NVIDIA 和 NAVER 如何使用 NVIDIA TensorRT-LLM 优化 SLM 推理性能,从而在 NVIDIA Triton Inference Server 上实现基于 SLM 的垂直服务。如需详细了解 NAVER 如何使用 AI,请参阅 NAVER Place AI 开发团队简介

适用于 NAVER Place 评测的小语言模型

大语言模型(LLMs) 相比,小语言模型(SLMs)是能够以更少的参数理解自然语言的 AI 模型。众所周知,当 SLMs 针对特定域任务进行适当微调时,它们可以在内存和计算能力较低的情况下正常工作。

NAVER Place 使用定制的小语言模型(SLMs)与其内部数据集结合使用,以提供摘要(根据 NAVER Place 用户留下的评论创建)或微评论,解释每个地点的特点。

Screenshot of NAVER Place service app showing review summary and microreview examples.
图 1.查看 NAVER Place 服务应用中的摘要和微评论示例。图片来源:NAVER

使用 SLM Transformer 解码器将参观与景点匹配

NAVER Place 从其注册地点收集收据和付款记录,以显示 NAVER Map 上每个地点的访问和评论。为此,NAVER Place 提供了一个将参观与兴趣点 (POIs) 相匹配的系统。系统还会从博客文章中发现新的 POIs,或检查重复的 POIs,以确保数据完整性并提高服务质量。

Screenshots of the NAVER Place POI matching service UI.
图 2. NAVER Place POI 匹配服务 UI 由 SLM Transformer 解码器启用。图片来源:NAVER

采用 NVIDIA TensorRT-LLM 实现卓越的推理性能

NVIDIA TensorRT-LLM 可加速并优化 NVIDIA GPU 上 LLM 的推理性能。它支持动态批处理以最大限度地提高吞吐量,并使用自回归模型的内存优化方法 (例如分页 KV 缓存和分块上下文) 来提高内存效率。

NAVER Place 采用了 TensorRT-LLM,因为它在吞吐量、到达第一个令牌的时间 (TTFT) 和每个输出令牌的时间 (TPOT) 方面优于其他 LLM 推理解决方案。TensorRT-LLM 在各种输入长度和输出令牌场景中始终如一地提供卓越性能。

图 3 比较了使用 Qwen 模型 测量的热门替代开源 LLM 推理库和 TensorRT-LLM 在 NVIDIA A100 和 NVIDIA H100 GPU 上各种输入和输出令牌长度的吞吐量。

Four charts showing QPS Comparison of TensorRT-LLM and a popular alternative library across different operation modes.
图 3、TensorRT-LLM 与不同操作模式下热门替代库的 QPS 比较。图片来源:NAVER

TensorRT-LLM 在所有解码 – 预填充轻、预填充重、解码重和解码 – 预填充重操作模式下的表现均优于替代库。其中,使用 SLM 的解码重操作模式提供了最强的性能。此外,由于 TensorRT-LLM 提供针对最新 GPU 优化的内核,因此它在 NVIDIA Hopper 架构 上实现了特别高的性能。

要了解如何使用 TensorRT-LLM 评估性能,请参阅 NVIDIA/TensorRT-LLM GitHub repo 中提供的 性能概述 。如需详细了解构建 TensorRT-LLM 引擎的基本调优技术,请参阅 调优 TensorRT-LLM 性能的最佳实践

推理优化:在吞吐量和延迟之间做出权衡

本节将探讨在批量大小和内存优化技术 (例如分页 KV 缓存和动态批处理) 方面平衡 LLM 推理吞吐量和延迟的策略。

批量大小

LLM 推理服务器将请求批量处理,以更大限度地提高吞吐量。但是,这会导致高延迟。这种权衡意味着,虽然较大的批量大小可以提供更高的吞吐量,但也可能会增加响应时间,因此必须在效率和用户体验之间保持谨慎的平衡 (图 4)。通过根据您的目标 TTFT 和 TPOT 调整批量大小,您可以优化系统的性能,以更好地满足您的特定服务要求。

Four graphs showing throughput and time per output token according to batch size.
图 4、每个输出令牌的吞吐量和时间 (根据批量大小而定)。图片来源:NAVER

Paged KV 缓存和 in-flight batching

TensorRT-LLM 包括默认启用的 分页 KV 缓存 选项,可提高内存效率并增加批量大小上限,以适应需要低延迟和高吞吐量的任务。此默认设置可确保模型能够平滑扩展,以处理延迟敏感的实时请求和需要更高吞吐量的批量处理场景,从而提供更灵活、更可靠的解决方案。

TensorRT-LLM 也默认启用 In-flight batching ,这可以提高吞吐量。对于大多数任务,NAVER 团队默认使用这两个选项。

一个例外是,服务需要在较小的模型和较旧的 GPU 上实现极低的延迟。NAVER Place 在特定情况下需要极低的延迟,当关闭两个选项时,性能表现更好。例如,POI 匹配是指实时处理请求,需要极低延迟的情况。由于模型相对较小,只有 1.3 亿个,并且 NVIDIA T4 GPU 架构相对较旧,因此该服务需要将批量大小设为 1 以实现最低延迟,并关闭批处理选项。

此外,使用小模型大小为 1.3 亿,批量大小为 1,与计算开销相比,分页开销更高,从而导致延迟增加和 QPS 降低。为了解决这个问题,团队采用了连续的 KV 缓存,而不是分页 KV 缓存,因为在给定条件下,内存开销不太重要。这种选择使我们能够满足 POI 匹配等用例的严格实时要求。

精度 分页 KV 缓存 缓存块 输入/输出 最大 batch_size QPS 延迟 (以秒为单位)
FP16 打开 7110 500/5 1 6.49 0.154
FP16 关闭 7110 500/5 1 8.39 0.119
表 1、当在特定情况下禁用分页 KV 缓存时,当使用较小的模型和批量大小利用较旧的 GPU 架构时,QPS 和延迟会更好

虽然 POI 匹配对实时服务的延迟要求极低,但它也需要高吞吐量才能进行背景匹配。因此,我们目前对每种版本使用不同的构建选项。

"build_config": {
        "max_input_len": 512,
        "max_output_len": 32,
        "max_batch_size": 1,
        "max_beam_width": 1,
        "max_num_tokens": 4096,
        ...
        "plugin_config": {
            ...
            "paged_kv_cache": false,
            ...
        }
    }
 "build_config": {
        "max_input_len": 512,
        "max_output_len": 32,
        "max_batch_size": 8,
        "max_beam_width": 1,
        "max_num_tokens": 4096,
        ...
        "plugin_config": {
            ...


            "paged_kv_cache": true,
            ...
        }
    }

推理优化:下游缓存

本节将探讨利用缓存技术来简化下游推理任务的优化策略。我们研究了前缀和响应缓存如何帮助减少冗余计算并提高整体效率。

前缀缓存

由于下游任务生成的提示词具有通用前缀,因此计算每个请求的整个预填充会浪费资源。为了避免这种情况,TensorRT-LLM 提供了前缀缓存,这可以显著减少内存使用量和计算负载。有关更多详细信息,请参阅 如何在 NVIDIA/TensorRT-LLM GitHub repo 中启用 KV 缓存重用

这种方法可以显著增强 TTFT,并且对于具有长输入长度、共享系统提示和短输出长度的任务很有帮助。它特别适用于微评论,因为生成一个微评论平均需要 40 个多步骤推理,并且每个步骤共享前缀。

但是,对于涉及高度多样化系统提示的任务,前缀缓存可能无法高效运行,同时降低缓存性能并增加管理开销,因为缓存基于最近使用最少(LRU)策略。

响应缓存

响应缓存是 NVIDIA Triton Inference Server 的一项功能,有助于避免低效的冗余推理。Triton 会使用推理请求哈希来访问响应缓存,其中包括模型名称、模型版本和模型输入。响应缓存非常有效,但有意要求重新引用的情况除外,例如多项采样解码。在实时提供的 POI 匹配中,每秒发生 4 到 5 次缓存命中,这意味着计算负载减少了 17%。有关更多详细信息,请参阅 Triton Response Cache 文档

Chart of response cache hits for the POI matching service.
图 5、POI 匹配服务的响应缓存命中。图片来源:NAVER

使用 Triton 服务 TensorRT-LLM

使用 TensorRT-LLM 构建的 SLM 引擎可在 Triton Inference Server 上提供。Triton 提供了诸如 ensemble models Business Logic Scripting (BLS) 等功能,用于组成标记化、后处理或多步骤推理等工作流。例如,NAVER Place 选择使用 BLS,是因为它为特定用例提供了所需的灵活性。本节将介绍 NAVER Place 如何最大限度地提高 Triton BLS 的优势和可用性。

通过定义明确的请求/响应模式提高可用性

Triton 模型以 pb_tensor 格式交换数据。为提高通信效率和优化 LLM 推理而选择的 BLS 结构包含预处理和后处理代码,这需要将数据类型从 pb_tensor 转换为 NumPy 数组,然后再转换回 pb_tensor

此过程存在两个困难。首先,如果每个模型的 IO 数据未经过验证,则调试很困难,因为在运行时发现了任何无效的数据格式或缺少必填字段。其次,由于将预处理和后处理合并到 BLS 中,代码变得更加复杂,如果模型之间存在调用依赖项,则扩展和维护变得更加困难。

这些挑战强调了需要一个定义明确的请求/响应模式,以减少运行时错误并简化代码管理,尤其是在必须将多个模型链接在一起的情况下。此外,在整个工作流中保持一致的数据格式可显著缓解调试困难,并确保更流畅的集成。例如,POI 匹配会经历复杂的工作流,如图 6 所示。

Diagram of POI matching inference pipeline in BLS.
图 6、BLS 中的 POI 匹配推理工作流。图片来源:NAVER

为了克服这些困难,NAVER Place 团队提出了以下方法。

标准化 IO 模式管理

基于 NVIDIA 的 Python 数据类,我们使用 Pydantic 定义了 IO 模式,这使得数据验证变得更容易。这有助于确保所有 Triton 模型的请求和响应之间的结构一致性,并增强数据验证。通过在此阶段采用定义明确的模式,开发者可以尽早检测到数据问题,并在整个推理工作流中维护一致的数据结构,最终减少调试用度并提高整体可靠性。

例如,我们定义了一个名为 BlsRequest 的类,用于管理 Triton 请求的输入数据格式并执行数据验证,如以下代码示例所示:

# NOTE: Because Triton uses pb_tensor and Numpy objects,
# it is required to declaratively manage the fields that are not defined as Python default types.
# For this, we added tTe json_schema_extra field of Pydantic to explicitly manage data types.
class BlsRequest(TritonFieldModel):
      name: Optional[str] = Field(None, json_schema_extra={'data_type': "TYPE_STRING"})
      subname: Optional[str] = Field(None, json_schema_extra={'data_type': "TYPE_STRING"})
      biznum: Optional[str] = Field(None, json_schema_extra={'data_type': "TYPE_STRING"})
      address: Optional[List[str]] = Field(None, json_schema_extra={'data_type': "TYPE_STRING"})
      tel: Optional[List[str]] = Field(None, json_schema_extra={'data_type': "TYPE_STRING"})
      @root_validator(pre=True)
      def check_all_fields_empty(cls, values):
          if not any(bool(v) for v in values.values()):
              raise ValidationError("All fields cannot be empty", model=cls.__name__)

按模型实现 IO 类型转换的模块化

我们为每个模型封装了 IO 数据转换过程,并为 pb_tensor 和 Pydantic 之间的转换创建了一个通用函数,使其适合基础 Triton Python 模型。这有助于以一致的方式调用模型,而无需担心内部数据转换过程。

以下代码示例是一个函数,该函数接收 Pydantic Request 对象,将其转换为 Triton pb_tensor,然后将模型推理的结果作为 Pydantic Response 对象返回:

def _infer_model(self, request_model, response_model_cls, model_name, request_model, **infer_kwargs):
     # Converts Pydantic Request to Triton pb_tensors.
     pb_tensors = self.convert_pydantic_to_pb_tensors(request_model, batch_inference)
     # Runs model inference.
     infer_request = pb_utils.InferenceRequest(
         model_name=model_name,
         inputs=pb_tensors,
         requested_output_names=response_model_cls.get_field_names(),
         **infer_kwargs,
     )
     infer_response = infer_request.exec()
     # Converts Triton Response(pb_tensors) to Pydantic Response.
     return self.convert_pb_tensors_to_pydantic(response, response_model_cls)

以下代码示例使用 _infer_model 调用模型。只需声明 GeneratorRequestGeneratorResponse 类,而忽略了复杂的数据转换或模型调用过程。

def infer_generator(self, request, text_input, max_tokens):
      response_model_cls = schema.GeneratorResponse
      request_model = schema.GeneratorRequest(text_input=text_input, max_tokens=max_tokens)
       return self._infer_model(
          request=request,
          model_name="generator_bls",
          request_model=request_model,
          response_model_cls=response_model_cls,
      )

模块化 BLS 业务逻辑并增强可测试性

NAVER 团队通过以下方式模块化了业务逻辑,并在 BLS 中预处理和后处理代码,以实现低耦合。这有助于降低代码的复杂性,并提高可测试性和可维护性。

  • 模块化预处理和后处理,并引入单元测试 将模型训练、预处理和后处理代码的业务逻辑模块化,使其可重复使用。 将测试代码设计为在 Python 运行时中独立运行,即使没有 Triton 运行时,也能验证每个模型的预处理和后处理。
  • 重新定义 BLS 的角色 BLS 仅负责模型调用和端到端测试。这可以确保系统保持可扩展性,即使添加了新要求,也能最大限度地减少对 BLS 代码的影响。
  • CI 简介 为业务逻辑以及预处理和后处理代码创建了 CI 测试管道。这有助于快速验证模型训练过程中所做的更改,确保它们不会影响服务。将这些测试集成到 CI 管道中可实现更早的问题检测和快速解决,在不中断服务流程的情况下确保稳定的更新。

使用这种方法,我们有效地实现了增强数据验证、代码可维护性和开发生产力的目标,从而提高了基于 Triton 的 LLM 服务开发的生产力。

总结

NAVER Place 已成功使用 NVIDIA TensorRT-LLM 优化 LLM 引擎,并提高了 NVIDIA Triton Inference Server 的可用性。通过这种优化,该团队还最大限度地提高了 GPU 利用率,进一步提高了整体系统效率。整个流程有助于优化多个基于 SLM 的垂直服务,使 NAVER Place 更加用户友好。基于这些经验,我们将继续开发其他垂直模型,并将其应用于我们的服务。

开始使用 NVIDIA TensorRT-LLM NVIDIA Triton Inference Server

 

 

标签