From 0919b19c1601dd7631d63c3f3cfc302034fd6e13 Mon Sep 17 00:00:00 2001 From: wuhuxiao Date: Thu, 4 Dec 2025 15:21:44 +0800 Subject: [PATCH 1/5] blend ready --- examples/offline_inference_blend.py | 276 +++++++++ ucm/integration/vllm/blend_connector.py | 525 ++++++++++++++++++ .../patch_funcs/v092/vllm_ascend_patch.py | 46 +- .../vllm/patch/patch_funcs/v092/vllm_patch.py | 374 ++++++++++++- ucm/sparse/base.py | 49 +- ucm/sparse/{cache_blend => blend}/README.md | 0 ucm/sparse/blend/__init__.py | 0 ucm/sparse/blend/blend.py | 365 ++++++++++++ ucm/sparse/blend/blockwise_rope.py | 214 +++++++ ucm/sparse/blend/utils.py | 31 ++ ucm/sparse/esa/esa.py | 7 +- ucm/sparse/factory.py | 1 + ucm/sparse/gsa/gsa.py | 11 +- ucm/sparse/kvstar/multistep.py | 7 +- ucm/sparse/state.py | 40 ++ 15 files changed, 1890 insertions(+), 56 deletions(-) create mode 100644 examples/offline_inference_blend.py create mode 100644 ucm/integration/vllm/blend_connector.py rename ucm/sparse/{cache_blend => blend}/README.md (100%) create mode 100644 ucm/sparse/blend/__init__.py create mode 100644 ucm/sparse/blend/blend.py create mode 100644 ucm/sparse/blend/blockwise_rope.py create mode 100644 ucm/sparse/blend/utils.py diff --git a/examples/offline_inference_blend.py b/examples/offline_inference_blend.py new file mode 100644 index 000000000..5218b1744 --- /dev/null +++ b/examples/offline_inference_blend.py @@ -0,0 +1,276 @@ +import contextlib +import csv +import json +import os +import random +import re +import time +from dataclasses import asdict + +from tqdm import tqdm +from vllm.v1.metrics.reader import Counter, Gauge, Histogram, Vector + +random.seed(0) + +import sys + +from transformers import AutoTokenizer +from vllm import LLM, SamplingParams +from vllm.config import KVTransferConfig +from vllm.engine.arg_utils import EngineArgs +from vllm.inputs import TokensPrompt + +from ucm.logger import init_logger + +logger = init_logger(__name__) + +model = "" +data_dir = "" +path_to_dataset = "" +tokenizer = None +# 28705 is the token id for char in llama model +# 151643 is the pad token id in qwen model +chunk_end_token_id = -1 +chunk_pad_token_id = -1 +block_size = 64 + + +def setup_environment_variables(): + os.environ["VLLM_USE_V1"] = "1" + os.environ["PYTHONHASHSEED"] = "123456" + + global model, data_dir, path_to_dataset, tokenizer, chunk_end_token_id, chunk_pad_token_id + model = os.getenv("MODEL_PATH", "/home/models/mistralai/Mistral-7B-Instruct-v0.2") + if not os.path.isdir(model): + model = input( + "Enter path to model, e.g./home/models/mistralai/Mistral-7B-Instruct-v0.2: " + ) + if not os.path.isdir(model): + print("Exiting. Incorrect model_path") + sys.exit(1) + + data_dir = os.getenv("DATA_DIR", "/home/data/kv_cache") + if not os.path.isdir(data_dir): + data_dir = input( + "Enter the directory for UCMStore to save kv cache, e.g. /home/data/kv_cache: " + ) + create = input(f"Directory {data_dir} dose not exist. Create it? (Y/n): ") + if create.lower() == "y": + os.makedirs(data_dir, exist_ok=True) + else: + print("Exiting. Directory not created.") + sys.exit(1) + + # now support wikimqa + path_to_dataset = os.getenv( + "BLEND_DATASET_PATH", "/home/data/Longbench/data/2wikimqa.jsonl" + ) + if not os.path.isfile(path_to_dataset): + path_to_dataset = input( + "Enter path of one of 2wikimqa dataset in longbench, e.g. /home/data/Longbench/data/2wikimqa.jsonl: " + ) + if not os.path.isfile(path_to_dataset): + print("Exiting. Incorrect dataset path") + sys.exit(1) + + tokenizer = AutoTokenizer.from_pretrained(model, use_chat_template=True) + # as for Qwen model, use pad_token_id for padding block + # as for Llama model, current use unk_token for padding block + chunk_pad_token_id = tokenizer.encode("▁", add_special_tokens=False)[0] + chunk_end_token_id = chunk_pad_token_id + + if tokenizer.pad_token_id is not None: + chunk_pad_token_id = tokenizer.pad_token_id + chunk_end_token_id = tokenizer.pad_token_id + + +@contextlib.contextmanager +def build_llm_with_uc(module_path: str, name: str, model: str): + ktc = KVTransferConfig( + kv_connector=name, + kv_connector_module_path=module_path, + kv_role="kv_both", + kv_connector_extra_config={ + "ucm_connectors": [ + { + "ucm_connector_name": "UcmNfsStore", + "ucm_connector_config": { + "storage_backends": data_dir, + "kv_block_size": 33554432, + }, + } + ], + "load_only_first_rank": False, + "ucm_sparse_config": { + "Blend": { + "chunk_end_token_id": chunk_end_token_id, + "compute_meta": { + "model.layers.1.self_attn.attn": { + "ratio": 0.2, + }, + }, + } + }, + "use_layerwise": True, + }, + ) + + llm_args = EngineArgs( + model=model, + enforce_eager=True, + kv_transfer_config=ktc, + max_model_len=16384 * 2, + max_num_batched_tokens=16384 * 2, + gpu_memory_utilization=0.8, + block_size=block_size, + enable_prefix_caching=False, + distributed_executor_backend="mp", + tensor_parallel_size=1, + trust_remote_code=True, + ) + + llm = LLM(**asdict(llm_args)) + try: + yield llm + finally: + logger.info("LLM engine is exiting.") + + +def get_output( + llm: LLM, + prompt, + sampling_params: SamplingParams, +): + start = time.time() + outputs = llm.generate(prompt, sampling_params) + print("-" * 50) + generated_text = None + for output in outputs: + generated_text = output.outputs[0].text + e2e_time = time.time() - start + print("-" * 50) + return e2e_time, generated_text + + +def pad_rag_chunks(token_ids, block_size, pad_id, end_id): + """ + pad token_ids with pad_id and end up with end_id + """ + # assert pad_id != end_id + remainder = len(token_ids) % block_size + + if remainder == 0 and token_ids[-1] in [pad_id, end_id]: + # no need to pad + token_ids[-1] = end_id + return token_ids + + pad_len = block_size - remainder - 1 + padded = token_ids + [pad_id] * pad_len + [end_id] + return padded + + +systemPrompt = """ + You are a helpful assistant. + Please read the following Passages and answer the Question below. +""" + + +def main(): + module_path = "ucm.integration.vllm.blend_connector" + name = "UCMBlendConnector" + + setup_environment_variables() + + with build_llm_with_uc(module_path, name, model) as llm: + prefill_sampling_params = SamplingParams( + temperature=0.0, top_p=0.95, max_tokens=1 + ) + sampling_params = SamplingParams(temperature=0, top_p=0.95, max_tokens=128) + # choose one data row in LongBenchV1 (wikimqa) + assert os.path.isfile( + path_to_dataset + ), f"Incorrect dataset path. Please specify the dataset path by `export DATASET_PATH=/path/to/longbench/multifieldqa_zh.jsonl`" + with open(path_to_dataset, "r") as f: + lines = f.readlines() + dataset_row = json.loads(lines[0]) + + passages = re.findall( + r"Passage\s+(\d+):(.*?)(?=Passage\s+\d+:|$)", dataset_row["context"], re.S + ) + chunks = [f"Passage {i}:{passages[i][1]}" for i in range(len(passages))] + question = "\n Question: " + dataset_row["input"] + "Answer within 5 words." + origin_sys_prompt_ids = tokenizer.encode(systemPrompt) + padded_sys_prompt_ids = pad_rag_chunks( + origin_sys_prompt_ids, block_size, chunk_pad_token_id, chunk_end_token_id + ) + # 1. sys prompt warm up + print(f"---------------1. sys prompt: warm up---------------") + get_output( + llm, + TokensPrompt(prompt_token_ids=padded_sys_prompt_ids), + prefill_sampling_params, + ) + time.sleep(0.5) + + padded_contexts_ids = [] + padded_prompt_ids = padded_sys_prompt_ids + origin_prompt_ids = origin_sys_prompt_ids + for text_chunk in chunks: + un_pad_ids = tokenizer.encode(text_chunk, add_special_tokens=False) + padded_ids = pad_rag_chunks( + un_pad_ids, block_size, chunk_pad_token_id, chunk_end_token_id + ) + padded_prompt_ids = padded_prompt_ids + padded_ids + origin_prompt_ids = origin_prompt_ids + un_pad_ids + padded_contexts_ids.append(padded_ids) + + question_ids = tokenizer.encode(question, add_special_tokens=False) + padded_prompt_ids = padded_prompt_ids + question_ids + origin_prompt_ids = origin_prompt_ids + question_ids + + print(f"--------------- baseline with no cache blend ---------------") + baseline_time, baseline_gen_text = get_output( + llm, TokensPrompt(prompt_token_ids=origin_prompt_ids), sampling_params + ) + time.sleep(0.5) + + print(f"--------------- cache rag chunks ---------------") + llm.generate( + [TokensPrompt(prompt_token_ids=ids) for ids in padded_contexts_ids], + sampling_params, + ) + time.sleep(0.5) + + print(f"--------------- warm up blend code ---------------") + warm_up_blend_prompt_ids = padded_sys_prompt_ids + for ids in reversed(padded_contexts_ids): + warm_up_blend_prompt_ids = warm_up_blend_prompt_ids + ids + warm_up_blend_prompt_ids = warm_up_blend_prompt_ids + question_ids + llm.generate( + TokensPrompt(prompt_token_ids=warm_up_blend_prompt_ids), sampling_params + ) + time.sleep(0.5) + + print(f"--------------- cache blend ---------------") + blend_time, blend_gen_text = get_output( + llm, TokensPrompt(prompt_token_ids=padded_prompt_ids), sampling_params + ) + time.sleep(0.5) + + print(f"--------------- prefix cache ---------------") + pc_time, pc_gen_text = get_output( + llm, TokensPrompt(prompt_token_ids=origin_prompt_ids), sampling_params + ) + + print(f"Baseline generated text: {baseline_gen_text!r}") + print(f"Baseline generated cost time: {baseline_time:.2f} seconds") + print(f"Blend generated text: {blend_gen_text!r}") + print(f"Blend generated cost time: {blend_time:.2f} seconds") + print(f"Prefix Cache generated text: {pc_gen_text!r}") + print(f"Prefix Cache generated cost time: {pc_time:.2f} seconds") + print(f"Question:{dataset_row['input']}") + print(f"Golden answer:{dataset_row["answers"]}") + + +if __name__ == "__main__": + main() diff --git a/ucm/integration/vllm/blend_connector.py b/ucm/integration/vllm/blend_connector.py new file mode 100644 index 000000000..1692d22b3 --- /dev/null +++ b/ucm/integration/vllm/blend_connector.py @@ -0,0 +1,525 @@ +import hashlib +import itertools +import os +import pickle +import time +from dataclasses import dataclass, field +from enum import Enum, auto +from typing import TYPE_CHECKING, Callable, List, Optional, Self, Tuple + +import torch +from vllm.config import VllmConfig +from vllm.distributed.kv_transfer.kv_connector.v1.base import ( + KVConnectorBase_V1, + KVConnectorMetadata, + KVConnectorRole, +) +from vllm.distributed.parallel_state import get_tp_group, get_world_group +from vllm.platforms import current_platform +from vllm.v1.core.sched.output import SchedulerOutput +from vllm.v1.request import Request + +from ucm.integration.vllm.ucm_connector import ( + RequestDispatchMeta, + RequestHasher, + RequestMeta, + UCMConnectorMetadata, + UCMDirectConnector, +) +from ucm.logger import init_logger +from ucm.shared.metrics import ucmmonitor +from ucm.shared.metrics.observability import UCMStatsLogger +from ucm.sparse.blend.blockwise_rope import block_wise_rope_forward +from ucm.sparse.kvstar.multistep import ReqStage +from ucm.store.factory import UcmConnectorFactory +from ucm.store.ucmstore import Task, UcmKVStoreBase +from ucm.utils import Config + +if TYPE_CHECKING: + from vllm.attention.backends.abstract import AttentionMetadata + from vllm.forward_context import ForwardContext + from vllm.v1.core.kv_cache_manager import KVCacheBlocks + +logger = init_logger(__name__) + + +@dataclass +class ChunkMetaData: + # [start, start + len) + start_idx_in_req: int + chunk_tokens_len: int + + start_idx_in_req_blks: int + chunk_blks_len: int + + cached_start_position: int + + vllm_blk_ids: List[int] = field(default_factory=list) + chunk_blks_hash: List[str] = field(default_factory=list) + store_hits: List[bool] = field(default_factory=list) + + @property + def end_idx_in_req(self) -> int: + return self.start_idx_in_req + self.chunk_tokens_len + + @property + def end_idx_in_req_blks(self) -> int: + return self.start_idx_in_req_blks + self.chunk_blks_len + + @property + def cached_end_position(self) -> int: + return self.cached_start_position + self.chunk_tokens_len + + @property + def position_offset(self) -> int: + return self.start_idx_in_req - self.cached_start_position + + @property + def hits_vllm_blk_ids(self) -> List[int]: + return list(itertools.compress(self.vllm_blk_ids, self.store_hits)) + + @property + def hits_chunk_blks_hash(self) -> List[str]: + return list(itertools.compress(self.chunk_blks_hash, self.store_hits)) + + def merge_chunk(self, temp_chunk_meta: Self): + # current we use a fix pattern(end with a fix token id) to recognize the text token chunk + # in some special situation, one text chunk maybe split as multi text chunk, so we should merge them into one + self.chunk_tokens_len += temp_chunk_meta.chunk_tokens_len + self.chunk_blks_len += temp_chunk_meta.chunk_blks_len + self.chunk_blks_hash += temp_chunk_meta.chunk_blks_hash + + def update_meta_partial_pc(self, num_pc_part_blks: int, block_size: int) -> None: + if num_pc_part_blks > 0: + self.start_idx_in_req += num_pc_part_blks * block_size + self.chunk_tokens_len -= num_pc_part_blks * block_size + + self.start_idx_in_req_blks += num_pc_part_blks + self.chunk_blks_len -= num_pc_part_blks + + self.chunk_blks_hash = self.chunk_blks_hash[num_pc_part_blks:] + self.store_hits = self.store_hits[num_pc_part_blks:] + self.cached_start_position += num_pc_part_blks * block_size + + +class BlendStage(Enum): + BUILD_CHUNK_CACHE = auto() + BUILD_PREFIX_CACHE = auto() + CACHE_BLEND = auto() + + def is_blend_cache(self): + return self == BlendStage.CACHE_BLEND + + def is_prefix_cache(self): + return self == BlendStage.BUILD_PREFIX_CACHE + + +@dataclass +class BlendRequestMeta: + ucm_block_hashs: list[str] = field(default_factory=list) + # hbm pc is not supported + hbm_hit_block_num: int = 0 + # ucm pc is supported + pc_hit_block_num: int = 0 + chunks_meta: List[ChunkMetaData] = field(default_factory=list) + blend_stage: BlendStage = BlendStage.BUILD_PREFIX_CACHE + + +@dataclass +class BlendRequestDispatchMeta(RequestDispatchMeta): + chunks_meta: List[ChunkMetaData] + + +@dataclass +class UCMBlendConnectorMetadata(UCMConnectorMetadata): + request_meta: dict[str, BlendRequestDispatchMeta] = field(default_factory=dict) + + +class UCMBlendConnector(UCMDirectConnector): + """ + This Connector means overlap: + load l0 -> forward l0 -> save l0 + load l1 -> forward l1 -> save l1 + load l2 -> forward l2 -> save l2 + """ + + def __init__(self, vllm_config: "VllmConfig", role: KVConnectorRole): + super().__init__(vllm_config, role) + ucm_sparse_config = self.launch_config.get("ucm_sparse_config", []) + self.blend_stage = BlendStage.BUILD_PREFIX_CACHE + self.req2rag_load_chunks: dict[str, list[ChunkMetaData]] = {} + if "Blend" in ucm_sparse_config: + blend_config = ucm_sparse_config["Blend"] + self.enable_blend = True + self.chunk_end_token_id = blend_config["chunk_end_token_id"] + else: + raise "UCMBlendConnector init failed, please check your config" + + self.ucm_chunk_end_hash: int = self.request_hasher("UCM_CHUNK_END_HASH") + self.ucm_chunk_continue_hash: int = self.request_hasher( + "UCM_CHUNK_CONTINUE_HASH" + ) + self.requests_blend_meta: dict[str, BlendRequestMeta] = {} + self.cos_sin_cache: torch.Tensor = None + + # if chunk cache hits less than min_blend_threshold, no need to cache blend + self.min_blend_threshold = 16 + + def _generate_hash( + self, block_size: int, token_ids: list[int], parent_block_hash_value: int + ) -> list[str]: + ret = [] + for start in range(0, len(token_ids), block_size): + end = start + block_size + block_token_ids = token_ids[start:end] + # Do not hash the block if it is not full. + if len(block_token_ids) < block_size: + break + + block_token_ids_tuple = tuple(block_token_ids) + hash_value = self.request_hasher( + (parent_block_hash_value, block_token_ids_tuple) + ) + parent_block_hash_value = hash_value + ret.append(str(hash_value)) + + return ret + + def _process_req(self, all_token_ids: List[int]): + """ + pre-assumption, we explicitly construct block-padded chunk req to make it cached all tokens + beside chunk-build req, we try to split chunk from req, if no chunk exist, it just builds naive prefix cache + if chunk found, first we should match the prefix cache as much as possible, cause, they can be fully reused + then for other chunk blocks, if store hit num of block hash is less than threshold, we do not conduct cache blend + finally, if there are quite many chunk block-hits, we do cache blend to get TTFT-promot + """ + chunks_meta = [] + prefix_block_hashes = self._generate_hash( + self.block_size, all_token_ids, RequestHasher._SEED_HASH + ) + if ( + all_token_ids[-1] == self.chunk_end_token_id + and len(all_token_ids) % self.block_size == 0 + ): + return ( + BlendStage.BUILD_CHUNK_CACHE, + prefix_block_hashes, + chunks_meta, + [], + ) + + start_blk_idx = 0 + start_token_dix = 0 + req_chunks_hashes = [] + + for end_blk_idx, end_token_idx in enumerate( + range(self.block_size - 1, len(all_token_ids), self.block_size) + ): + # only compare the last token id in each blk to split chunk + # in future we should add chunk info as llm engine input,then pass them to schedule out + # but this will bring lots of modification to engine. + if all_token_ids[end_token_idx] == self.chunk_end_token_id: + chunk_token_ids = all_token_ids[start_token_dix : end_token_idx + 1] + chunk_blks_hash = self._generate_hash( + self.block_size, chunk_token_ids, RequestHasher._SEED_HASH + ) + + chunk_blks_len = end_blk_idx - start_blk_idx + 1 + chunk_tokens_len = chunk_blks_len * self.block_size + + rag_chunk_meta = ChunkMetaData( + start_idx_in_req=start_token_dix, + chunk_tokens_len=chunk_tokens_len, + start_idx_in_req_blks=start_blk_idx, + chunk_blks_len=chunk_blks_len, + chunk_blks_hash=chunk_blks_hash, + cached_start_position=0, + ) + + # update for next rag chunk + start_blk_idx = end_blk_idx + 1 + start_token_dix = end_token_idx + 1 + + chunks_meta.append(rag_chunk_meta) + req_chunks_hashes.extend(chunk_blks_hash) + + if chunks_meta: + # found chunk, as for suffix part(such as user question about chunk), current no need to cache hit and dump + return ( + BlendStage.CACHE_BLEND, + prefix_block_hashes, + chunks_meta, + req_chunks_hashes, + ) + else: + return ( + BlendStage.BUILD_PREFIX_CACHE, + prefix_block_hashes, + chunks_meta, + req_chunks_hashes, + ) + + def _get_req_chunk_hit( + self, + req_stage: BlendStage, + prefix_block_hashes: List[str], + req_chunks_meta: List[ChunkMetaData], + req_chunks_hashes: List[str], + ): + + # first perform prefix cache lookup + pc_lookup_results = self.store.lookup(prefix_block_hashes) + pc_hit_blocks = 0 + chunk_hit_blocks = 0 + + for i, hit in enumerate(pc_lookup_results): + if not hit: + break + pc_hit_blocks += 1 + + if not req_stage.is_blend_cache(): + return pc_hit_blocks, chunk_hit_blocks + + # then perform chunk cache lookup + chunk_lookup_results = self.store.lookup(req_chunks_hashes[pc_hit_blocks:]) + chunk_hit_blocks = sum(chunk_lookup_results) + + chunk_lookup_results = pc_lookup_results[:pc_hit_blocks] + chunk_lookup_results + # for cache blend + for i, chunk_meta in enumerate(req_chunks_meta): + chunk_meta.store_hits = chunk_lookup_results[ + chunk_meta.start_idx_in_req_blks : chunk_meta.end_idx_in_req_blks + ] + first_chunk_meta = req_chunks_meta[0] + first_chunk_meta.update_meta_partial_pc(pc_hit_blocks, self.block_size) + # remove total pc hit chunk + if first_chunk_meta.chunk_tokens_len == 0: + req_chunks_meta.pop(0) + + return pc_hit_blocks, chunk_hit_blocks + + def _generate_blend_dispatch_meta( + self, + req_meta: BlendRequestMeta, + new_tokens: int, + vllm_block_ids: list[int], + ) -> BlendRequestDispatchMeta: + """ + Request Blocks layout: + Stage: Build Prefix Cache or Build Chunk Cache (max one chunk per req) + ---------------------------------------------------------------------------------------------------------- + | prefix cache (at first chunk) | other chunk cache | + ---------------------------------------------------------------------------------------------------------- + | LOAD | DUMP | + ---------------------------------------------------------------------------------------------------------- + | REUSE | RECOMPUTE | + ---------------------------------------------------------------------------------------------------------- + + + Stage: Cache Blend + ---------------------------------------------------------------------------------------------------------- + | prefix cache at first chunk | other chunk cache hit | other chunk cache miss | suffix part(question) | + ---------------------------------------------------------------------------------------------------------- + | LOAD | LOAD | NO NEED TO DUMP | NO NEED TO DUMP | + ---------------------------------------------------------------------------------------------------------- + | REUSE | REUSE & RECOMPUTE | RECOMPUTE | RECOMPUTE | + ---------------------------------------------------------------------------------------------------------- + + """ + + # current not support chunk prefill, cause the topK high deviation KV should come from the all tokens + pc_hit_block_num = req_meta.pc_hit_block_num + ucm_block_hashs = req_meta.ucm_block_hashs + # load prefix part + load_ucm_block_ids, load_vllm_block_ids = ( + ucm_block_hashs[:pc_hit_block_num], + vllm_block_ids[:pc_hit_block_num], + ) + dump_ucm_block_ids, dump_vllm_block_ids = [], [] + + if req_meta.blend_stage.is_blend_cache(): + # just need to load, in future we may create a multi-chunk hash to dump and reuse the blended cache + for chunk_meta in req_meta.chunks_meta: + chunk_meta.vllm_blk_ids = vllm_block_ids[ + chunk_meta.start_idx_in_req_blks : chunk_meta.end_idx_in_req_blks + ] + load_ucm_block_ids.extend(chunk_meta.hits_chunk_blks_hash) + load_vllm_block_ids.extend(chunk_meta.hits_vllm_blk_ids) + return BlendRequestDispatchMeta( + (load_ucm_block_ids, load_vllm_block_ids), + (dump_ucm_block_ids, dump_vllm_block_ids), + req_meta.chunks_meta, + ) + + # build cache stage + dump_ucm_block_ids, dump_vllm_block_ids = ( + ucm_block_hashs[pc_hit_block_num:], + vllm_block_ids[pc_hit_block_num : len(ucm_block_hashs)], + ) + return BlendRequestDispatchMeta( + (load_ucm_block_ids, load_vllm_block_ids), + (dump_ucm_block_ids, dump_vllm_block_ids), + req_meta.chunks_meta, + ) + + def _post_process_chunk_cache(self, k_cache, vllm_ids, positions): + """ + post process loaded chunk kcache + """ + if self.cos_sin_cache is None: + raise "Please call setup model first." + # triton kernl for block-wise delta rope + block_wise_rope_forward(k_cache, vllm_ids, positions, self.cos_sin_cache) + + def _register_cos_sin_cache(self, model: "Model"): + try: + rotary_emb = model.model.layers[0].self_attn.rotary_emb + self.cos_sin_cache = rotary_emb.cos_sin_cache + except Exception: + raise "get cos_sin_cache from model failed! current not implemented for this model" + + def setup_model(self, model: "Model") -> None: + self._register_cos_sin_cache(model) + + def get_num_new_matched_tokens( + self, + request: "Request", + num_computed_tokens: int, + ) -> tuple[int, bool]: + + # current not support HBM prefix cache, cause the blended cached have a ground view of all chunks + # so they can not apply to other req + assert num_computed_tokens == 0 + all_token_ids = request.all_token_ids + + max_blk_num = len(all_token_ids) // self.block_size + + if max_blk_num == 0: + return 0, False + + req_stage, prefix_block_hashes, req_chunks_meta, req_chunks_hashes = ( + self._process_req(all_token_ids) + ) + + pc_hit_blocks, chunk_hit_blocks = self._get_req_chunk_hit( + req_stage, prefix_block_hashes, req_chunks_meta, req_chunks_hashes + ) + + if chunk_hit_blocks < self.min_blend_threshold: + req_stage = BlendStage.BUILD_PREFIX_CACHE + req_chunks_meta = [] + + req_block_hashes = prefix_block_hashes + if req_stage.is_blend_cache(): + req_block_hashes = req_chunks_hashes + + logger.info( + f"request_id: {request.request_id}, " + f"total_blocks_num: {max_blk_num}, " + f"req_stage: {req_stage}, " + f"first chunk prefix hit: {pc_hit_blocks}, " + f"chunks cache total hit: {chunk_hit_blocks}, " + ) + if self.metrics_config: + self.monitor.update_stats( + "ConnStats", + {"interval_lookup_hit_rates": chunk_hit_blocks / max_blk_num}, + ) + + pc_hit_tokens = pc_hit_blocks * self.block_size + + # When all the tokens are cached in ssd or hbm, + # we need to recompute the last token. This if condition will be removed + # once vLLM scheduler provides a better solution in the future. + if pc_hit_tokens == request.num_tokens: + pc_hit_tokens -= 1 + + self.requests_blend_meta[request.request_id] = BlendRequestMeta( + ucm_block_hashs=req_block_hashes, + pc_hit_block_num=pc_hit_blocks, + chunks_meta=req_chunks_meta, + blend_stage=req_stage, + ) + + return pc_hit_tokens, False + + def update_state_after_alloc( + self, request: "Request", blocks: "KVCacheBlocks", num_external_tokens: int + ): + pass + + def build_connector_meta( + self, scheduler_output: SchedulerOutput + ) -> KVConnectorMetadata: + requests_dispatch_meta = {} + # for new request, we need to load and dump + for request in scheduler_output.scheduled_new_reqs: + request_id, vllm_block_ids = request.req_id, request.block_ids[0] + req_meta = self.requests_blend_meta.get(request_id) + if req_meta: + requests_dispatch_meta[request_id] = self._generate_blend_dispatch_meta( + req_meta, + scheduler_output.num_scheduled_tokens[request_id], + vllm_block_ids, + ) + + # for cached request, there are 3 situation: + # 1. chunked prefill: we should make sure this will not happen + # 2. resumed: we need to handle like new request + # 3. TODO decode stage: nothing happened + scheduled_cached_reqs = scheduler_output.scheduled_cached_reqs + if not isinstance(scheduled_cached_reqs, list): + # >= 0.9.2 + for i, request_id in enumerate(scheduled_cached_reqs.req_ids): + if scheduler_output.num_scheduled_tokens[request_id] == 1: + # decode stage + continue + req_meta = self.requests_blend_meta.get(request_id) + if req_meta: + requests_dispatch_meta[request_id] = ( + self._generate_blend_dispatch_meta( + req_meta, + scheduler_output.num_scheduled_tokens[request_id], + scheduled_cached_reqs.new_block_ids[i][0], + ) + ) + else: + for request in scheduled_cached_reqs: + request_id = request.request_id + if scheduler_output.num_scheduled_tokens[request_id] == 1: + # decode stage + continue + req_meta = self.requests_blend_meta.get(request_id) + if req_meta: + requests_dispatch_meta[request_id] = ( + self._generate_blend_dispatch_meta( + req_meta, + scheduler_output.num_scheduled_tokens[request_id], + request.new_block_ids[0], + ) + ) + + # clear finished request + for request_id in scheduler_output.finished_req_ids: + self.requests_meta.pop(request_id, None) + + return UCMBlendConnectorMetadata(requests_dispatch_meta) + + def wait_for_layer_load(self, layer_name: str) -> None: + metadata = self._get_connector_metadata() + assert isinstance(metadata, UCMBlendConnectorMetadata) + + all_hits_vllm_ids = [] + positions = [] + k_cache = self.kv_caches[layer_name][0] + for request_id, request in metadata.request_meta.items(): + for chunk_meta in request.chunks_meta: + all_hits_vllm_ids.extend(chunk_meta.hits_vllm_blk_ids) + positions.extend( + [chunk_meta.position_offset] * len(chunk_meta.hits_vllm_blk_ids) + ) + if all_hits_vllm_ids: + vllm_ids = torch.tensor(all_hits_vllm_ids, device=k_cache.device) + positions = torch.tensor(positions, device=k_cache.device) + self._post_process_chunk_cache(k_cache, vllm_ids, positions) + pass diff --git a/ucm/integration/vllm/patch/patch_funcs/v092/vllm_ascend_patch.py b/ucm/integration/vllm/patch/patch_funcs/v092/vllm_ascend_patch.py index f3927ece9..8d4a09af0 100644 --- a/ucm/integration/vllm/patch/patch_funcs/v092/vllm_ascend_patch.py +++ b/ucm/integration/vllm/patch/patch_funcs/v092/vllm_ascend_patch.py @@ -58,7 +58,7 @@ def _apply_ascend_patch() -> None: def _patch_attention_v1() -> None: """Patch attention_v1.py for vLLM-Ascend.""" try: - from typing import List + from typing import List, Optional import torch from vllm.forward_context import ForwardContext, get_forward_context @@ -72,15 +72,19 @@ def maybe_execute_sparse_attention_begin( value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, + phase: Optional[str] = None, ): if not has_ucm_sparse(): - return + return query, key, value, output ucm_sparse = get_ucm_sparse() attn_metadata = forward_context.attn_metadata if attn_metadata is None: - return - ucm_sparse.attention_begin(query, key, value, layer_name, forward_context) + return query, key, value, output + return ucm_sparse.attention_begin( + query, key, value, layer_name, forward_context, output, phase + ) attention_v1.maybe_execute_sparse_attention_begin = ( maybe_execute_sparse_attention_begin @@ -139,7 +143,7 @@ def unified_ascend_attention_with_output_impl( self = forward_context.no_compile_layers[layer_name] kv_cache = self.kv_cache[forward_context.virtual_engine] if not self.use_mla: - maybe_execute_sparse_attention_begin( + query, key, value, _ = maybe_execute_sparse_attention_begin( query, key, value, layer_name, forward_context ) self.impl.forward( @@ -386,13 +390,15 @@ def forward( # FIX: aicore move should be also placed on the comm stream in dbo, # otherwise it may affect the accuracy # TODO: use an elegant way to overlap - maybe_execute_sparse_attention_begin( - prefill_q, - prefill_k_c_normed, - prefill_k_pe, - layer.layer_name, - forward_context, - "prefill", + prefill_q, prefill_k_c_normed, prefill_k_pe, _ = ( + maybe_execute_sparse_attention_begin( + prefill_q, + prefill_k_c_normed, + prefill_k_pe, + layer.layer_name, + forward_context, + phase="prefill", + ) ) output_prefill = self._forward_prefill( prefill_q, prefill_k_c_normed, prefill_k_pe, kv_cache, attn_metadata @@ -414,13 +420,15 @@ def forward( "prefill", ) if has_decode: - maybe_execute_sparse_attention_begin( - torch.cat([decode_ql_nope, decode_q_pe], dim=-1), - decode_ql_nope, - decode_q_pe, - layer.layer_name, - forward_context, - "decode", + _, decode_ql_nope, decode_q_pe, _ = ( + maybe_execute_sparse_attention_begin( + torch.cat([decode_ql_nope, decode_q_pe], dim=-1), + decode_ql_nope, + decode_q_pe, + layer.layer_name, + forward_context, + phase="decode", + ) ) if self.running_in_graph: return self._forward_decode( diff --git a/ucm/integration/vllm/patch/patch_funcs/v092/vllm_patch.py b/ucm/integration/vllm/patch/patch_funcs/v092/vllm_patch.py index 2a697efb0..15bc8037b 100644 --- a/ucm/integration/vllm/patch/patch_funcs/v092/vllm_patch.py +++ b/ucm/integration/vllm/patch/patch_funcs/v092/vllm_patch.py @@ -49,6 +49,8 @@ def _apply_sparse_adapt() -> None: _patch_gpu_worker() _patch_scheduler_output() _patch_scheduler() + _patch_llama_model() + _patch_qwen_model() logger.info("UCM sparse adapt patches applied successfully") except Exception as e: logger.error(f"Could not apply sparse adapt patches: {e}") @@ -147,25 +149,103 @@ def _patch_attention_layer() -> None: from ucm.sparse.state import get_ucm_sparse, has_ucm_sparse + def attn_forward( + self, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + # For some alternate attention backends like MLA the attention output + # shape does not match the query shape, so we optionally let the model + # definition specify the output tensor shape. + output_shape: Optional[torch.Size] = None, + ) -> torch.Tensor: + """ + The KV cache is stored inside this class and is accessed via + `self.kv_cache`. + + Attention metadata (`attn_metadata`) is set using a context manager in + the model runner's `execute_model` method. It is accessed via forward + context using + `vllm.forward_context.get_forward_context().attn_metadata`. + """ + if self.calculate_kv_scales: + attn_metadata = get_forward_context().attn_metadata + if attn_metadata.enable_kv_scales_calculation: + self.calc_kv_scales(query, key, value) + if self.use_output: + output_shape = output_shape if output_shape is not None else query.shape + output = torch.zeros( + output_shape, dtype=query.dtype, device=query.device + ) + hidden_size = output_shape[-1] + # We skip reshaping query, key and value tensors for the MLA + # backend since these tensors have different semantics and are + # processed differently. + if not self.use_mla: + # Reshape the query, key, and value tensors. + # NOTE(woosuk): We do this outside the custom op to minimize the + # CPU overheads from the non-CUDA-graph regions. + query = query.view(-1, self.num_heads, self.head_size) + output = output.view(-1, self.num_heads, self.head_size) + if key is not None: + key = key.view(-1, self.num_kv_heads, self.head_size) + if value is not None: + value = value.view(-1, self.num_kv_heads, self.head_size) + if self.use_direct_call: + forward_context: ForwardContext = get_forward_context() + attn_metadata = forward_context.attn_metadata + if isinstance(attn_metadata, dict): + attn_metadata = attn_metadata[self.layer_name] + self_kv_cache = self.kv_cache[forward_context.virtual_engine] + self.impl.forward( + self, + query, + key, + value, + self_kv_cache, + attn_metadata, + output=output, + ) + else: + torch.ops.vllm.unified_attention_with_output( + query, key, value, output, self.layer_name + ) + return output.view(-1, hidden_size) + else: + if self.use_direct_call: + forward_context = get_forward_context() + attn_metadata = forward_context.attn_metadata + if isinstance(attn_metadata, dict): + attn_metadata = attn_metadata[self.layer_name] + self_kv_cache = self.kv_cache[forward_context.virtual_engine] + return self.impl.forward( + self, query, key, value, self_kv_cache, attn_metadata + ) + else: + return torch.ops.vllm.unified_attention( + query, key, value, self.layer_name + ) + def maybe_execute_sparse_attention_begin( query: torch.Tensor, key: torch.Tensor, value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, phase: Optional[str] = None, ): if not has_ucm_sparse(): - return + return query, key, value, output ucm_sparse = get_ucm_sparse() attn_metadata = forward_context.attn_metadata if attn_metadata is None: - return + return query, key, value, output - ucm_sparse.attention_begin( - query, key, value, layer_name, forward_context, phase + return ucm_sparse.attention_begin( + query, key, value, layer_name, forward_context, output, phase ) def maybe_execute_sparse_attention_finished( @@ -221,7 +301,7 @@ def unified_attention_impl( attn_metadata = attn_metadata[layer_name] self = forward_context.no_compile_layers[layer_name] kv_cache = self.kv_cache[forward_context.virtual_engine] - maybe_execute_sparse_attention_begin( + query, key, value, _ = maybe_execute_sparse_attention_begin( query, key, value, layer_name, forward_context ) output = self.impl.forward(self, query, key, value, kv_cache, attn_metadata) @@ -247,8 +327,8 @@ def unified_attention_with_output_impl( self = forward_context.no_compile_layers[layer_name] kv_cache = self.kv_cache[forward_context.virtual_engine] if not self.use_mla: - maybe_execute_sparse_attention_begin( - query, key, value, layer_name, forward_context + query, key, value, output = maybe_execute_sparse_attention_begin( + query, key, value, layer_name, forward_context, output ) self.impl.forward( self, @@ -281,6 +361,7 @@ def unified_attention_with_output_impl( layer.maybe_execute_sparse_attention_finished = ( maybe_execute_sparse_attention_finished ) + layer.Attention.forward = attn_forward layer.unified_attention = unified_attention_impl layer.unified_attention_with_output = unified_attention_with_output_impl @@ -412,13 +493,15 @@ def forward( ) if has_prefill: - maybe_execute_sparse_attention_begin( - prefill_q, - prefill_k_c_normed, - prefill_k_pe, - layer.layer_name, - forward_context, - "prefill", + prefill_q, prefill_k_c_normed, prefill_k_pe, _ = ( + maybe_execute_sparse_attention_begin( + prefill_q, + prefill_k_c_normed, + prefill_k_pe, + layer.layer_name, + forward_context, + phase="prefill", + ) ) output[num_decode_tokens:] = self._forward_prefill( prefill_q, prefill_k_c_normed, prefill_k_pe, kv_cache, attn_metadata @@ -443,13 +526,15 @@ def forward( decode_ql_nope = torch.bmm(decode_q_nope, self.W_UK_T) # Convert from (N, B, L) to (B, N, L) decode_ql_nope = decode_ql_nope.transpose(0, 1) - maybe_execute_sparse_attention_begin( - torch.cat([decode_ql_nope, decode_q_pe], dim=-1), - decode_ql_nope, - decode_q_pe, - layer.layer_name, - forward_context, - "decode", + _, decode_ql_nope, decode_q_pe, _ = ( + maybe_execute_sparse_attention_begin( + torch.cat([decode_ql_nope, decode_q_pe], dim=-1), + decode_ql_nope, + decode_q_pe, + layer.layer_name, + forward_context, + phase="decode", + ) ) output[:num_decode_tokens] = self._forward_decode( decode_ql_nope, decode_q_pe, kv_cache, attn_metadata @@ -1155,17 +1240,24 @@ def maybe_execute_ucm_sparse_begin( ): if not has_ucm_sparse(): return + + if has_kv_transfer_group(): + uc_connector = get_kv_transfer_group() + uc_setup_model = getattr(uc_connector, "setup_model", None) + if callable(uc_setup_model): + uc_setup_model(self.model) + ucm_sparse = get_ucm_sparse() ucm_sparse.build_sparse_meta( scheduler_output, self.requests, self.input_batch, attn_metadata ) ucm_sparse.execute_begin(scheduler_output) - def maybe_execute_ucm_sparse_finished(self): + def maybe_execute_ucm_sparse_finished(self, logits_indices): if not has_ucm_sparse(): - return + return logits_indices ucm_sparse = get_ucm_sparse() - ucm_sparse.execute_finished() + return ucm_sparse.execute_finished(logits_indices) def ucm_sparse_request_finished_in_worker(self, request_id: str | int): if not has_ucm_sparse(): @@ -1749,7 +1841,7 @@ def execute_model( ) self.maybe_wait_for_kv_save() - self.maybe_execute_ucm_sparse_finished() + logits_indices = self.maybe_execute_ucm_sparse_finished(logits_indices) finished_sending, finished_recving = self.get_finished_kv_transfers( scheduler_output @@ -1990,3 +2082,235 @@ def patched_init_worker_distributed_environment( ) except ImportError: logger.warning("Could not patch gpu worker - module not found") + + +# ==================== vllm/model_executor/models/llama.py ==================== +def _patch_llama_model() -> None: + """Patch gpu worker to add UCM sparse support.""" + try: + from typing import Optional, Union + + import torch + from vllm.config import VllmConfig + from vllm.distributed import get_pp_group + from vllm.model_executor.models.llama import LlamaDecoderLayer, LlamaModel + from vllm.sequence import IntermediateTensors + + from ucm.sparse.state import ( + get_ucm_sparse, + has_ucm_sparse, + maybe_execute_sparse_ffn_begin, + maybe_execute_sparse_ffn_finished, + maybe_execute_sparse_layer_begin, + maybe_execute_sparse_layer_finished, + ) + + def llamaDecoderLayer_forward( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + residual: Optional[torch.Tensor], + ) -> tuple[torch.Tensor, torch.Tensor]: + # Self Attention + if residual is None: + residual = hidden_states + hidden_states = self.input_layernorm(hidden_states) + else: + hidden_states, residual = self.input_layernorm(hidden_states, residual) + hidden_states = self.self_attn( + positions=positions, hidden_states=hidden_states + ) + ###################### + ### UCM PATCH START### + hidden_states, residual = maybe_execute_sparse_ffn_begin( + hidden_states, residual + ) + ### UCM PATCH END ### + ###################### + # Fully Connected + hidden_states, residual = self.post_attention_layernorm( + hidden_states, residual + ) + hidden_states = self.mlp(hidden_states) + ###################### + ### UCM PATCH START### + hidden_states, residual = maybe_execute_sparse_ffn_finished( + hidden_states, residual + ) + ### UCM PATCH END ### + ###################### + return hidden_states, residual + + LlamaDecoderLayer.forward = llamaDecoderLayer_forward + + def llamaModel_forward( + self, + input_ids: Optional[torch.Tensor], + positions: torch.Tensor, + intermediate_tensors: Optional[IntermediateTensors], + inputs_embeds: Optional[torch.Tensor] = None, + ) -> Union[ + torch.Tensor, IntermediateTensors, tuple[torch.Tensor, list[torch.Tensor]] + ]: + if get_pp_group().is_first_rank: + if inputs_embeds is not None: + hidden_states = inputs_embeds + else: + hidden_states = self.get_input_embeddings(input_ids) + residual = None + else: + assert intermediate_tensors is not None + hidden_states = intermediate_tensors["hidden_states"] + residual = intermediate_tensors["residual"] + + aux_hidden_states = [] + for idx, layer in enumerate(self.layers[self.start_layer : self.end_layer]): + ###################### + ### UCM PATCH START### + positions, hidden_states, residual = maybe_execute_sparse_layer_begin( + positions, hidden_states, residual + ) + ### UCM PATCH END ### + ###################### + if idx in self.aux_hidden_state_layers: + aux_hidden_states.append(hidden_states + residual) + hidden_states, residual = layer(positions, hidden_states, residual) + ###################### + ### UCM PATCH START### + positions, hidden_states, residual = ( + maybe_execute_sparse_layer_finished( + positions, hidden_states, residual + ) + ) + ### UCM PATCH END ### + ###################### + + if not get_pp_group().is_last_rank: + return IntermediateTensors( + {"hidden_states": hidden_states, "residual": residual} + ) + + hidden_states, _ = self.norm(hidden_states, residual) + + if len(aux_hidden_states) > 0: + return hidden_states, aux_hidden_states + return hidden_states + + LlamaModel.forward = llamaModel_forward + + except ImportError: + logger.warning("Could not patch llama modelr - module not found") + + +# ==================== vllm/model_executor/models/qwen2.py ==================== +def _patch_qwen_model() -> None: + """Patch gpu worker to add UCM sparse support.""" + try: + from typing import Optional, Union + + import torch + from vllm.config import VllmConfig + from vllm.distributed import get_pp_group + from vllm.model_executor.models.qwen2 import Qwen2DecoderLayer, Qwen2Model + from vllm.sequence import IntermediateTensors + + from ucm.sparse.state import ( + get_ucm_sparse, + has_ucm_sparse, + maybe_execute_sparse_ffn_begin, + maybe_execute_sparse_ffn_finished, + maybe_execute_sparse_layer_begin, + maybe_execute_sparse_layer_finished, + ) + + def qwen2DecoderLayer_forward( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + residual: Optional[torch.Tensor], + ) -> tuple[torch.Tensor, torch.Tensor]: + # Self Attention + if residual is None: + residual = hidden_states + hidden_states = self.input_layernorm(hidden_states) + else: + hidden_states, residual = self.input_layernorm(hidden_states, residual) + hidden_states = self.self_attn( + positions=positions, + hidden_states=hidden_states, + ) + ###################### + ### UCM PATCH START### + residual, hidden_states = maybe_execute_sparse_ffn_begin( + residual, hidden_states + ) + ### UCM PATCH END ### + ###################### + # Fully Connected + hidden_states, residual = self.post_attention_layernorm( + hidden_states, residual + ) + hidden_states = self.mlp(hidden_states) + ###################### + ### UCM PATCH START### + residual, hidden_states = maybe_execute_sparse_ffn_finished( + residual, hidden_states + ) + ### UCM PATCH END ### + ###################### + return hidden_states, residual + + Qwen2DecoderLayer.forward = qwen2DecoderLayer_forward + + def qwen2Model_forward( + self, + input_ids: torch.Tensor, + positions: torch.Tensor, + intermediate_tensors: Optional[IntermediateTensors] = None, + inputs_embeds: Optional[torch.Tensor] = None, + ) -> Union[torch.Tensor, IntermediateTensors]: + if get_pp_group().is_first_rank: + if inputs_embeds is not None: + hidden_states = inputs_embeds + else: + hidden_states = self.get_input_embeddings(input_ids) + residual = None + else: + assert intermediate_tensors is not None + hidden_states = intermediate_tensors["hidden_states"] + residual = intermediate_tensors["residual"] + for layer in self.layers[self.start_layer : self.end_layer]: + ###################### + ### UCM PATCH START### + positions, hidden_states, residual = maybe_execute_sparse_layer_begin( + positions, + hidden_states, + residual, + ) + ### UCM PATCH END ### + ###################### + hidden_states, residual = layer( + positions, + hidden_states, + residual, + ) + ###################### + ### UCM PATCH START### + positions, hidden_states, residual = ( + maybe_execute_sparse_layer_finished( + positions, hidden_states, residual + ) + ) + ### UCM PATCH END ### + ###################### + if not get_pp_group().is_last_rank: + return IntermediateTensors( + {"hidden_states": hidden_states, "residual": residual} + ) + hidden_states, _ = self.norm(hidden_states, residual) + return hidden_states + + Qwen2Model.forward = qwen2Model_forward + + except ImportError: + logger.warning("Could not patch llama modelr - module not found") diff --git a/ucm/sparse/base.py b/ucm/sparse/base.py index ed62ab30c..7dc27fb46 100644 --- a/ucm/sparse/base.py +++ b/ucm/sparse/base.py @@ -23,7 +23,7 @@ import enum from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, List, Optional, Union +from typing import TYPE_CHECKING, List, Optional, Tuple, Union if TYPE_CHECKING: from vllm.v1.core.sched.output import SchedulerOutput @@ -117,11 +117,11 @@ def execute_begin(self, scheduler_output: SchedulerOutput): """ pass - def execute_finished(self): + def execute_finished(self, logits_indices: torch.Tensor) -> torch.Tensor: """ This is called at the end of "ModelRunner->execute_model" function. """ - pass + return logits_indices def attention_begin( self, @@ -130,14 +130,15 @@ def attention_begin( value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, phase: Optional[str] = None, - ) -> None: + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """ This is called at the beginning of "unified_attention". Sparse attention algorithm can modify forward_context.attn_metadata if necessary. (UC_TODO: modify dataclass is not allowed in python?) """ - pass + return query, key, value, output def attention_finished( self, @@ -154,6 +155,44 @@ def attention_finished( """ pass + def ffn_begin( + self, hidden_states: torch.Tensor, residual: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + This is called at the beginning of ffn in each DecodeLayer. + """ + return hidden_states, residual + + def ffn_finished( + self, hidden_states: torch.Tensor, residual: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + This is called at the end of ffn in each DecodeLayer. + """ + return hidden_states, residual + + def layer_begin( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + residual: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ + This is called at the beginning of DecodeLayer. + """ + return positions, hidden_states, residual + + def layer_finished( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + residual: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ + This is called at the end of DecodeLayer. + """ + return positions, hidden_states, residual + def request_finished_in_worker(self, request_id: Union[int, str]): """ This function releases the resources of finished requests at worker-side. diff --git a/ucm/sparse/cache_blend/README.md b/ucm/sparse/blend/README.md similarity index 100% rename from ucm/sparse/cache_blend/README.md rename to ucm/sparse/blend/README.md diff --git a/ucm/sparse/blend/__init__.py b/ucm/sparse/blend/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ucm/sparse/blend/blend.py b/ucm/sparse/blend/blend.py new file mode 100644 index 000000000..c2838e27f --- /dev/null +++ b/ucm/sparse/blend/blend.py @@ -0,0 +1,365 @@ +import time +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union + +import torch +from sympy import false +from torch import Tensor + +from ucm.logger import init_logger +from ucm.store.dramstore.dramstore_connector import device + +logger = init_logger(__name__) + +from vllm.config import VllmConfig +from vllm.forward_context import ForwardContext +from vllm.v1.core.sched.output import SchedulerOutput +from vllm.v1.request import Request + +from ucm.integration.vllm.blend_connector import BlendRequestDispatchMeta, ChunkMetaData +from ucm.sparse.base import ( + INVALID_SLOT, + UcmSparseBase, + UcmSparseMetadata, + UcmSparseRole, +) +from ucm.sparse.utils import round_up + + +def get_num_blks(num_tokens, block_size): + return (num_tokens + block_size - 1) // block_size + + +@dataclass +class ReqMeta: + req_idx: int = 0 + need_blend: bool = false + + prefix_len: int = 0 + prefix_blk_len: int = 0 + + chunks_len: int = 0 + chunks_blk_len: int = 0 + + suffix_len: int = 0 + suffix_blk_len: int = 0 + + chunk_hit_mask: List[bool] = field(default_factory=list) + + chunk_hit_blk_len: int = 0 + + +@dataclass +class BlendMetaData(UcmSparseMetadata): + requests: list[ReqMeta] = field(default_factory=list) + compute_mask: Tensor = None + chunk_blks_hit_mask: Tensor = None + query_lens: Tensor = None + blend_start_req_idx: int = 0 + need_re_index: bool = False + + def reset_blend_meta(self, forward_mask, attn_metadata, scheduler_output): + # current not support chunk prefill + # for multi req in one batch, we should discard the decode req + self.need_re_index = False + self.requests = [] + self.compute_mask = forward_mask[: attn_metadata.query_start_loc[-1]] + + self.query_lens = ( + attn_metadata.query_start_loc[1:] - attn_metadata.query_start_loc[:-1] + ) + + self.blend_start_req_idx = len(scheduler_output.scheduled_cached_reqs.req_ids) + + def add_request( + self, + idx: int, + req_dispatch_meta: BlendRequestDispatchMeta, + seq_lens: Tensor, + block_size: int, + ) -> None: + chunks_meta = req_dispatch_meta.chunks_meta + if chunks_meta: + hit_mask = [] + req_idx_batch = self.blend_start_req_idx + idx + for meta in chunks_meta: + hit_mask.extend(meta.store_hits) + reqMeta = ReqMeta( + req_idx=req_idx_batch, + prefix_len=chunks_meta[0].start_idx_in_req, + prefix_blk_len=get_num_blks( + chunks_meta[0].start_idx_in_req, block_size + ), + chunks_len=len(hit_mask) * block_size, + chunks_blk_len=len(hit_mask), + chunk_hit_mask=hit_mask, + chunk_hit_blk_len=sum(hit_mask), + ) + reqMeta.need_blend = reqMeta.chunk_hit_blk_len > 0 + reqMeta.suffix_len = ( + seq_lens[req_idx_batch].item() - reqMeta.prefix_len - reqMeta.chunks_len + ) + reqMeta.suffix_blk_len = get_num_blks(reqMeta.suffix_len, block_size) + + self.requests.append(reqMeta) + + def reset_compute_mask(self) -> None: + self.compute_mask.fill_(False) + # for decode req in the front of the batch + self.compute_mask[: self.blend_start_req_idx] = True + + def update_query_lens(self, req_idx: int, reused_num_tokens: int) -> None: + self.query_lens[req_idx] -= reused_num_tokens + + def update_need_re_index(self, need_re_index: bool) -> None: + self.need_re_index = need_re_index + + def update_req_compute_mask( + self, + req_query_start, + req_chunk_end, + req_query_end, + chunk_hit_mask, + top_k_indices, + ): + # for multi req batch, maybe we should update compute_mask in batch level rather than in req level + chunks = self.compute_mask[req_query_start:req_chunk_end] + chunks = chunks.reshape(len(chunk_hit_mask), -1) + + # for chunk block cache miss part, just recompute + chunks.masked_fill_(~chunk_hit_mask.unsqueeze(1), True) + + flat = chunks.view(-1) + # for chunk block cache hit part, just recompute HKVD(highest KV deviation) tokens + flat[top_k_indices] = True + + # for question part, default + self.compute_mask[req_chunk_end:req_query_end].fill_(True) + + +class Blend(UcmSparseBase): + def __init__(self, vllm_config: VllmConfig, role: UcmSparseRole): + super().__init__(vllm_config, role) + self.blend_config = vllm_config.kv_transfer_config.kv_connector_extra_config[ + "ucm_sparse_config" + ]["Blend"] + + max_model_len = vllm_config.model_config.max_model_len + self.block_size = vllm_config.cache_config.block_size + + self.device = vllm_config.device_config.device + self.forward_mask = torch.zeros(max_model_len, device=self.device).bool() + self.mask_idx = torch.arange( + round_up(max_model_len, self.block_size), device=self.device + ) + self.mask_idx = self.mask_idx.reshape(-1, self.block_size) + + # for multi batch, ignore the decode-stage req at the beginning + self.blend_start_req_idx = 0 + + self.compute_meta = self.blend_config["compute_meta"] + self.blend_req_metas: BlendMetaData = BlendMetaData( + need_re_index=False, + chunk_blks_hit_mask=torch.zeros( + round_up(max_model_len, self.block_size), device=self.device + ).bool(), + ) + self.attn_metadata = None + + def build_sparse_meta( + self, scheduler_output, requests, input_batch, attn_metadata + ) -> UcmSparseMetadata: + + if isinstance(attn_metadata, dict): + attn_metadata = next(iter(attn_metadata.values())) + self.attn_metadata = attn_metadata + + self.blend_req_metas.reset_blend_meta( + self.forward_mask, attn_metadata, scheduler_output + ) + + blend_conn_request_meta = scheduler_output.kv_connector_metadata.request_meta + for idx, request in enumerate(scheduler_output.scheduled_new_reqs): + req_id = request.req_id + self.blend_req_metas.add_request( + idx, + blend_conn_request_meta[req_id], + attn_metadata.seq_lens, + self.block_size, + ) + + return self.blend_req_metas + + def _update_attn_metadata(self): + # update attn_metadata, cause we sparse the prefill tokens + self.attn_metadata.slot_mapping = self.attn_metadata.slot_mapping[ + self.blend_req_metas.compute_mask + ] + self.attn_metadata.query_start_loc[1:] = torch.cumsum( + self.blend_req_metas.query_lens, dim=0 + ) + self.attn_metadata.max_query_len = self.blend_req_metas.query_lens.max().item() + self.attn_metadata.num_actual_tokens = ( + self.blend_req_metas.query_lens.sum().item() + ) + + def estimate_num_slots_sparsed(self, request: Request) -> int: + """ + This is called by "Scheduler->schedule" function to estimate the number of required blocks. + """ + return INVALID_SLOT + + def request_begin(self, request_id: Union[int, str], prompt_token_ids: List[int]): + pass + + def attention_begin( + self, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + layer_name: str, + forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, + phase: Optional[str] = None, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + attn = forward_context.no_compile_layers[layer_name] + kv_cache = attn.kv_cache[forward_context.virtual_engine] + start_time = time.perf_counter() + if layer_name in self.compute_meta.keys(): + need_update = False + self.blend_req_metas.reset_compute_mask() + + # maybe we can use triton kernel + for req_meta in self.blend_req_metas.requests: + req_idx = req_meta.req_idx + req_query_start = self.attn_metadata.query_start_loc[req_idx].item() + req_query_end = self.attn_metadata.query_start_loc[req_idx + 1].item() + + if not req_meta.need_blend: + self.blend_req_metas.compute_mask[ + req_query_start:req_query_end + ].fill_(True) + continue + req_chunk_end = req_query_start + req_meta.chunks_len + + # HBM prefix cache is not supported now + # UC store prefix cache can be fully reused for the first chunk + his_vllm_blk_ids = self.attn_metadata.block_table[req_idx][ + req_meta.prefix_blk_len : req_meta.prefix_blk_len + + req_meta.chunks_blk_len + ] + # only compute topk of chunk's hits block + chunk_hit_mask = self.blend_req_metas.chunk_blks_hit_mask[ + : len(req_meta.chunk_hit_mask) + ] + src = torch.as_tensor( + req_meta.chunk_hit_mask, + dtype=chunk_hit_mask.dtype, + device=chunk_hit_mask.device, + ) + chunk_hit_mask.copy_(src) + + his_vllm_blk_ids = his_vllm_blk_ids[chunk_hit_mask] + his_k = kv_cache[0, his_vllm_blk_ids] + candidate_len = req_meta.chunk_hit_blk_len * self.block_size + his_k = his_k.reshape(candidate_len, -1) + + req_key = key[req_query_start:req_chunk_end] + + # req_key does not contain prefix cache + golden_k = req_key.reshape( + req_meta.chunks_blk_len, self.block_size, -1 + )[chunk_hit_mask] + golden_k = golden_k.reshape(candidate_len, -1) + + diff_k = torch.sum((his_k - golden_k).abs(), dim=[1]) + topK_num = int(candidate_len * self.compute_meta[layer_name]["ratio"]) + + topK_indices = torch.topk(diff_k, k=topK_num).indices + + # get origin idx in req_key + topK_indices = self.mask_idx[: req_meta.chunks_blk_len][ + chunk_hit_mask + ].reshape(-1)[topK_indices] + + # update compute_mask + self.blend_req_metas.update_req_compute_mask( + req_query_start, + req_chunk_end, + req_query_end, + chunk_hit_mask, + topK_indices, + ) + + self.blend_req_metas.update_query_lens( + req_idx, candidate_len - topK_num + ) + need_update = True + + if need_update: + logger.info( + f"[blend-attn] compute_mask time: {(time.perf_counter() - start_time) * 1000}ms" + ) + self.blend_req_metas.update_need_re_index(True) + self._update_attn_metadata() + + indexed_query = query[self.blend_req_metas.compute_mask] + indexed_key = key[self.blend_req_metas.compute_mask] + indexed_value = value[self.blend_req_metas.compute_mask] + indexed_output = None + if output is not None: + indexed_output = output[: self.blend_req_metas.compute_mask.sum()] + logger.info( + f"[blend-attn] compute_mask time + index time: {(time.perf_counter() - start_time) * 1000}ms" + ) + logger.info( + f"[blend-attn] reduce attn tokens from {len(self.blend_req_metas.compute_mask)} " + f"to {self.attn_metadata.num_actual_tokens}" + ) + return indexed_query, indexed_key, indexed_value, indexed_output + return query, key, value, output + + def ffn_begin( + self, hidden_states: torch.Tensor, residual: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + # hidden_states is equal to attn out, which is contiguous + if self.blend_req_metas.need_re_index and len( + self.blend_req_metas.compute_mask + ) == len(residual): + logger.info( + f"[blend-ffn] after cache blend, reduce ffn tokens from {len(self.blend_req_metas.compute_mask)} " + f"to {self.blend_req_metas.compute_mask.sum().item()}" + ) + return hidden_states[ + : self.attn_metadata.num_actual_tokens + ], self._index_tensor(residual) + return hidden_states, residual + + def layer_begin( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + residual: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + if len(positions) != len(hidden_states): + logger.info( + f"[blend-layer] after cache blend, reduce layer tokens from {len(self.blend_req_metas.compute_mask)} " + f"to {self.blend_req_metas.compute_mask.sum().item()}" + ) + return self._index_tensor(positions), hidden_states, residual + return positions, hidden_states, residual + + def execute_finished(self, logits_indices: torch.Tensor): + if self.blend_req_metas.need_re_index: + modified_logits_indices = self.attn_metadata.query_start_loc[1:] - 1 + logger.info( + f"[blend-model] modify logits_indices from {logits_indices} " + f"to {modified_logits_indices}" + ) + return modified_logits_indices + return logits_indices + + def _index_tensor(self, tensor: torch.Tensor): + if self.blend_req_metas.need_re_index: + return tensor[self.blend_req_metas.compute_mask] + return tensor diff --git a/ucm/sparse/blend/blockwise_rope.py b/ucm/sparse/blend/blockwise_rope.py new file mode 100644 index 000000000..36da7104e --- /dev/null +++ b/ucm/sparse/blend/blockwise_rope.py @@ -0,0 +1,214 @@ +import torch +import triton +import triton.language as tl + + +@triton.jit +def _triton_rope_blockwise_kernel( + k_ptr, # (total_blocks, seq_len, n_kv_head, hd) + vllm_ids, # (bs,) block id for each batch + positions, # (bs,) delta angle for each batch + cos_sin_cache, # (1, seq_len, hd) + k_row_stride, + k_head_stride, + cos_sin_row_stride, + sl, + bs: tl.constexpr, + n_kh: tl.constexpr, + hd: tl.constexpr, + pad_hd: tl.constexpr, +): + """ + each program/batch process a single head for each token + programs matrix (batch_idx, seq_idx, head_idx) + """ + pid = tl.program_id(0) + + heads_per_seq = n_kh + tokens_per_batch = sl * n_kh + batch_idx = pid // tokens_per_batch + seq_head_idx = pid % tokens_per_batch + seq_idx = seq_head_idx // n_kh + head_idx = seq_head_idx % n_kh + + # block id & position + block_id = tl.load(vllm_ids + batch_idx) + pos_idx = tl.load(positions + batch_idx) + + # k offset + k_offset = block_id * k_row_stride + seq_idx * (n_kh * hd) + head_idx * hd + k_ptr = k_ptr + k_offset + + # fetch cos sin from cos_sin_cache + cos_base = pos_idx * cos_sin_row_stride + sin_base = cos_base + hd // 2 # sin just behind cos + + offs = tl.arange(0, pad_hd // 2) + mask = offs < hd // 2 + + cos_row = tl.load(cos_sin_cache + cos_base + offs, mask=mask, other=0) + sin_row = tl.load(cos_sin_cache + sin_base + offs, mask=mask, other=0) + + k_tile_1 = tl.load(k_ptr + offs, mask=mask, other=0).to(cos_row.dtype) + k_tile_2 = tl.load(k_ptr + offs + hd // 2, mask=mask, other=0).to(cos_row.dtype) + + new_k_tile_1 = k_tile_1 * cos_row - k_tile_2 * sin_row + new_k_tile_2 = k_tile_2 * cos_row + k_tile_1 * sin_row + + tl.store(k_ptr + offs, new_k_tile_1, mask=mask) + tl.store(k_ptr + offs + hd // 2, new_k_tile_2, mask=mask) + + +def block_wise_rope_forward(k_cache, vllm_ids, positions, cos_sin_cache): + """ + Args: + k_cache: torch.Tensor (total_blocks, seq_len, n_kv_heads, hd), vllm owned. + vllm_ids: torch.LongTensor (batch_size,), vllm block id + positions: torch.LongTensor (batch_size,), delta angle of each block for rope + cos_sin_cache: torch.Tensor (1, seq_len, hd),same as the tensor in rotary_emb + """ + total_blocks, seq_len, n_kv_head, head_dim = k_cache.shape + batch_size = vllm_ids.shape[0] + pad_hd = triton.next_power_of_2(head_dim) + + k_cache = k_cache.contiguous() + vllm_ids = vllm_ids.contiguous() + positions = positions.contiguous() + cos_sin_cache = cos_sin_cache.contiguous() + + n_row = batch_size * seq_len * n_kv_head + + _triton_rope_blockwise_kernel[(n_row,)]( + k_cache, + vllm_ids, + positions, + cos_sin_cache, + k_cache.stride(0), + k_cache.stride(-2), + cos_sin_cache.stride(-2), + seq_len, + batch_size, + n_kv_head, + head_dim, + pad_hd, + ) + + return k_cache + + +def rope_naive_torch(k_cache, vllm_ids, positions, cos_sin_cache): + """ + naive torch implementation for accuracy and perf baseline + Args: + k_cache: (total_blocks, seq_len, n_heads, hd) + vllm_ids: (bs,) + positions: (bs,) + cos_sin_cache: (1, seq_len, hd) + Returns: + rotated_k: same shape as k_cache + """ + total_blocks, sl, nh, hd = k_cache.shape + bs = vllm_ids.shape[0] + + # copy to avoid in-place modifying original + k_out = k_cache.clone() + + half = hd // 2 + + # cos_sin_cache shape: (1, seq_len, hd) + cos_sin_cache = cos_sin_cache.squeeze(0) # (sl, hd) + cos_table = cos_sin_cache[:, :half] # (sl, half) + sin_table = cos_sin_cache[:, half:] # (sl, half) + + # Loop in python (slow but clear) + for b in range(bs): + blk = vllm_ids[b].item() + pos = positions[b].item() # rope offset + + for s in range(sl): + # cos, sin row for this position + cos = cos_table[pos] # (half,) + sin = sin_table[pos] + + for h in range(nh): + # read original k + k_vec = k_out[blk, s, h] # (hd,) + k1 = k_vec[:half] # (half,) + k2 = k_vec[half:] # (half,) + + # rope rotate + new_k1 = k1 * cos - k2 * sin + new_k2 = k2 * cos + k1 * sin + + # write back + k_out[blk, s, h, :half] = new_k1 + k_out[blk, s, h, half:] = new_k2 + + return k_out + + +if __name__ == "__main__": + import time + + torch.manual_seed(42) + + total_blocks = 5120 + num_blocks = 128 + block_size = 128 + max_num_tokens = num_blocks * block_size + num_heads = 8 + head_size = 128 + dtype = torch.bfloat16 + + kcache = torch.randn( + total_blocks, block_size, num_heads, head_size, device="cuda", dtype=dtype + ) + vllm_ids = torch.randint( + 0, total_blocks, (num_blocks,), device="cuda", dtype=torch.long + ) + positions = torch.randint( + 0, max_num_tokens, (num_blocks,), device="cuda", dtype=torch.long + ) + cos_sin_cache = torch.randn(max_num_tokens, head_size, device="cuda", dtype=dtype) + + # naive torch result + baseline_rope_kcache = rope_naive_torch(kcache, vllm_ids, positions, cos_sin_cache) + + triton_rope_kcache = block_wise_rope_forward( + kcache, vllm_ids, positions, cos_sin_cache + ) + + # precision compare + diff = (triton_rope_kcache[vllm_ids] - baseline_rope_kcache[vllm_ids]).abs() + mean_err = diff.mean().item() + print(f"MAE : {mean_err:.6f}. Expected 1e-3") + + def bench(fn, n_iter=50): + torch.cuda.synchronize() + t0 = time.time() + for _ in range(n_iter): + fn() + torch.cuda.synchronize() + dt = (time.time() - t0) / n_iter + return dt * 1e3 # ms + + ms = bench( + lambda: block_wise_rope_forward(kcache, vllm_ids, positions, cos_sin_cache) + ) + print(f"Kernel avg latency: {ms:.3f} ms. Expected 100 us") + + # load K,load cos,sin -> dump K + bytes_total = ( + num_blocks + * block_size + * num_heads + * ( + head_size * kcache.dtype.itemsize # K load + + vllm_ids.dtype.itemsize # vllm_ids load + + positions.dtype.itemsize # positions load + + head_size * cos_sin_cache.dtype.itemsize # cos sin load + + head_size * kcache.dtype.itemsize # K dump + ) + ) + bw = bytes_total / (ms / 1e3) / (1024**3) + print(f"Estimated memory BW: {bw:.1f} GiB/s") diff --git a/ucm/sparse/blend/utils.py b/ucm/sparse/blend/utils.py new file mode 100644 index 000000000..1397ba950 --- /dev/null +++ b/ucm/sparse/blend/utils.py @@ -0,0 +1,31 @@ +from vllm.model_executor.models.llama import LlamaForCausalLM +from vllm.model_executor.models.qwen2 import Qwen2ForCausalLM + + +def get_rotary_emb_ops(model): + if isinstance(model, Qwen2ForCausalLM): + return model.model.layers[0].self_attn.rotary_emb + if isinstance(model, LlamaForCausalLM): + return model.model.layers[0].self_attn.rotary_emb + else: + raise "get model rotary emb failed! current not implemented for this model" + + +import functools +import time + +from ucm.logger import init_logger + +logger = init_logger(__name__) + + +def timeit(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + elapsed = time.perf_counter() - start + logger.info(f"{func.__name__} exec time: {elapsed:.6f}s") + return result + + return wrapper diff --git a/ucm/sparse/esa/esa.py b/ucm/sparse/esa/esa.py index ac36e54c5..97cf921be 100644 --- a/ucm/sparse/esa/esa.py +++ b/ucm/sparse/esa/esa.py @@ -4,7 +4,7 @@ from collections import defaultdict from dataclasses import dataclass from functools import cache -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union import numpy as np import torch @@ -554,8 +554,9 @@ def attention_begin( value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, phase: Optional[str] = None, - ) -> None: + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: if not self.is_mla: for req_meta in self._sparse_metadata.requests: self.create_req_state_attention_begin( @@ -573,6 +574,8 @@ def attention_begin( req_meta, layer_name, query, key, value, forward_context ) + return query, key, value, output + def update_req_state_attention_end( self, req_meta, layer_name, query, key, value, attn_output, forward_context ): diff --git a/ucm/sparse/factory.py b/ucm/sparse/factory.py index d5b49cf37..da0f6b6e4 100644 --- a/ucm/sparse/factory.py +++ b/ucm/sparse/factory.py @@ -51,3 +51,4 @@ def create_sparse_method( UcmSparseFactory.register_sparse_method( "KVStarMultiStep", "ucm.sparse.kvstar.multistep", "KVStarMultiStep" ) +UcmSparseFactory.register_sparse_method("Blend", "ucm.sparse.blend.blend", "Blend") diff --git a/ucm/sparse/gsa/gsa.py b/ucm/sparse/gsa/gsa.py index b1bf1e5c1..fd54ec927 100644 --- a/ucm/sparse/gsa/gsa.py +++ b/ucm/sparse/gsa/gsa.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from functools import cache, wraps from itertools import accumulate -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Tuple, Union import torch from vllm.config import VllmConfig @@ -631,8 +631,9 @@ def attention_begin( value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, phase: Optional[str] = None, - ) -> None: + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: current_layer_id = int(layer_name.split(".")[2]) if self.prefetch_engine.atb_gsa_enable and self.prefetch_engine.is_topk_cal: if not self.use_mla: @@ -683,6 +684,8 @@ def attention_begin( ] ) + return query, key, value, output + def attention_finished( self, query: torch.Tensor, @@ -901,7 +904,7 @@ def execute_begin(self, scheduler_output: SchedulerOutput): self.gsa_stats = self.gsa_metadata.gsa_stats self._start_topk_cal() - def execute_finished(self): + def execute_finished(self, logits_indices: torch.Tensor): kv_caches = [None] * self.layer_num forward_context = get_forward_context() attn = forward_context.no_compile_layers @@ -1003,6 +1006,8 @@ def check_transfer_task_done(self) -> bool: self.task_load.clear() return True + return logits_indices + def build_sparse_meta( self, scheduler_output: SchedulerOutput, requests, input_batch, attn_metadata ) -> None: diff --git a/ucm/sparse/kvstar/multistep.py b/ucm/sparse/kvstar/multistep.py index 18ed4cb87..7467d1936 100644 --- a/ucm/sparse/kvstar/multistep.py +++ b/ucm/sparse/kvstar/multistep.py @@ -1,7 +1,7 @@ import enum import math from dataclasses import dataclass, field -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Tuple, Union import torch from vllm.config import VllmConfig @@ -731,8 +731,9 @@ def attention_begin( value: torch.Tensor, layer_name: str, forward_context: ForwardContext, + output: Optional[torch.Tensor] = None, phase: Optional[str] = None, - ) -> None: + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """ This is called at the beginning of "unified_attention". Sparse attention algorithm can modify forward_context.attn_metadata if necessary. @@ -746,6 +747,8 @@ def attention_begin( req_layerwise_state.update_meta(req_meta, forward_context) req_layerwise_state.attention_begin(query, key, value, forward_context) + return query, key, value, output + def attention_finished( self, query: torch.Tensor, diff --git a/ucm/sparse/state.py b/ucm/sparse/state.py index a0f77a53b..13a8c51c4 100644 --- a/ucm/sparse/state.py +++ b/ucm/sparse/state.py @@ -8,6 +8,8 @@ from typing import TYPE_CHECKING, Optional +import torch + from ucm.logger import init_logger from ucm.sparse.base import UcmSparseBase, UcmSparseRole from ucm.sparse.factory import UcmSparseFactory @@ -72,3 +74,41 @@ def has_ucm_sparse() -> bool: """Check if UCM sparse agent is available.""" global _UCM_SPARSE_AGENT return _UCM_SPARSE_AGENT is not None + + +def maybe_execute_sparse_layer_begin( + positions: torch.Tensor, hidden_states: torch.Tensor, residual: torch.Tensor +): + if not has_ucm_sparse(): + return positions, hidden_states, residual + ucm_spare = get_ucm_sparse() + # after sparse, n_tokens of source tensor is larger than target + return ucm_spare.layer_begin(positions, hidden_states, residual) + + +def maybe_execute_sparse_layer_finished( + positions: torch.Tensor, hidden_states: torch.Tensor, residual: torch.Tensor +): + if not has_ucm_sparse(): + return positions, hidden_states, residual + ucm_spare = get_ucm_sparse() + # after sparse, n_tokens of source tensor is larger than target + return ucm_spare.layer_finished(positions, hidden_states, residual) + + +def maybe_execute_sparse_ffn_begin(hidden_states: torch.Tensor, residual: torch.Tensor): + if not has_ucm_sparse(): + return hidden_states, residual + ucm_spare = get_ucm_sparse() + # after sparse, n_tokens of source tensor is larger than target + return ucm_spare.ffn_begin(hidden_states, residual) + + +def maybe_execute_sparse_ffn_finished( + hidden_states: torch.Tensor, residual: torch.Tensor +): + if not has_ucm_sparse(): + return hidden_states, residual + ucm_spare = get_ucm_sparse() + # after sparse, n_tokens of source tensor is larger than target + return ucm_spare.ffn_finished(hidden_states, residual) From d6bc98d915cbca17e35851d23d4a38f303cc5ef9 Mon Sep 17 00:00:00 2001 From: wuhuxiao Date: Thu, 4 Dec 2025 15:40:13 +0800 Subject: [PATCH 2/5] clean code --- ucm/integration/vllm/blend_connector.py | 35 +++++++------------------ ucm/sparse/blend/README.md | 1 - ucm/sparse/blend/blend.py | 3 +-- ucm/sparse/blend/blockwise_rope.py | 14 ++++++++-- ucm/sparse/blend/utils.py | 31 ---------------------- ucm/sparse/gsa/gsa.py | 3 +-- ucm/sparse/state.py | 4 --- 7 files changed, 23 insertions(+), 68 deletions(-) delete mode 100644 ucm/sparse/blend/README.md delete mode 100644 ucm/sparse/blend/utils.py diff --git a/ucm/integration/vllm/blend_connector.py b/ucm/integration/vllm/blend_connector.py index 1692d22b3..151e6ec2b 100644 --- a/ucm/integration/vllm/blend_connector.py +++ b/ucm/integration/vllm/blend_connector.py @@ -1,21 +1,14 @@ -import hashlib import itertools -import os -import pickle -import time from dataclasses import dataclass, field from enum import Enum, auto -from typing import TYPE_CHECKING, Callable, List, Optional, Self, Tuple +from typing import TYPE_CHECKING, List, Self, Tuple import torch from vllm.config import VllmConfig from vllm.distributed.kv_transfer.kv_connector.v1.base import ( - KVConnectorBase_V1, KVConnectorMetadata, KVConnectorRole, ) -from vllm.distributed.parallel_state import get_tp_group, get_world_group -from vllm.platforms import current_platform from vllm.v1.core.sched.output import SchedulerOutput from vllm.v1.request import Request @@ -28,16 +21,9 @@ ) from ucm.logger import init_logger from ucm.shared.metrics import ucmmonitor -from ucm.shared.metrics.observability import UCMStatsLogger from ucm.sparse.blend.blockwise_rope import block_wise_rope_forward -from ucm.sparse.kvstar.multistep import ReqStage -from ucm.store.factory import UcmConnectorFactory -from ucm.store.ucmstore import Task, UcmKVStoreBase -from ucm.utils import Config if TYPE_CHECKING: - from vllm.attention.backends.abstract import AttentionMetadata - from vllm.forward_context import ForwardContext from vllm.v1.core.kv_cache_manager import KVCacheBlocks logger = init_logger(__name__) @@ -82,7 +68,7 @@ def hits_vllm_blk_ids(self) -> List[int]: def hits_chunk_blks_hash(self) -> List[str]: return list(itertools.compress(self.chunk_blks_hash, self.store_hits)) - def merge_chunk(self, temp_chunk_meta: Self): + def merge_chunk(self, temp_chunk_meta: Self) -> None: # current we use a fix pattern(end with a fix token id) to recognize the text token chunk # in some special situation, one text chunk maybe split as multi text chunk, so we should merge them into one self.chunk_tokens_len += temp_chunk_meta.chunk_tokens_len @@ -107,10 +93,10 @@ class BlendStage(Enum): BUILD_PREFIX_CACHE = auto() CACHE_BLEND = auto() - def is_blend_cache(self): + def is_blend_cache(self) -> bool: return self == BlendStage.CACHE_BLEND - def is_prefix_cache(self): + def is_prefix_cache(self) -> bool: return self == BlendStage.BUILD_PREFIX_CACHE @@ -137,10 +123,7 @@ class UCMBlendConnectorMetadata(UCMConnectorMetadata): class UCMBlendConnector(UCMDirectConnector): """ - This Connector means overlap: - load l0 -> forward l0 -> save l0 - load l1 -> forward l1 -> save l1 - load l2 -> forward l2 -> save l2 + This Connector process chunk hash and prefix cache """ def __init__(self, vllm_config: "VllmConfig", role: KVConnectorRole): @@ -265,7 +248,7 @@ def _get_req_chunk_hit( prefix_block_hashes: List[str], req_chunks_meta: List[ChunkMetaData], req_chunks_hashes: List[str], - ): + ) -> Tuple[int, int]: # first perform prefix cache lookup pc_lookup_results = self.store.lookup(prefix_block_hashes) @@ -312,7 +295,7 @@ def _generate_blend_dispatch_meta( ---------------------------------------------------------------------------------------------------------- | LOAD | DUMP | ---------------------------------------------------------------------------------------------------------- - | REUSE | RECOMPUTE | + | REUSE | RECOMPUTE | ---------------------------------------------------------------------------------------------------------- @@ -362,7 +345,7 @@ def _generate_blend_dispatch_meta( req_meta.chunks_meta, ) - def _post_process_chunk_cache(self, k_cache, vllm_ids, positions): + def _post_process_chunk_cache(self, k_cache, vllm_ids, positions) -> None: """ post process loaded chunk kcache """ @@ -371,7 +354,7 @@ def _post_process_chunk_cache(self, k_cache, vllm_ids, positions): # triton kernl for block-wise delta rope block_wise_rope_forward(k_cache, vllm_ids, positions, self.cos_sin_cache) - def _register_cos_sin_cache(self, model: "Model"): + def _register_cos_sin_cache(self, model: "Model") -> None: try: rotary_emb = model.model.layers[0].self_attn.rotary_emb self.cos_sin_cache = rotary_emb.cos_sin_cache diff --git a/ucm/sparse/blend/README.md b/ucm/sparse/blend/README.md deleted file mode 100644 index 8b1378917..000000000 --- a/ucm/sparse/blend/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ucm/sparse/blend/blend.py b/ucm/sparse/blend/blend.py index c2838e27f..b42f33885 100644 --- a/ucm/sparse/blend/blend.py +++ b/ucm/sparse/blend/blend.py @@ -13,10 +13,9 @@ from vllm.config import VllmConfig from vllm.forward_context import ForwardContext -from vllm.v1.core.sched.output import SchedulerOutput from vllm.v1.request import Request -from ucm.integration.vllm.blend_connector import BlendRequestDispatchMeta, ChunkMetaData +from ucm.integration.vllm.blend_connector import BlendRequestDispatchMeta from ucm.sparse.base import ( INVALID_SLOT, UcmSparseBase, diff --git a/ucm/sparse/blend/blockwise_rope.py b/ucm/sparse/blend/blockwise_rope.py index 36da7104e..4fea30733 100644 --- a/ucm/sparse/blend/blockwise_rope.py +++ b/ucm/sparse/blend/blockwise_rope.py @@ -59,7 +59,12 @@ def _triton_rope_blockwise_kernel( tl.store(k_ptr + offs + hd // 2, new_k_tile_2, mask=mask) -def block_wise_rope_forward(k_cache, vllm_ids, positions, cos_sin_cache): +def block_wise_rope_forward( + k_cache: torch.Tensor, + vllm_ids: torch.Tensor, + positions: torch.Tensor, + cos_sin_cache: torch.Tensor, +) -> torch.Tensor: """ Args: k_cache: torch.Tensor (total_blocks, seq_len, n_kv_heads, hd), vllm owned. @@ -96,7 +101,12 @@ def block_wise_rope_forward(k_cache, vllm_ids, positions, cos_sin_cache): return k_cache -def rope_naive_torch(k_cache, vllm_ids, positions, cos_sin_cache): +def rope_naive_torch( + k_cache: torch.Tensor, + vllm_ids: torch.Tensor, + positions: torch.Tensor, + cos_sin_cache: torch.Tensor, +) -> torch.Tensor: """ naive torch implementation for accuracy and perf baseline Args: diff --git a/ucm/sparse/blend/utils.py b/ucm/sparse/blend/utils.py deleted file mode 100644 index 1397ba950..000000000 --- a/ucm/sparse/blend/utils.py +++ /dev/null @@ -1,31 +0,0 @@ -from vllm.model_executor.models.llama import LlamaForCausalLM -from vllm.model_executor.models.qwen2 import Qwen2ForCausalLM - - -def get_rotary_emb_ops(model): - if isinstance(model, Qwen2ForCausalLM): - return model.model.layers[0].self_attn.rotary_emb - if isinstance(model, LlamaForCausalLM): - return model.model.layers[0].self_attn.rotary_emb - else: - raise "get model rotary emb failed! current not implemented for this model" - - -import functools -import time - -from ucm.logger import init_logger - -logger = init_logger(__name__) - - -def timeit(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - start = time.perf_counter() - result = func(*args, **kwargs) - elapsed = time.perf_counter() - start - logger.info(f"{func.__name__} exec time: {elapsed:.6f}s") - return result - - return wrapper diff --git a/ucm/sparse/gsa/gsa.py b/ucm/sparse/gsa/gsa.py index fd54ec927..20aa7a69b 100644 --- a/ucm/sparse/gsa/gsa.py +++ b/ucm/sparse/gsa/gsa.py @@ -933,6 +933,7 @@ def execute_finished(self, logits_indices: torch.Tensor): self.prefetch_engine.deal_async_prefetch( False, self.gsa_metadata, kv_caches, None ) + return logits_indices def launch_transfer_task(self, all_free_block_ids, all_miss_ids, kv_caches): if all_free_block_ids == None: @@ -1006,8 +1007,6 @@ def check_transfer_task_done(self) -> bool: self.task_load.clear() return True - return logits_indices - def build_sparse_meta( self, scheduler_output: SchedulerOutput, requests, input_batch, attn_metadata ) -> None: diff --git a/ucm/sparse/state.py b/ucm/sparse/state.py index 13a8c51c4..36cd93909 100644 --- a/ucm/sparse/state.py +++ b/ucm/sparse/state.py @@ -82,7 +82,6 @@ def maybe_execute_sparse_layer_begin( if not has_ucm_sparse(): return positions, hidden_states, residual ucm_spare = get_ucm_sparse() - # after sparse, n_tokens of source tensor is larger than target return ucm_spare.layer_begin(positions, hidden_states, residual) @@ -92,7 +91,6 @@ def maybe_execute_sparse_layer_finished( if not has_ucm_sparse(): return positions, hidden_states, residual ucm_spare = get_ucm_sparse() - # after sparse, n_tokens of source tensor is larger than target return ucm_spare.layer_finished(positions, hidden_states, residual) @@ -100,7 +98,6 @@ def maybe_execute_sparse_ffn_begin(hidden_states: torch.Tensor, residual: torch. if not has_ucm_sparse(): return hidden_states, residual ucm_spare = get_ucm_sparse() - # after sparse, n_tokens of source tensor is larger than target return ucm_spare.ffn_begin(hidden_states, residual) @@ -110,5 +107,4 @@ def maybe_execute_sparse_ffn_finished( if not has_ucm_sparse(): return hidden_states, residual ucm_spare = get_ucm_sparse() - # after sparse, n_tokens of source tensor is larger than target return ucm_spare.ffn_finished(hidden_states, residual) From f982864a76ef91f7a0b59ee02ba3ed926d6b15d4 Mon Sep 17 00:00:00 2001 From: wuhuxiao Date: Fri, 5 Dec 2025 15:27:12 +0800 Subject: [PATCH 3/5] update blend doc --- docs/source/_static/images/blend_scheme.jpg | Bin 0 -> 219093 bytes .../user-guide/sparse-attention/cacheblend.md | 109 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 docs/source/_static/images/blend_scheme.jpg create mode 100644 docs/source/user-guide/sparse-attention/cacheblend.md diff --git a/docs/source/_static/images/blend_scheme.jpg b/docs/source/_static/images/blend_scheme.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75638b68c1ff79b4820781b778f1925b3a557e6f GIT binary patch literal 219093 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 w^Jx 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%0D1US3obidTfC$})|doK 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 literal 0 HcmV?d00001 diff --git a/docs/source/user-guide/sparse-attention/cacheblend.md b/docs/source/user-guide/sparse-attention/cacheblend.md new file mode 100644 index 000000000..9b7e7dd6c --- /dev/null +++ b/docs/source/user-guide/sparse-attention/cacheblend.md @@ -0,0 +1,109 @@ +# CacheBlend: : Fast Large Language Model Serving for RAG with Cached Knowledge Fusion +

