大模型的latency(延迟)和throughput(吞吐量)有什么区别?

news2024/9/30 0:38:54

1. 导入

为了快速应用大模型,我们需要采购商业大模型。采购前,对接销售时,我们描述了我们的场景和需求:

Q:我们的prompts token数量在1500-2000之间,completion token数量在500左右。这种情况下,prefilling多久?每个token输出是多久?

销售回复:标准3500 token Input,首包吐出来小于1秒;throughput 300token/s.

你是否看出来答非所问了?

问的和latency相关,回答的是throughput。那这两个词有什么区别?导致连这个领域的销售都会搞混?
请添加图片描述

在搞懂latency和throughput之前,我们先来看看KV cache 和 prefilling。

2. KV Cache

KV Cache 采用以空间换时间的思想,复用上次推理的 KV 缓存,可以极大降低内存压力、提高推理性能,而且不会影响任何计算精度。

decoder架构里面最主要的就是 transformer 中的 self-attention 结构的堆叠,KV-cache的实质是用之前计算过的 key-value 以及当前的 query 来生成下一个 token。

prefill指的是生成第一个token的时候,kv是没有任何缓存的,需要预填充prompt对应的KV矩阵做缓存,所以第一个token生成的最慢,而从第二个token开始,都会快速获取缓存,并将前一个token的kv也缓存。

可以看到,这是一个空间换时间的方案,缓存会不断变大,所以在私有化部署计算显存的时候,除了模型大小,还要要看你的应用中prompt和completion的大小(当然还有batch-size)。

3. Prefilling & Decoding

如果你使用商用大模型,或者使用开源大模型本地化部署,除了生成的质量之外,另外一个关键的指标就是生成token的速度。而且并不是简单的每秒生成多少个token,而是拆成了两个阶段:

  • prefill:预填充,并行处理输入的 tokens;
  • decoding:解码,逐个生成下一个 token.

预填充(prefill)

在预填充阶段,模型会并行处理输入的 prompt(即 input token),生成 KV cache。这一步骤包括一次完整的前向传播(forward),并输出第一个 token。这个过程的时间主要由 input token 决定,因为它们需要进行一次全面的计算来初始化整个生成过程。

解码(decoding)

解码阶段是逐个生成下一个 token 的过程。在这一步中,output token 的数量决定了需要进行多少次前向传播。虽然每次前向传播由于 KV cache 的存在而更快,但这仍然需要模型多次计算,逐步生成每一个后续的 token。

不同的公司使用的术语不同:

  • 首token延迟,Time To First Token (TTFT), prefill, Prefilling

    指的都是从输入到输出第一个token 的延迟;

  • 每个输出 token 的延迟(不含首个Token),Time Per Output Token (TPOT)

    指的是第二个token开始的吐出速度;

  • 延迟Lantency

    理论上即从输入到输出最后一个 token 的时间,原则上的计算公式是:Latency = (TTFT) + (TPOT) * (the number of tokens to be generated);

  • Tokens Per Second (TPS):

    (the number of tokens to be generated) / Latency;

4. Latency VS Throughput

  • Latency:延迟,指的是从输入到输出的时间,即从输入到输出最后一个 token 的时间;
    请添加图片描述

  • Throughput:吞吐量,指的是单位时间内处理的任务数,即每秒处理的 token 数。
    请添加图片描述

下面给出latency和throughput的计算方法:

# constants
max_tokens = 10

# observations
durations = []
throughputs = []
latencies = []

batch_sizes = [2**p for p in range(8)]
for batch_size in batch_sizes:
    print(f"bs= {batch_size}")

    # generate tokens for batch and record duration
    t0 = time.time()
    batch_prompts = [
        prompts[i % len(prompts)] for i in range(batch_size)
    ]
    inputs = tokenizer(
        batch_prompts, padding=True, return_tensors="pt"
    )
    generated_tokens = generate_batch(inputs, max_tokens=max_tokens)
    duration_s = time.time() - t0

    ntokens = batch_size * max_tokens
    throughput = ntokens / duration_s
    avg_latency = duration_s / max_tokens
    print("duration", duration_s)
    print("throughput", throughput)
    print("avg latency", avg_latency)    
    print()

    durations.append(duration_s)
    throughputs.append(throughput)
    latencies.append(avg_latency)

5. Navie batching

Navie batching是指将多个输入合并成一个batch,然后一次性输入模型,这样可以减少模型的前向传播次数,提高效率。
有的人也称其为synchronous batching或者static batching,区别于后面的continuous batching。
请添加图片描述

Navie batching的缺点是,如果一个batch中有一个输入很大,那么整个batch的计算时间就会被拉长,这样会导致整个batch的计算时间变长。

