当前位置: 首页 > news >正文

engine/sequence

engine/sequence.py

单个请求进来以后被封存成Sequence对象,这个函数是定义相关Sequence对象的

fromcopyimportcopyfromenumimportEnum,autofromitertoolsimportcountfrommy-nano-vllm.sampling_paramsimportSamplingParamsclassSequenceStatus(Enum):WAITING=auto()RUNNING=auto()FINISHED=auto()classSequence:block_size=256counter=count()def__init__(self,token_ids:list[int],sampling_params=SamplingParams()):self.seq_id=next(Sequence.counter)self.status=SequenceStatus.WAITING self.token_ids=copy(token_ids)self.last_token=self.token_ids[-1]self.num_tokens=len(self.token_ids)self.num_prompt_tokens=len(self.token_ids)self.num_cached_tokens=0self.block_table=[]self.temperature=sampling_params.temperature self.max_tokens=sampling_params.max_tokens self.ignore_eos=sampling_params.ignore_eosdef__len__(self):returnself.num_tokensdef__getitem__(self,key):returnself.token_ids[key]@propertydefis_finished(self):returnself.status==SequenceStatus.FINISHED@propertydefnum_completion_tokens(self):returnself.num_tokens-self.num_prompt_tokens@propertydefpromopt_token_ids(self):returnself.token_ids[:self.num_prompt_tokens]@propertydefcompletion_token_ids(self):returnself.token_ids[self.num_prompt_tokens:]@propertydefnum_cached_blocks(self):returnself.num_cached_tokens//self.block_size@propertydefnum_blocks(self):return(self.num_tokens+self.block_size-1)//self.block_size@propertydeflast_block_num_tokens(self):returnself.num_tokens-(self.num_blocks-1)*self.block_sizedefblock(self,i):assert0<=i<=self.num_blocksreturnself.token_ids[i*self.block_size:(i+1)*self.block_size]defappend_token(self,token_id:int):self.token_ids.append(token_id)self.num_tokens+=1self.last_token=token_iddef__getstate__(self):return(self.num_tokens,self.num_prompt_tokens,self.num_cached_tokens,self.block_table,self.token_idsifself.num_completion_tokens==0elseself.last_token)def__setstate__(self,state):self.num_tokens,self.num_prompt_tokens,self.num_cached_tokens,self.block_table=state[:-1]ifself.num_completion_tokens==0:self.token_ids=state[-1]else:self.last_token=state[-1]

SequenceStatus是三种序列的三种生命周期状态,

  • WAITING等待
  • RUNNING运行中
  • FINISHED结束

Sequence序列,比较关键的一个类,用来描述一个请求进来以后被封装的状态

初始化

def__init__(self,token_ids:list[int],sampling_params=SamplingParams()):self.seq_id=next(Sequence.counter)self.status=SequenceStatus.WAITING self.token_ids=copy(token_ids)self.last_token=self.token_ids[-1]self.num_tokens=len(self.token_ids)self.num_prompt_tokens=len(self.token_ids)self.num_cached_tokens=0self.block_table=[]self.temperature=sampling_params.temperature self.max_tokens=sampling_params.max_tokens self.ignore_eos=sampling_params.ignore_eos
  • seq_id,用于标识每一个序列的id,唯一标识
  • status,用于标识序列当前的状态
  • token_ids,存输入和生成的所有token
  • last_token,存最后一个token,用于生成下一个
  • num_tokens,当前所有token总数,每生成一个token会实时更新数量
  • num_prompt_tokens,输入的token总数,不会变化
  • num_cached_tokens,已经进行kv cache缓存的token数量
  • block_table,核心属性,这是一个物理块ID的列表,记录了该序列的KV Cache存储在GPU的哪些显存块里
  • temperaturemax_tokensignore_eos上述介绍过了,不过多赘述
def__len__(self):returnself.num_tokensdef__getitem__(self,key):returnself.token_ids[key]

两个魔术方法

__len__可以获取当前总token数

__getitem__可以获取指定下标的token

@propertydefis_finished(self):returnself.status==SequenceStatus.FINISHED@propertydefnum_completion_tokens(self):returnself.num_tokens-self.num_prompt_tokens@propertydefpromopt_token_ids(self):returnself.token_ids[:self.num_prompt_tokens]@propertydefcompletion_token_ids(self):returnself.token_ids[self.num_prompt_tokens:]@propertydefnum_cached_blocks(self):returnself.num_cached_tokens//self.block_size@propertydefnum_blocks(self):return(self.num_tokens+self.block_size-1)//self.block_size@propertydeflast_block_num_tokens(self):returnself.num_tokens-(self.num_blocks-1)*self.block_size

属性计算方法,用@property装饰器,提供了实时计算的状态,不需要手动更新变量

  • is_finished,序列是否生成完成
  • num_completion_tokens,生成的token的数量,用num_tokens减去num_prompt_tokens
  • prompt_token_ids,获取prompt的token列表,使用python的切片语法
  • completion_token_ids,获取生成的所有token列表,使用python的切片语法
  • num_cached_blocks,计算目前已经有多少个完整的块已经写入缓存(下取整)
  • num_blocks,计算目前缓存所有token需要的KV cache 块的数量(上取整)
  • last_blcok_num_tokens,计算最后一个块里目前填了多少token(如果满了,下次就要申请新的块)
    • 这里的计算方法是用self.num_tokens - (self.num_blocks - 1) * self.block_size
    • 思考一下为什么不用取余?self.num_tokens % self.block_size
      • 为了避免0带来的歧义,0%256 = 256 % 256 = 0,这两者都是0,而前者不需要申请新块,后者却需要,其次速度上取余数也会慢一点
