正文
在我们开始做KV cache初始化之前,已对Executor->Workers架构进行了初始化,同时把模型权重加载到了各个Worker对应的卡上。现在我们直接通过
_initialize_kv_caches
的代码,来看kv cache初始化在做什么事(一切尽在注释中):
# https://github.com/vllm-project/vllm/blob/refs/tags/v0.8.2/vllm/v1/engine/core.py#L113
def _initialize_kv_caches(self,
vllm_config: VllmConfig) -> tuple[int, int]:
start = time.time()
# ===================================================================================
# 1、计算对于当前模型,各个worker的各个layer上,attn模块相关的kv cache元数据。
# kv_cache_specs:List[Dict[str, KVCacheSpec]],每一个dict对应一个worker的返回结果:
# - str:模型某一层的layer_name
# - KVCacheSpec:维护在该worker上的、这一层layer的kv cache相关元信息
# 包括 num_heads, head_size,dtype, use_mla等信息
# (注意,这里仅记录元信息,没有实际执行kv cache的分配!)
# - 执行流程:【Executor.get_kv_cache_specs】
# -> 【 MultiProcExecutor.collective_rpc 】:
# Executor触发所有worker执行get_kv_cache_specs,并收集相关结果
# -> 【 GPUModelRunner.get_kv_cache_specs 】:
# Worker上的 ModelRunner 负责实际执行命令
# -> 【 MultiProcExecutor.collective_rpc 】:
# Executor收集各个workers上的结果
# ===================================================================================
kv_cache_specs = self.model_executor.get_kv_cache_specs()
# ===================================================================================
# 2、profiling:模拟执行1次前向计算,统计各个worker(卡)上有多少空间可以留给kv cache
# available_gpu_memory:List[float],每个元素代表一个worker(卡)的返回结果
# 每块卡上可分配给kv cache的显存 = 该卡总显存 * 用户设置的显存利用率 - fwd推理过程中的峰值显存
# ===================================================================================
available_gpu_memory = self.model_executor.determine_available_memory()
assert