+ +## 🌟 What is CacheBlend? + +**CacheBlend** is a cached fusion system that combines multiple pre-computed KV caches, when their corresponding texts +are concatenated in the LLM input. By selectively recomputing the KV cache values of a small fraction of tokens, +CacheBlend reduces TTFT by 2.2 ~ 3.3Γ— and increases throughput by 2.8 ~ 5Γ— under negligible quality drop. +### 🎯 Key Component + +- **πŸ” Loading Controller**: the Loading Controller orchestrates which KV caches to load, where from, and how much recomputation is needed. +- **⚑ KV Cache Store**: the KV Cache Store manages persistent storage, lookup, and eviction of precomputed KV caches keyed by text-chunk identity. +- **πŸŽ›οΈ Cache Fusor**: the Fusor merges multiple chunk-level caches into one coherent, cross-attention–correct KV cache, using minimal recomputation. + +### πŸ”₯ Key Results +- **2.2 ~ 3.3Γ— speedup** of TTFT and **2.8 ~ 5Γ— increase** of throughput for long sequences +- **Preserve High quality** no more than (1% ~ 3%) quality drop compared to full KV recompute + +## 🧠 Ucm Implementation + +### Native Block-Wise Chunk KV Cache Dump, Load, PostProcess and Recompute +1. **πŸ” Chunk Hash Encoding**: Similar as prefix hash encoder, hash all blocks in each chunk from the same hash meta beginning. +2. **⚑ Combine Prefix Cache and Chunk Cache**: Since chunk cache and native prefix cache share the same hash space, ucm first performs prefix cache lookup to fetch fully resued cache and then conduct chunk cache lookup to fetch the candidate cache for blending. +3. **🎯 Delta-Rope PostProcess**: Rectify loaded chunk cache according to their position in the new request. +3. **πŸ” Integrate Cache Blend and First Token Generation**: Construct compute mask and attention meta according to HKVD tokens, cache miss tokens and suffix tokens, then compute their kv cache in a single model forward stage +4. **πŸš€ Comprehensive Hook for LLM Forward Pipeline**: Based on ucm sparse module, blend module spare the prefill tokens not only in attention stage but also in ffn, layer stage. + +## πŸš€ Quick Start + +### Installation + +Blend is part of the UCM Sparse Attention module. For installation instructions, please refer to the [UCM's top-level README](https://github.com/ModelEngine-Group/unified-cache-management). Once UCM is installed, Blend is naturally supported by running the following example python scripts. + +```bash +export ENABLE_SPARSE=TRUE +export DATA_DIR=/home/data/kv_cache +export MODEL_PATH=/home/models/mistralai/Mistral-7B-Instruct-v0.2 +export BLEND_DATASET_PATH=/home/datasets/LongBench/data/2wikimqa.jsonl +python /examples/offline_inference_blend.py +``` + +### Basic Usage +Similr to UCM's `offline_inference_esa.py` examples. We only need to specify `ucm_sparse_method` to be `Blend` and specify meta config, as shown below. + +```python +... +ktc = KVTransferConfig( + kv_connector=name, + kv_connector_module_path=module_path, + kv_role="kv_both", + kv_connector_extra_config={ + "ucm_connectors": [ + { + "ucm_connector_name": "UcmNfsStore", + "ucm_connector_config": { + "storage_backends": data_dir, + "kv_block_size": 33554432, + }, + } + ], + "load_only_first_rank": False, + "ucm_sparse_config": { + "Blend": { + "chunk_end_token_id": chunk_end_token_id, + "compute_meta": { + "model.layers.1.self_attn.attn": { + "ratio": 0.2, + }, + }, + } + }, + "use_layerwise": True, + }, + ) +... +``` + +## πŸ“Š Supported Models +Llama-based models and Qwen-based models now are available + +## πŸŽ“ Citation + +```bibtex +@inproceedings{yao2025cacheblend, + title={CacheBlend: Fast large language model serving for RAG with cached knowledge fusion}, + author={Yao, Jiayi and Li, Hanchen and Liu, Yuhan and Ray, Siddhant and Cheng, Yihua and Zhang, Qizheng and Du, Kuntai and Lu, Shan and Jiang, Junchen}, + booktitle={Proceedings of the Twentieth European Conference on Computer Systems}, + pages={94--109}, + year={2025} +} +``` + + +--- + +
+ +**🌟 Star [UCM](https://github.com/ModelEngine-Group/unified-cache-management) repository if you find KvComp useful!** + +
From 5a37f346b05e9da0eee0ba999b6d3a5fc0018388 Mon Sep 17 00:00:00 2001 From: wuhuxiao Date: Tue, 9 Dec 2025 09:24:16 +0800 Subject: [PATCH 4/5] clean code --- .../user-guide/sparse-attention/cacheblend.md | 8 +++--- ucm/integration/vllm/blend_connector.py | 26 +++++++++---------- ucm/sparse/blend/blend.py | 6 ++--- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/docs/source/user-guide/sparse-attention/cacheblend.md b/docs/source/user-guide/sparse-attention/cacheblend.md index 9b7e7dd6c..0f5d8e819 100644 --- a/docs/source/user-guide/sparse-attention/cacheblend.md +++ b/docs/source/user-guide/sparse-attention/cacheblend.md @@ -29,10 +29,10 @@ CacheBlend reduces TTFT by 2.2 ~ 3.3Γ— and increases throughput by 2.8 ~ 5Γ— und ### Native Block-Wise Chunk KV Cache Dump, Load, PostProcess and Recompute 1. **πŸ” Chunk Hash Encoding**: Similar as prefix hash encoder, hash all blocks in each chunk from the same hash meta beginning. -2. **⚑ Combine Prefix Cache and Chunk Cache**: Since chunk cache and native prefix cache share the same hash space, ucm first performs prefix cache lookup to fetch fully resued cache and then conduct chunk cache lookup to fetch the candidate cache for blending. +2. **⚑ Combine Prefix Cache and Chunk Cache**: Since chunk cache and native prefix cache share the same hash space, ucm first performs prefix cache lookup to fetch fully reused cache and then conduct chunk cache lookup to fetch the candidate cache for blending. 3. **🎯 Delta-Rope PostProcess**: Rectify loaded chunk cache according to their position in the new request. -3. **πŸ” Integrate Cache Blend and First Token Generation**: Construct compute mask and attention meta according to HKVD tokens, cache miss tokens and suffix tokens, then compute their kv cache in a single model forward stage -4. **πŸš€ Comprehensive Hook for LLM Forward Pipeline**: Based on ucm sparse module, blend module spare the prefill tokens not only in attention stage but also in ffn, layer stage. +3. **πŸ” Integrate Cache Blend and First Token Generation**: Construct compute mask and attention meta according to HKVD tokens, cache miss tokens and suffix tokens, then compute their kv cache in a single model forward stage. +4. **πŸš€ Comprehensive Hook for LLM Forward Pipeline**: Based on ucm sparse module, blend module sparse the prefill tokens not only in attention stage but also in ffn, layer stage. ## πŸš€ Quick Start @@ -49,7 +49,7 @@ python /examples/offline_inference_blend.py ``` ### Basic Usage -Similr to UCM's `offline_inference_esa.py` examples. We only need to specify `ucm_sparse_method` to be `Blend` and specify meta config, as shown below. +Similar to UCM's `offline_inference_esa.py` examples. We only need to specify `ucm_sparse_method` to be `Blend` and specify meta config, as shown below. ```python ... diff --git a/ucm/integration/vllm/blend_connector.py b/ucm/integration/vllm/blend_connector.py index 151e6ec2b..eaba1b381 100644 --- a/ucm/integration/vllm/blend_connector.py +++ b/ucm/integration/vllm/blend_connector.py @@ -32,10 +32,10 @@ @dataclass class ChunkMetaData: # [start, start + len) - start_idx_in_req: int + start_token_dix: int chunk_tokens_len: int - start_idx_in_req_blks: int + start_blk_idx: int chunk_blks_len: int cached_start_position: int @@ -45,12 +45,12 @@ class ChunkMetaData: store_hits: List[bool] = field(default_factory=list) @property - def end_idx_in_req(self) -> int: - return self.start_idx_in_req + self.chunk_tokens_len + def end_token_dix(self) -> int: + return self.start_token_dix + self.chunk_tokens_len @property - def end_idx_in_req_blks(self) -> int: - return self.start_idx_in_req_blks + self.chunk_blks_len + def end_blk_idx(self) -> int: + return self.start_blk_idx + self.chunk_blks_len @property def cached_end_position(self) -> int: @@ -58,7 +58,7 @@ def cached_end_position(self) -> int: @property def position_offset(self) -> int: - return self.start_idx_in_req - self.cached_start_position + return self.start_token_dix - self.cached_start_position @property def hits_vllm_blk_ids(self) -> List[int]: @@ -77,10 +77,10 @@ def merge_chunk(self, temp_chunk_meta: Self) -> None: def update_meta_partial_pc(self, num_pc_part_blks: int, block_size: int) -> None: if num_pc_part_blks > 0: - self.start_idx_in_req += num_pc_part_blks * block_size + self.start_token_dix += num_pc_part_blks * block_size self.chunk_tokens_len -= num_pc_part_blks * block_size - self.start_idx_in_req_blks += num_pc_part_blks + self.start_blk_idx += num_pc_part_blks self.chunk_blks_len -= num_pc_part_blks self.chunk_blks_hash = self.chunk_blks_hash[num_pc_part_blks:] @@ -211,9 +211,9 @@ def _process_req(self, all_token_ids: List[int]): chunk_tokens_len = chunk_blks_len * self.block_size rag_chunk_meta = ChunkMetaData( - start_idx_in_req=start_token_dix, + start_token_dix=start_token_dix, chunk_tokens_len=chunk_tokens_len, - start_idx_in_req_blks=start_blk_idx, + start_blk_idx=start_blk_idx, chunk_blks_len=chunk_blks_len, chunk_blks_hash=chunk_blks_hash, cached_start_position=0, @@ -271,7 +271,7 @@ def _get_req_chunk_hit( # for cache blend for i, chunk_meta in enumerate(req_chunks_meta): chunk_meta.store_hits = chunk_lookup_results[ - chunk_meta.start_idx_in_req_blks : chunk_meta.end_idx_in_req_blks + chunk_meta.start_blk_idx : chunk_meta.end_blk_idx ] first_chunk_meta = req_chunks_meta[0] first_chunk_meta.update_meta_partial_pc(pc_hit_blocks, self.block_size) @@ -324,7 +324,7 @@ def _generate_blend_dispatch_meta( # just need to load, in future we may create a multi-chunk hash to dump and reuse the blended cache for chunk_meta in req_meta.chunks_meta: chunk_meta.vllm_blk_ids = vllm_block_ids[ - chunk_meta.start_idx_in_req_blks : chunk_meta.end_idx_in_req_blks + chunk_meta.start_blk_idx : chunk_meta.end_blk_idx ] load_ucm_block_ids.extend(chunk_meta.hits_chunk_blks_hash) load_vllm_block_ids.extend(chunk_meta.hits_vllm_blk_ids) diff --git a/ucm/sparse/blend/blend.py b/ucm/sparse/blend/blend.py index b42f33885..7cc945674 100644 --- a/ucm/sparse/blend/blend.py +++ b/ucm/sparse/blend/blend.py @@ -85,10 +85,8 @@ def add_request( hit_mask.extend(meta.store_hits) reqMeta = ReqMeta( req_idx=req_idx_batch, - prefix_len=chunks_meta[0].start_idx_in_req, - prefix_blk_len=get_num_blks( - chunks_meta[0].start_idx_in_req, block_size - ), + prefix_len=chunks_meta[0].start_token_dix, + prefix_blk_len=get_num_blks(chunks_meta[0].start_token_dix, block_size), chunks_len=len(hit_mask) * block_size, chunks_blk_len=len(hit_mask), chunk_hit_mask=hit_mask, From df6f40334d783fce11b07cab5e463b30580d99a0 Mon Sep 17 00:00:00 2001 From: wuhuxiao Date: Wed, 10 Dec 2025 14:24:56 +0800 Subject: [PATCH 5/5] midify prompt --- examples/offline_inference_blend.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/offline_inference_blend.py b/examples/offline_inference_blend.py index 5218b1744..0de105f55 100644 --- a/examples/offline_inference_blend.py +++ b/examples/offline_inference_blend.py @@ -169,10 +169,7 @@ def pad_rag_chunks(token_ids, block_size, pad_id, end_id): return padded -systemPrompt = """ - You are a helpful assistant. - Please read the following Passages and answer the Question below. -""" +systemPrompt = "Answer the question based on the given passages. Only give me the answer and do not output any other words.\n\nThe following are given passages.\n" def main(): @@ -198,7 +195,7 @@ def main(): r"Passage\s+(\d+):(.*?)(?=Passage\s+\d+:|$)", dataset_row["context"], re.S ) chunks = [f"Passage {i}:{passages[i][1]}" for i in range(len(passages))] - question = "\n Question: " + dataset_row["input"] + "Answer within 5 words." + question = f"\n\nAnswer the question based on the given passages. Answer the question within 5 words. Do NOT repeat the question or output any other words. Question: {dataset_row["input"]}\nAnswer:" origin_sys_prompt_ids = tokenizer.encode(systemPrompt) padded_sys_prompt_ids = pad_rag_chunks( origin_sys_prompt_ids, block_size, chunk_pad_token_id, chunk_end_token_id