6. Continuous batching

在传统的批处理方法中,一批请求必须全部完成处理后才能一起返回结果。这就意味着较短请求需要等待较长请求处理完成,导致了GPU资源的浪费和推理延迟的增加。而Continuous Batching技术允许模型在处理完当前迭代后,如果有请求已经处理完成,则可以立即返回该请求的结果,而不需要等待整个批次的请求都处理完成,这样可以显著提高硬件资源的利用率并减少空闲时间。
请添加图片描述

此外,Continuous Batching还能够解决不同请求计算量不同导致的资源浪费问题,通过迭代级别的调度动态调整批处理大小,适应不同请求的复杂程度,有效降低高复杂度请求的等待时间。

值得注意的是,实现Continuous Batching需要考虑一些关键问题,如对Early-finished Requests、Late-joining Requests的处理,以及如何处理不同长度的请求Batching。OCRA提出的两个设计思路:Iteration-level Batching和Selective Batching,就是为了解决这些问题。

在实际应用中,不同的框架可能对Continuous Batching有不同的实现方式。例如,vLLM框架采用了一种简化的实现,将prefill和decoding分开处理,而FastGen框架则采用了SplitFuse方法,将长prompt分解成小块并在多个step中调度。这些不同的实现方式都旨在提高推理性能,降低延迟,同时优化资源的利用

给出生成continous batching的代码:

# seed the random number generator so our results are deterministic
random.seed(42)

# constants
queue_size = 32
batch_size = 8

# requests waiting to be processed
# this time requests are tuples (prompt, max_tokens)
request_queue = [
    (prompts[0], 100 if i % batch_size == 0 else 10)
    for i in range(queue_size)
]

t0 = time.time()
with tqdm(total=len(request_queue), desc=f"bs={batch_size}") as pbar:
    # first, let's seed the initial cached_batch
    # with the first `batch_size` inputs
    # and run the initial prefill step
    batch = init_batch(request_queue[:batch_size])
    cached_batch = generate_next_token(batch)
    request_queue = request_queue[batch_size:]

    # continue until both the request queue is 
    # fully drained and every input
    # within the cached_batch has completed generation
    while (
        len(request_queue) > 0 or
        cached_batch["input_ids"].size(0) > 0
    ):
        batch_capacity = (
            batch_size - cached_batch["input_ids"].size(0)
        )
        if batch_capacity > 0 and len(request_queue) > 0:
            # prefill
            new_batch = init_batch(request_queue[:batch_capacity])
            new_batch = generate_next_token(new_batch)
            request_queue = request_queue[batch_capacity:]

            # merge
            cached_batch = merge_batches(cached_batch, new_batch)

        # decode
        cached_batch = generate_next_token(cached_batch)

        # remove any inputs that have finished generation
        cached_batch, removed_indices = filter_batch(cached_batch)
        pbar.update(len(removed_indices))

duration_s = time.time() - t0
print("duration", duration_s)

参考

[1] deeplearning.ai

[2] Continuous Batching:一种提升 LLM 部署吞吐量的利器

[3] LLM 推理优化 Continuous Batching 及其实现

[4] How continuous batching enables 23x throughput in LLM inference while reducing p50 latency

[5] GitHub: LLMForEverybody

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2087673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式学习——ARM学习(2)——汇编学习

工具:Keil-uVision5 1、汇编 1.1 汇编的组成 指令:汇编语言的核心部分,表示 CPU 可以执行的操作,如数据传输、算术运算、逻辑运算等。 操作数:指令中用于指定操作对象的数据,可以是寄存器、内存地址或立即…

Qt第二课----信号和槽

作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 ​🎂 作者介绍: 🎂🎂 🎂 🎉🎉&#x1f389…

带你速通C语言——静态变量(14)

使用静态变量 (static) 在 C 语言中是管理函数内部状态或跨函数调用保持数据的一种有效方式。理解静态变量如何工作可以帮助你编写更加复杂和可控的程序。 1.静态变量的特性 静态变量有几个关键特性: 持久性:静态变量在函数多次调用之间保持其值。它们…

霍尼韦尔护眼大路灯怎么样?书客、月影、霍尼韦尔实测数据大揭秘

霍尼韦尔大路灯怎么样?目前市面上的大路灯外观几乎都大同小异,但很多品牌在宣传方面做的很牛,消费者在拿到手后的体验却是大打折扣,跟官方宣传的真的是一个天一个地,相差太大。作为一个测评博主,很多人问我…

elasticsearch整合java使用创建索引、指定索引映射、操作添加文档、删除文档、更新文档、批量操作