defblock(self,i):assert0<=i<=self.num_blocksreturnself.token_ids[i*self.block_size:(i+1)*self.block_size]defappend_token(self,token_id:int):self.token_ids.append(token_id)self.num_tokens+=1self.last_token=token_id

功能函数

  • block(i)根据索引获取第i个块对应的token子列表
  • append_token(token_id),当模型预测出一个新词时调用,同步更新token_idsnum_tokenslast_token
def__getstate__(self):return(self.num_tokens,self.num_prompt_tokens,self.num_cached_tokens,self.block_table,self.token_idsifself.num_completion_tokens==0elseself.last_token)def__setstate__(self,state):self.num_tokens,self.num_prompt_tokens,self.num_cached_tokens,self.block_table=state[:-1]ifself.num_completion_tokens==0:self.token_ids=state[-1]else:self.last_token=state[-1]

这两个魔术方法构成了一套针对分布式推理场景优化的“数据打包与还原”机制

  • getstate,智能压缩打包,只带走必须带走的东西

    • num_tokensnum_promot_tokensnum_cached_tokensblock_table这四个是序列的元数据,提及很小但至关重要,需要传输
    • 如果模型还在Prefill阶段,也就是没生成token,那就需要打包完整的token_ids
    • 否则,仅需要打包最后一个token即可,因为推理是逐个token生成的,前面的token计算的KV Cache已经存好了,只需要最后一个token即可计算出下一个token,所以我们不需要传输整个列表
  • setstate,按需恢复,这个函数在接收端被调用,负责把收到的“元组”还原回对象属性。

Q:为什么不把num_tokens做成一个属性计算方法,每次需要他的时候直接求len(self.token_ids)

A:为了解决分布式计算中列表丢失的问题,就是上述的getstatesetstate,会导致分布式计算的时候不会永远存储token_ids,所以也就没法利用len函数求长度,我们仅通过维护一个int 变量即可以达到目的,还可以节省传输带宽,何乐而不为呢?而且,访问一个属性的速度肯定会比调用一个@property的方法要快

http://www.jsqmd.com/news/570160/

相关文章:

  • 面试官:MySQL 乐观锁与悲观锁怎么实现?(修订版)
  • AI模型训练显存优化:从Stable Diffusion到LLaMA2的实战配置与调优
  • 魔兽争霸III终极优化指南:免费工具解决现代电脑兼容性问题
  • 京东E卡回收平台推荐,安全有保障! - 团团收购物卡回收
  • input-otp性能优化指南:避免布局偏移和提升用户体验的10个技巧
  • Wan2.2-I2V-A14B图像转视频实战:基于卷积神经网络的风格迁移与动态生成
  • Qwen3-14B部署避坑指南:显存/内存/CUDA驱动兼容性全排查
  • CloudFront + Lambda@Edge 实战:双函数架构实现失败请求记录与异步重放完整方案
  • 璀璨星河Starry Night部署教程:Python3.9+Diffusers环境完整配置
  • 文墨共鸣作品分享:中文食品标签‘零添加’‘无添加’‘不添加’语义等效性验证
  • PyTorch 3.0 DDP + torch.compile混合训练面试通关手册:涵盖Graph Break诊断、Shard策略冲突、以及3种反模式现场复现
  • 2026年西安有名的家装公司排行榜,西安芭宝整装装修公司排第几 - mypinpai
  • 卡牌设计革命:如何用CardEditor批量生成桌游卡牌效率提升300%
  • 豆包API+腾讯云COS实战:手把手教你打造智能图床(含完整代码)
  • 5分钟掌握B站视频下载:免费获取大会员4K高清内容的完整方案
  • Phi-4-mini-reasoning在C语言项目中的调用接口设计与实现
  • 遗传算法(GA)调参实战:以Scikit-learn模型为例,手把手教你自动化超参数搜索
  • 英雄联盟回放分析终极指南:ROFL-Player完整教程
  • 乙巳马年春联生成终端多场景落地:营销/教育/政务/文创四大应用矩阵
  • 解密Twitter风控参数:x-client-transaction-id的生成机制与逆向思考
  • 长沙 GEO 优化公司实测:本地场景适配与转化效率评测 - 亿仁imc
  • 说说西安比较好的家装企业,陕西芭宝整装装饰装修设计有限公司靠谱吗? - 工业设备
  • Qwen3-TTS语音合成案例分享:多语言合成效果展示
  • 2026 年山东长岛渔家乐口碑推荐榜单:长岛民宿、南岛民宿、北岛民宿哪家好,住宿选择全指南 - 海棠依旧大
  • 从零开始:roLabelImg安装与OBB旋转框标注实战指南
  • 长沙网络推广服务商评测:AI赋能与精准获客能力实测 - 亿仁imc
  • 解锁本地图片检索:ImageSearch的千万级图库秒级查找指南
  • Pixel Dimension Fissioner 游戏素材生成实践:快速创建2D像素风与概念原画
  • Phi-4-Reasoning-Vision代码实例:TextIteratorStreamer流式解析实现
  • 软件设计师学习