Files
enginex-iluvatar-bi100-vllm…/detect_head_size.py
Sun Ruoxi 0c1bb7a415
All checks were successful
Docker Build and Push / docker (push) Successful in 1m5s
feature:add head size detect and patch some ops
Signed-off-by: Sun Ruoxi <sunruoxi@4paradigm.com>
2026-07-27 16:45:05 +08:00

187 lines
6.3 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
检测模型的head_size如果不在vLLM支持列表中则patch到vllm代码中
"""
import os
import json
import re
import shutil
from typing import Optional, List
# vLLM默认支持的head_size列表
DEFAULT_SUPPORTED_HEAD_SIZES = [64, 80, 96, 112, 120, 128, 192, 256]
# vLLM需要patch的文件路径
VLLM_PAGED_ATTN_PATH = "/usr/local/corex/lib64/python3/dist-packages/vllm/attention/ops/paged_attn.py"
def get_model_head_size(model_dir: str) -> Optional[int]:
"""
从模型config.json中获取head_size
Args:
model_dir: 模型目录路径
Returns:
head_size如果无法获取则返回None
"""
config_path = os.path.join(model_dir, "config.json")
if not os.path.exists(config_path):
print(f"[detect_head_size] config.json not found in {model_dir}")
return None
try:
with open(config_path, 'r') as f:
config = json.load(f)
# 尝试多种方式获取head_size
# 1. 直接从head_dim字段获取
if 'head_dim' in config:
head_size = config['head_dim']
print(f"[detect_head_size] Found head_dim in config: {head_size}")
return head_size
# 2. 从hidden_size和num_attention_heads计算
if 'hidden_size' in config and 'num_attention_heads' in config:
hidden_size = config['hidden_size']
num_heads = config['num_attention_heads']
head_size = hidden_size // num_heads
print(f"[detect_head_size] Calculated from hidden_size({hidden_size}) / num_attention_heads({num_heads}) = {head_size}")
return head_size
# 3. 对于GPTJ等模型可能使用n_embd和n_head
if 'n_embd' in config and 'n_head' in config:
n_embd = config['n_embd']
n_head = config['n_head']
head_size = n_embd // n_head
print(f"[detect_head_size] Calculated from n_embd({n_embd}) / n_head({n_head}) = {head_size}")
return head_size
# 4. 对于T5等模型可能使用d_kv和num_heads
if 'd_kv' in config:
head_size = config['d_kv']
print(f"[detect_head_size] Found d_kv in config: {head_size}")
return head_size
print(f"[detect_head_size] Cannot determine head_size from config.json")
return None
except Exception as e:
print(f"[detect_head_size] Error reading config.json: {e}")
return None
def patch_vllm_head_sizes(new_head_size: int) -> bool:
"""
将新的head_size patch到vLLM的get_supported_head_sizes方法中
Args:
new_head_size: 需要添加的新head_size
Returns:
是否成功patch
"""
if not os.path.exists(VLLM_PAGED_ATTN_PATH):
print(f"[patch] vLLM file not found: {VLLM_PAGED_ATTN_PATH}")
return False
try:
# 备份原文件
backup_path = VLLM_PAGED_ATTN_PATH + ".backup"
if not os.path.exists(backup_path):
shutil.copy2(VLLM_PAGED_ATTN_PATH, backup_path)
print(f"[patch] Backed up original file to {backup_path}")
# 读取文件内容
with open(VLLM_PAGED_ATTN_PATH, 'r') as f:
content = f.read()
# 找到get_supported_head_sizes方法并patch
pattern = r'(@staticmethod\s+def get_supported_head_sizes\(\)\s*->\s*List\[int\]:\s*return\s*\[)([^\]]+)(\])'
match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
if not match:
print(f"[patch] Could not find get_supported_head_sizes method in {VLLM_PAGED_ATTN_PATH}")
return False
prefix = match.group(1)
current_list = match.group(2)
suffix = match.group(3)
# 解析当前列表
current_sizes = [int(x.strip()) for x in current_list.split(',') if x.strip()]
# 添加新的head_size并排序
if new_head_size not in current_sizes:
current_sizes.append(new_head_size)
current_sizes.sort()
# 生成新的列表字符串
new_list_str = ', '.join(str(size) for size in current_sizes)
# 替换原方法
new_method = f"{prefix}{new_list_str}{suffix}"
new_content = re.sub(pattern, new_method, content, flags=re.MULTILINE | re.DOTALL)
# 写回文件
with open(VLLM_PAGED_ATTN_PATH, 'w') as f:
f.write(new_content)
print(f"[patch] Successfully added head_size {new_head_size} to supported list: {current_sizes}")
return True
else:
print(f"[patch] head_size {new_head_size} already in list, skipping")
return True
except Exception as e:
print(f"[patch] Error patching vLLM file: {e}")
return False
def main():
"""主函数"""
try:
model_dir = os.environ.get("MODEL_DIR", "/model")
print(f"[detect_head_size] Checking model in: {model_dir}")
# 获取head_size
head_size = get_model_head_size(model_dir)
if head_size is None:
print(f"[detect_head_size] Could not determine head_size, skipping")
return
print(f"[detect_head_size] Model head_size: {head_size}")
# 检查是否需要patch
if head_size in DEFAULT_SUPPORTED_HEAD_SIZES:
print(f"[detect_head_size] head_size {head_size} is already supported by vLLM, skipping patch")
return
print(f"[detect_head_size] head_size {head_size} is NOT in default supported list: {DEFAULT_SUPPORTED_HEAD_SIZES}")
print(f"[detect_head_size] Attempting to patch vLLM...")
# 执行patch
success = patch_vllm_head_sizes(head_size)
if success:
print(f"[detect_head_size] Successfully patched vLLM to support head_size {head_size}")
else:
print(f"[detect_head_size] Failed to patch vLLM for head_size {head_size}")
except Exception as e:
print(f"[detect_head_size] Error during head_size detection/patch: {e}")
print(f"[detect_head_size] Continuing with vLLM startup anyway...")
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"[detect_head_size] Unexpected error: {e}")
print(f"[detect_head_size] This will not prevent vLLM from starting")
import sys
sys.exit(0) # 总是成功退出不阻止vLLM启动