前言: elasticsearch的整合流程可以参考:Elasticsearch7.15版本后新版本的接入-CSDN博客 索引 1.创建索引 Testpublic void contextLoads() throws IOException {ElasticsearchClient elasticsearchClient elasticSearchConfig.esRestClient();bool…

【Qt】表单布局QFormLayout

表单布局QFormLayout Qt 还提供了 QFormLayout , 属于是 QGridLayout 的特殊情况, 专⻔⽤于实现两列表单的布局. 这种表单布局多⽤于让⽤⼾填写信息的场景. 左侧列为提⽰, 右侧列为输⼊框 例子:使用QFormLayout创建表单 (1)设置三个label、…

数据分析及应用:如何对试卷得分做min-max归一化处理?

目录 0 问题描述 1 数据准备 2 问题分析 3 小结 0 问题描述 现有试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间): 试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时…

强者和弱者的区别体现在面对失败上

面对成功,面对日常,每一个人都是谦谦君子温文尔雅,谈论困难挫折,不屑一顾。 这是他们的真实面目吗? 有的是真的,有的是假的。 强者视失败为磨砺意志的砥石,他们勇于承认不足,积极寻…

物联网架构之CDH集群部署

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

中国各地区-交通运输-电信业务总量(1999-2020年)

电信业务总量是指以货币形式表示的电信企业为社会提供的各类电信服务的总数量,包含了各类电信业务,如固定电话、移动电话、数据通信、互联网接入等。 1999-2020年 中国各地区-交通运输-电信业务总量 指标 年份、地区、交通运输-电信业务总量(亿元)。 …

2024年8月29日(harbor似有仓库管理,Docker-compose容器编排)

一、harbor私有仓库管理 yum -y install epel-release yum -y install python2-pip pip install --upgrade pip pip list pip 8x pip install --upgrade pip pip install --upgrade pip20.3 -i https://mirrors.aliyun.com/pypi/simple pip list pip install docker-compo…

基于my Batis优化图书管理系统(总)

1.准备工作 1.1 数据库表设计 -- 创建数据库 DROP DATABASE IF EXISTS book_manage;CREATE DATABASE book_manage DEFAULT CHARACTER SET utf8mb4; use book_manage;-- 用户表 DROP TABLE IF EXISTS user_info; CREATE TABLE user_info (id INT NOT NULL AUTO_INCREMENT,use…

网站建设完成后, 功能性网站如何做seo

功能性网站的SEO优化关注于提高网站在搜索引擎中的排名,从而吸引更多用户并提升用户体验。以下是功能性网站SEO的详细解析: 关键词研究与布局 目标受众分析:了解目标受众的搜索习惯和需求,确定适合的关键词。使用工具如Google Ke…

反弹shell流量分析与检测

常用的隧道技术: 网络层:ipv6、Icmp、gre IPv6隧道:将ipv6报文放入ipv4作为载体进行传输,工具:socat、6tunnel ICMP隧道:将数据放入ping包中进行传输,工具:icmpsh、PingTunnel G…

日本麻将入门(二):牌效率【基础】

基础牌效率 引入 日麻,又称立直麻将。日麻的水平本质上与你是否会立直有很大关系(参见常用役种:立直:优点),但立直最大的缺点就是不能副露,导致我们只能通过自己的摸切来完成听牌形的组成。在…

20. 筛选dataframe

哈喽,大家好,我是木头左! 筛选条件 基本筛选 要筛选DataFrame,首先需要了解筛选条件。Pandas提供了多种筛选条件,包括等于()、不等于(!)、大于(…

Leetcode Day14排序算法

动态git可以看 :https://leetcode.cn/problems/sort-an-array/solutions/179370/python-shi-xian-de-shi-da-jing-dian-pai-xu-suan-fa/ 选择排序 def selection_sort(nums):n len(nums)for i in range(n):for j in range(i, n):if nums[i] > nums[j]:nums[i], nums[j] …

05.整合Axios+MockJs

1. 前言 作为前后端分离的项目,必不可少的当然是发请求向后端拿数据了, 但是不可能每次等到接口完成我们才开始开发前端,所以使用 mock.js 先模拟后端接口,等后端接口开发完成后,可以无缝衔接,直接替换为真…

EmguCV学习笔记 VB.Net 7.2 特征点检测

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

(24)(24.6) 基于OSD的参数菜单

文章目录 前言 1 Copter默认屏幕 2 Plane默认屏幕 3 实例 前言 这允许使用 ArduPilot 机载 OSD 和 RC 发射机的杆输入设置和调整参数。还有两个额外的 OSD 屏幕可用(OSD5 和 OSD6),每个屏幕有 9 个“插槽”来保存参数。屏幕首先显示一组…