diff --git a/.gitignore b/.gitignore index 63408699f4..9b69e2eb4c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist .vscode tmp/ requirements-musa.txt +logs/ \ No newline at end of file diff --git a/docs/CN/source/tutorial/api_server_args.rst b/docs/CN/source/tutorial/api_server_args.rst index 1472f0fc43..6d372fee27 100644 --- a/docs/CN/source/tutorial/api_server_args.rst +++ b/docs/CN/source/tutorial/api_server_args.rst @@ -27,7 +27,6 @@ APIServer 参数详解 - ``running_max_req_size`` 为 3 - ``batch_max_tokens`` 为 2048 (2k) - ``chunked_prefill_size`` 为 1024 (1k) - - ``mem_fraction`` 为 0.85 .. option:: --host diff --git a/docs/EN/source/tutorial/api_server_args.rst b/docs/EN/source/tutorial/api_server_args.rst index 66b01c2ffc..ab5143a476 100644 --- a/docs/EN/source/tutorial/api_server_args.rst +++ b/docs/EN/source/tutorial/api_server_args.rst @@ -27,7 +27,6 @@ Basic Configuration Parameters - ``running_max_req_size`` to 3 - ``batch_max_tokens`` to 2048 (2k) - ``chunked_prefill_size`` to 1024 (1k) - - ``mem_fraction`` to 0.85 .. option:: --host diff --git a/lightllm/common/basemodel/attention/nsa/flashmla_sparse.py b/lightllm/common/basemodel/attention/nsa/flashmla_sparse.py index 673b5896d8..c3456f4b7a 100644 --- a/lightllm/common/basemodel/attention/nsa/flashmla_sparse.py +++ b/lightllm/common/basemodel/attention/nsa/flashmla_sparse.py @@ -79,17 +79,17 @@ def _nsa_prefill_att( from sgl_kernel.flash_mla import flash_mla_sparse_fwd nsa_dict = att_control.nsa_prefill_dict - topk_indices = nsa_dict["topk_indices"] + topk_mem_indices = nsa_dict["topk_mem_indices"] softmax_scale = nsa_dict["softmax_scale"] kv_lora_rank = nsa_dict["kv_lora_rank"] - if topk_indices.ndim == 2: - topk_indices = topk_indices.unsqueeze(1) + if topk_mem_indices.ndim == 2: + topk_mem_indices = topk_mem_indices.unsqueeze(1) mla_out, _, _ = flash_mla_sparse_fwd( q=q, kv=kv, - indices=topk_indices, + indices=topk_mem_indices, sm_scale=softmax_scale, d_v=kv_lora_rank, ) diff --git a/lightllm/common/kv_cache_mem_manager/__init__.py b/lightllm/common/kv_cache_mem_manager/__init__.py index 2609cfb8ab..05544e149a 100644 --- a/lightllm/common/kv_cache_mem_manager/__init__.py +++ b/lightllm/common/kv_cache_mem_manager/__init__.py @@ -1,3 +1,4 @@ +from .allocator import KvCacheAllocator from .mem_manager import MemoryManager, ReadOnlyStaticsMemoryManager from .ppl_int8kv_mem_manager import PPLINT8KVMemoryManager from .ppl_int4kv_mem_manager import PPLINT4KVMemoryManager @@ -9,6 +10,7 @@ from .qwen3next_mem_manager import Qwen3NextMemManager __all__ = [ + "KvCacheAllocator", "MemoryManager", "ReadOnlyStaticsMemoryManager", "PPLINT4KVMemoryManager", diff --git a/lightllm/common/kv_cache_mem_manager/mem_manager.py b/lightllm/common/kv_cache_mem_manager/mem_manager.py index 0cc84db322..0454c86628 100755 --- a/lightllm/common/kv_cache_mem_manager/mem_manager.py +++ b/lightllm/common/kv_cache_mem_manager/mem_manager.py @@ -3,10 +3,11 @@ import torch import torch.distributed as dist import torch.multiprocessing as mp -from typing import List, Union, Tuple, Any +from typing import List, Tuple, Any, Union from lightllm.server.pd_io_struct import KVMoveTask from lightllm.utils.log_utils import init_logger from lightllm.server.router.dynamic_prompt.shared_arr import SharedInt +from .allocator import KvCacheAllocator from lightllm.utils.profile_max_tokens import get_available_gpu_memory, get_total_gpu_memory from lightllm.common.kv_trans_kernel.kv_trans import kv_trans from lightllm.utils.dist_utils import get_current_rank_in_node, get_node_world_size @@ -38,27 +39,8 @@ def __init__(self, size, dtype, head_num, head_dim, layer_num, always_copy=False # profile the max total token num if the size is None self.profile_size(mem_fraction) - self.mem_state = torch.arange( - 0, self.size, dtype=torch.int32, device="cpu", requires_grad=False, pin_memory=True - ) - self._mem_state_return = torch.arange( - 0, self.size * 3, dtype=torch.int32, device="cpu", requires_grad=False, pin_memory=True - ) - self._return_start = 0 - self.mark_start = 0 - self.mark_end = self.size - - self.can_use_mem_size = self.size - - # 用共享内存进行共享,router 模块读取进行精确的调度估计, nccl port 作为一个单机中单实列的标记。防止冲突。 - from lightllm.utils.envs_utils import get_unique_server_name + self.allocator = KvCacheAllocator(self.size) - rank_in_node = get_current_rank_in_node() - self.shared_can_use_token_num = SharedInt( - f"{get_unique_server_name()}_mem_manger_can_use_token_num_{rank_in_node}" - ) - - self.shared_can_use_token_num.set_value(self.can_use_mem_size) self._init_buffers( self.size, dtype, @@ -83,9 +65,10 @@ def profile_size(self, mem_fraction): if self.size is not None: return + torch.cuda.empty_cache() world_size = dist.get_world_size() - total_memory = get_total_gpu_memory() - available_memory = get_available_gpu_memory(world_size) - total_memory * (1 - mem_fraction) + + available_memory = get_available_gpu_memory(world_size) * mem_fraction cell_size = self.get_cell_size() self.size = int(available_memory * 1024 ** 3 / cell_size) if world_size > 1: @@ -338,57 +321,13 @@ def _free_buffers(self): self.kv_buffer = None def alloc(self, need_size) -> torch.Tensor: - if need_size > self.mark_end - self.mark_start: - logger.error(f"warn no enough cache need_size {need_size} left_size {self.can_use_mem_size}") - assert False, "error alloc state" - - start = self.mark_start - end = self.mark_start + need_size - self.mark_start += need_size - - self.can_use_mem_size -= need_size - self.shared_can_use_token_num.set_value(self.can_use_mem_size) - - # 利用缓冲区返回,避免异步情况下的内存竞争 - if self._return_start + need_size > self._mem_state_return.shape[0]: - self._return_start = 0 - ans = self._mem_state_return[self._return_start : self._return_start + need_size] - ans.copy_(self.mem_state[start:end]) - self._return_start += need_size - return ans - - def free(self, free_index: Union[torch.Tensor, List[int]]): - """_summary_ - - Args: - free_index (torch.Tensor): _description_ - """ + return self.allocator.alloc(need_size) - end = self.mark_start - start = self.mark_start - len(free_index) - assert start >= 0, f"error free state start: {self.mark_start} free len {len(free_index)}" - - if isinstance(free_index, list): - self.mem_state.numpy()[start:end] = free_index - else: - # 从 gpu 到 cpu 的拷贝操作是流内阻塞操作 - self.mem_state[start:end] = free_index - - self.mark_start -= len(free_index) - - self.can_use_mem_size += len(free_index) - self.shared_can_use_token_num.set_value(self.can_use_mem_size) - - if self.can_use_mem_size == len(self.mem_state): - logger.debug(f"freed all gpu mem size {self.can_use_mem_size}") - return + def free(self, free_index: Union[torch.Tensor, List[int]]) -> None: + self.allocator.free(free_index) def free_all(self): - self.can_use_mem_size = len(self.mem_state) - self.shared_can_use_token_num.set_value(self.can_use_mem_size) - self.mem_state.numpy()[:] = list(range(0, len(self.mem_state))) - self.mark_start = 0 - self.mark_end = len(self.mem_state) + self.allocator.free_all() def resize_mem(self, new_size): """ @@ -401,13 +340,8 @@ def resize_mem(self, new_size): layer_num = self.layer_num self.size = new_size - self.mem_state = torch.arange( - 0, self.size, dtype=torch.int32, device="cpu", requires_grad=False, pin_memory=True - ) - self.mark_start = 0 - self.mark_end = self.size - self.can_use_mem_size = self.size - self.shared_can_use_token_num.set_value(self.can_use_mem_size) + self.allocator.resize(new_size) + self.HOLD_TOKEN_MEMINDEX = self.size self._free_buffers() self._init_buffers(size, dtype, head_num, head_dim, layer_num) return diff --git a/lightllm/server/api_cli.py b/lightllm/server/api_cli.py index f33f58b86d..4a345000b0 100644 --- a/lightllm/server/api_cli.py +++ b/lightllm/server/api_cli.py @@ -145,7 +145,7 @@ def make_argument_parser() -> argparse.ArgumentParser: parser.add_argument( "--mem_fraction", type=float, - default=0.9, + default=0.8, help="""Memory usage ratio, default is 0.9, you can specify a smaller value if OOM occurs at runtime. If max_total_token_num is not specified, it will be calculated automatically based on this value.""", ) diff --git a/lightllm/server/api_openai.py b/lightllm/server/api_openai.py index c324df19c8..fe4f3b50b0 100644 --- a/lightllm/server/api_openai.py +++ b/lightllm/server/api_openai.py @@ -153,8 +153,13 @@ def _get_history_tool_calls_cnt(request: ChatCompletionRequest) -> int: return idx -def _get_reasoning_from_request(request: ChatCompletionRequest) -> bool: - """Judge whether the request needs reasoning""" +def _is_force_thinking_mode(request: ChatCompletionRequest) -> bool: + """Whether this request uses forced thinking / reasoning (parser + template).""" + from .build_prompt import tokenizer_supports_force_thinking + + if not tokenizer_supports_force_thinking(): + return False + reasoning_parser = get_env_start_args().reasoning_parser if not reasoning_parser: return False @@ -175,7 +180,7 @@ def _process_reasoning_stream( ) -> tuple[Optional[str], str]: """Process reasoning content in streaming response""" if index not in reasoning_parser_dict: - request_enable_reasoning = _get_reasoning_from_request(request) + request_enable_reasoning = _is_force_thinking_mode(request) reasoning_parser_dict[index] = ReasoningParser( get_env_start_args().reasoning_parser, request.stream_reasoning, @@ -376,7 +381,7 @@ async def chat_completions_impl(request: ChatCompletionRequest, raw_request: Req reasoning_text = None reasoning_parser = get_env_start_args().reasoning_parser if reasoning_parser: - request_enable_reasoning = _get_reasoning_from_request(request) + request_enable_reasoning = _is_force_thinking_mode(request) try: parser = ReasoningParser( model_type=reasoning_parser, diff --git a/lightllm/server/api_start.py b/lightllm/server/api_start.py index 8c6af128c8..e1182f2f77 100644 --- a/lightllm/server/api_start.py +++ b/lightllm/server/api_start.py @@ -127,15 +127,14 @@ def normal_or_p_d_start(args): # performance_mode 参数处理 if args.performance_mode == "personal": - args.running_max_req_size = 3 + args.running_max_req_size = 6 args.batch_max_tokens = 2048 args.chunked_prefill_size = 1024 - if args.mem_fraction > 0.82: - args.mem_fraction = 0.82 - args.graph_max_batch_size = 32 + args.embed_cache_storage_size = 0.8 + args.graph_max_batch_size = 6 logger.info( f"performance_mode is personal, set running_max_req_size to 3," - f"batch_max_tokens to 2048, chunked_prefill_size to 1024, mem_fraction to 0.82," + f"batch_max_tokens to 2048, chunked_prefill_size to 1024," f"graph_max_batch_size to 32" ) diff --git a/lightllm/server/build_prompt.py b/lightllm/server/build_prompt.py index 84044fccce..913cb67107 100644 --- a/lightllm/server/build_prompt.py +++ b/lightllm/server/build_prompt.py @@ -2,6 +2,7 @@ import json from lightllm.server.tokenizer import get_tokenizer from lightllm.utils.log_utils import init_logger +from functools import lru_cache logger = init_logger(__name__) @@ -45,6 +46,32 @@ def init_tokenizer(args): return +@lru_cache(maxsize=1) +def tokenizer_supports_force_thinking() -> bool: + """Whether this tokenizer supports thinking / reasoning.""" + + assert tokenizer is not None + + try: + ans = "thinking" in tokenizer.chat_template or "enable_thinking" in tokenizer.chat_template + logger.debug(f"chat_template: {tokenizer.chat_template}") + logger.info(f"tokenizer_supports_force_thinking : {ans}") + return ans + except: + pass + + try: + ans = "thinking" in tokenizer.tokenizer.chat_template or "enable_thinking" in tokenizer.tokenizer.chat_template + logger.debug(f"tokenizer.tokenizer.chat_template: {tokenizer.tokenizer.chat_template}") + logger.info(f"tokenizer_supports_force_thinking : {ans}") + return ans + except: + pass + + logger.info("tokenizer_supports_force_thinking : False") + return False + + def _normalize_tool_call_arguments(messages: list) -> None: # Convert tool_calls function.arguments from JSON string to dict for Jinja template compatibility # Qwen35's chat template expects arguments to be a dict (uses |items filter) @@ -94,6 +121,19 @@ async def build_prompt(request, tools) -> str: if request.chat_template_kwargs: kwargs.update(request.chat_template_kwargs) + # 修复一些parser类型是默认打开thinking,但是 tokenizer有时候不知道打开了thinking。导致 + # 构建的reasoning parser 和 tokenizer 的行为不对齐导致的问题。 + from .api_openai import _is_force_thinking_mode + + thinking = _is_force_thinking_mode(request) + + kwargs["thinking"] = thinking + kwargs["enable_thinking"] = thinking + + # TODO thinking 模式应该是3种,一种是强制思考,一种是强制不思考,一种是模型自己决定的自适应 + # 的思考模式。当前的代码只是实现了强制思考和强制不思考两种模式。后续要根据模型的情况,从tokenizer + # 上判断能支持的思考模式种类,再进行设置,才能具备更完备的处理。 + try: input_str = tokenizer.apply_chat_template(**kwargs, tokenize=False, add_generation_prompt=True, tools=tools) except BaseException as e: diff --git a/lightllm/server/core/objs/start_args_type.py b/lightllm/server/core/objs/start_args_type.py index 954daa50fe..ce613b1054 100644 --- a/lightllm/server/core/objs/start_args_type.py +++ b/lightllm/server/core/objs/start_args_type.py @@ -32,7 +32,7 @@ class StartArgs: tokenizer_mode: str = field(default="slow") load_way: str = field(default="HF") max_total_token_num: Optional[int] = field(default=None) - mem_fraction: float = field(default=0.9) + mem_fraction: float = field(default=0.8) batch_max_tokens: Optional[int] = field(default=None) eos_id: List[int] = field(default_factory=list) tool_call_parser: Optional[str] = field( diff --git a/lightllm/server/httpserver/manager.py b/lightllm/server/httpserver/manager.py index 4c049f77c0..d54de63f36 100644 --- a/lightllm/server/httpserver/manager.py +++ b/lightllm/server/httpserver/manager.py @@ -529,7 +529,7 @@ async def _encode( if self.args.detail_log: logger.debug( - f"req_id: {sampling_params.group_request_id} prompt: {prompt},\n" + f"req_id: {sampling_params.group_request_id} prompt: {prompt}\n" f"samplingparmas: {sampling_params.to_dict()}\n" f"token_ids: {prompt_ids}" ) diff --git a/lightllm/server/router/dynamic_prompt/linear_att_radix_cache.py b/lightllm/server/router/dynamic_prompt/linear_att_radix_cache.py index 73c6dba54d..c7408add39 100644 --- a/lightllm/server/router/dynamic_prompt/linear_att_radix_cache.py +++ b/lightllm/server/router/dynamic_prompt/linear_att_radix_cache.py @@ -568,8 +568,8 @@ def _print_helper(self, node: LinearAttPagedTreeNode, indent): def free_radix_cache_to_get_enough_token(self, need_token_num): assert self.mem_manager is not None - if need_token_num > self.mem_manager.can_use_mem_size: - need_evict_token_num = need_token_num - self.mem_manager.can_use_mem_size + if need_token_num > self.mem_manager.allocator.can_use_mem_size: + need_evict_token_num = need_token_num - self.mem_manager.allocator.can_use_mem_size release_mems = [] small_page_buffer_ids = [] diff --git a/lightllm/server/router/dynamic_prompt/radix_cache.py b/lightllm/server/router/dynamic_prompt/radix_cache.py index 88b099459b..21e26c5854 100644 --- a/lightllm/server/router/dynamic_prompt/radix_cache.py +++ b/lightllm/server/router/dynamic_prompt/radix_cache.py @@ -401,12 +401,6 @@ def merge_unreferenced_nodes(self): if merged_node: worklist.append(merged_node) - def assert_leafs_is_right(self): - for node in self.evict_tree_set: - if node.is_leaf() and node.ref_counter == 0: - a = node.token_mem_index_value.cuda() - assert (self.mem_manager.mem_state[a] == 1).sum().item() == len(a) - def clear_tree_nodes(self): """ 该函数只在测试时调用 @@ -497,8 +491,8 @@ def _print_helper(self, node: TreeNode, indent): def free_radix_cache_to_get_enough_token(self, need_token_num): assert self.mem_manager is not None - if need_token_num > self.mem_manager.can_use_mem_size: - need_evict_token_num = need_token_num - self.mem_manager.can_use_mem_size + if need_token_num > self.mem_manager.allocator.can_use_mem_size: + need_evict_token_num = need_token_num - self.mem_manager.allocator.can_use_mem_size release_mems = [] def release_mem(mem_index): diff --git a/lightllm/server/router/model_infer/infer_batch.py b/lightllm/server/router/model_infer/infer_batch.py index 3a27c082de..1a5d05784f 100644 --- a/lightllm/server/router/model_infer/infer_batch.py +++ b/lightllm/server/router/model_infer/infer_batch.py @@ -280,8 +280,8 @@ def _filter(self, finished_request_ids: List[int]): f"free a batch state:\n" f"radix refed token num {self.radix_cache.get_refed_tokens_num()}\n" f"radix hold token num {self.radix_cache.get_tree_total_tokens_num()}\n" - f"mem manager can alloc token num {self.req_manager.mem_manager.can_use_mem_size}\n" - f"mem manager total size {self.req_manager.mem_manager.size}" + f"mem manager can alloc token num {self.req_manager.mem_manager.allocator.can_use_mem_size}\n" + f"mem manager total size {self.req_manager.mem_manager.allocator.size}\n" ) return @@ -348,7 +348,7 @@ def get_can_alloc_token_num(self): radix_cache_unref_token_num = ( self.radix_cache.get_tree_total_tokens_num() - self.radix_cache.get_refed_tokens_num() ) - return self.req_manager.mem_manager.can_use_mem_size + radix_cache_unref_token_num + return self.req_manager.mem_manager.allocator.can_use_mem_size + radix_cache_unref_token_num def copy_linear_att_state_to_cache_buffer(self, b_req_idx: torch.Tensor, reqs: List["InferReq"]): """ diff --git a/lightllm/server/router/model_infer/mode_backend/continues_batch/pd_mode/decode_node_impl/decode_infer_rpyc.py b/lightllm/server/router/model_infer/mode_backend/continues_batch/pd_mode/decode_node_impl/decode_infer_rpyc.py index 696452b419..6d97714b8c 100644 --- a/lightllm/server/router/model_infer/mode_backend/continues_batch/pd_mode/decode_node_impl/decode_infer_rpyc.py +++ b/lightllm/server/router/model_infer/mode_backend/continues_batch/pd_mode/decode_node_impl/decode_infer_rpyc.py @@ -80,8 +80,8 @@ def _alloc_to_frozen_some_tokens(self, move_task: KVMoveTask): logger.debug( f"radix refed token num {self.backend.radix_cache.get_refed_tokens_num()}\n" f"radix hold token num {self.backend.radix_cache.get_tree_total_tokens_num()}\n" - f"mem manager can alloc token num {self.backend.model.mem_manager.can_use_mem_size}\n" - f"mem manager total size {self.backend.model.mem_manager.size}" + f"mem manager can alloc token num {self.backend.model.mem_manager.allocator.can_use_mem_size}\n" + f"mem manager total size {self.backend.model.mem_manager.allocator.size}\n" f"frozened token num {frozen_token_num}\n" f"estimated peak token num {estimated_peak_token_num}\n" ) diff --git a/skills/test_model/deepseekr1-base-tp/SKILL.md b/skills/test_model/deepseekr1-base-tp/SKILL.md new file mode 100644 index 0000000000..37be61db6d --- /dev/null +++ b/skills/test_model/deepseekr1-base-tp/SKILL.md @@ -0,0 +1,102 @@ +--- +name: test-model-deepseekr1-base-tp +description: >- + Runs LightLLM DeepSeek-R1 baseline TP gsm8k: single api_server with --tp 8 and + --batch_max_tokens only, no MTP draft, no --dp, no EP MoE (distinct from deepseekr1-mtp-tp + which adds MTP). GSM8K lm_eval on localhost port 8089. Requires a dedicated log directory, + api_server and eval logs under that tree, summary.txt as consolidated report, tokenizer + aligned with MODEL_DIR. Use for baseline R1 tensor-parallel accuracy runs without MTP/EP. +--- + +# DeepSeek-R1 **Base–TP**(无 MTP / 无 EP,`--tp 8`)本地 GSM8K 评测 + +**测试标识**:仅 **`--tp 8`** 与 **`--batch_max_tokens`** 等基础推理参数,**无** MTP、`--dp`、`--enable_ep_moe`。用于与 **MTP–TP**(含 MTP 草稿)、**MTP–EP**(EP MoE + TP+DP)等流程区分。 + +启动一组 `api_server`,待端口就绪后对同一服务执行一次 `lm_eval`(任务 **`gsm8k`**,`batch_size` **500**)。整轮产物须落在**同一日志目录**内归档日志与 **`summary.txt`**(见「日志目录」);具体操作见「启动说明」。 + +## 日志目录(含 `summary.txt`) + +- 每次评测先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开,便于区分管理。 +- **`api_server` 进程的标准输出/错误**须写入该目录下文件(示例同级命名 **`server_base_tp.log`**;也可按变体或日期分子目录,团队任选其一,保持可追溯)。 +- **`summary.txt` 固定放在该日志目录下**,写入本轮启动参数摘要、`lm_eval` 关键结果、失败原因或简要结论;**不再**把「最终总结」散落在当前工作目录或其它路径。 +- `lm_eval` 终端输出建议单独落盘(如 **`eval_gsm8k.log`**);**`summary.txt`** 仍承担**总览结论**角色。 + +## 启动说明 + +本节包含:启动前检查 → 启动服务的命令模板(可变项说明)→ 一条完整 server 命令 → 评测命令。 + +### 启动前检查 + +开跑前先确认资源可用;**不满足则先清理相关进程**,再启动服务与评测。 + +1. **显卡占用**:用 `nvidia-smi`(或与集群一致的占用查看方式)检查目标 GPU 是否被无关任务占满;若有冲突进程,结束后再启动本评测。 +2. **端口**:服务固定 **`8089`**(与下文 `lm_eval` 的 `base_url` 一致);用 `ss -tlnp`、`lsof -i :8089` 等确认**无进程监听**该端口;若已被占用,查出 PID 并结束占用进程后再启动。 + +### 启动服务的命令模板(可变项) + +下列命令中出现的可变项含义如下(其余为固定写法): + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮评测日志目录,建议**绝对路径**;执行前 `export LOG_DIR=…`。 | +| `MODEL_DIR` | 主模型目录,对应 `--model_dir`;与 `lm_eval` 的 `tokenizer` 必须一致。 | +| `server_*.log`、`eval_*.log` | 仅文件名示例,可按任务重命名。 | + +开跑前在同一 shell 中导出路径(将引号内整段替换为本机绝对路径;**勿写死下文未给出的机器路径**): + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈主模型目录,对应 --model_dir〉' +``` + +首次试跑可用的**默认 `MODEL_DIR`** 见「执行约定」;与当前环境不符时再改为用户提供的目录。 + +### 一条 server 启动命令(后台落盘) + +本条为 **Base–TP** 固定形态:**`LOADWORKER=18`**,**`--batch_max_tokens 6000`**,**`--tp 8`**,**`--port 8089`**,无 MTP / 无 `--dp` / 无 EP。以下为**可直接执行**的后台启动形式(已含 `nohup` 与日志重定向);若暂时不需落盘,可自行去掉 `nohup`、`>> … 2>&1 &` 并在前台调试。命令中 **`${MODEL_DIR}`、`${LOG_DIR}`** 须已由上文 `export` 赋值。 + +```bash +LOADWORKER=18 \ +nohup python -m lightllm.server.api_server \ + --batch_max_tokens 6000 \ + --model_dir "${MODEL_DIR}" --tp 8 --port 8089 \ + >> "${LOG_DIR}/server_base_tp.log" 2>&1 & +``` + +### 评测命令(服务就绪后执行一次) + +服务就绪后执行(本地回环走代理时用 `no_proxy` / `NO_PROXY` 排除本机)。**`model_args` 中 `tokenizer` 必须与本次 server 的 `--model_dir`(即 **`${MODEL_DIR}`**)为同一字符串路径**。以下为带日志落盘的**完整命令**(`--model_args` 使用双引号以便展开 **`${MODEL_DIR}`**): + +```bash +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=127.0.0.1,localhost,::1 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"deepseek-ai/DeepSeek-R1\", \"base_url\":\"http://localhost:8089/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- **`LOG_DIR`**:与启动服务一节相同;若仅调试不重定向,去掉 `\` 续行及最后的 `>> "${LOG_DIR}/eval_gsm8k.log" 2>&1` 即可在前台查看输出。 +- **`MODEL_DIR`**:须与 server 启动命令中的 `--model_dir` 一致;路径随环境变化时的默认试跑与向用户确认见「执行约定」。 +- 若环境需要,可同时设置 `NO_PROXY=127.0.0.1,localhost,::1`(或与团队约定一致的列表)。 + +## 执行约定(不要额外写“专用启动脚本”) + +**模型目录(随环境变化)**:`MODEL_DIR` 在不同机器上路径不同。**首轮试跑**可先用下列默认(与常见本地部署对应;若本机不存在则跳过默认、直接执行下一步「向用户确认」): + +```bash +export MODEL_DIR=/mtc/models/DeepSeek-R1 +``` + +若按默认路径 **export** 后仍无法启动服务,或日志中出现**明确的模型路径 / 权重加载 / 文件不存在**等错误,**不要反复盲试**:根据日志判断为路径问题时,**请用户提供**当前环境下实际的主模型目录,更新 `export MODEL_DIR=…` 后再执行(且保证 **`MODEL_DIR` 与 `lm_eval` 的 `tokenizer` 仍为同一路径**)。 + +1. **后台启动 server**:用 shell 后台或终端任务跑 `python -m lightllm.server.api_server ...`,**并将该进程输出重定向到本轮日志目录下的日志文件**(见上文「日志目录(含 summary.txt)」);排查问题时 **tail** 该文件,而不是依赖未落盘的终端缓冲。 +2. **不要用 health 接口** 判断就绪;改为探测 **端口 8089 是否处于 listen**(例如 `ss -tlnp` / `lsof -i :8089` 等,与系统一致即可)。 +3. **等待启动**:若端口未就绪,约 **每 20 秒** 查看一次**服务日志文件**,区分仍在启动还是已报错退出;报错则写入日志目录下的 **`summary.txt`**(或先写服务日志再在 `summary.txt` 引用)并停止,不要继续盲等。 +4. **维护 `summary.txt`**:位于**日志目录**;记录**本条使用的完整启动命令**(或等价摘要)、**端口检测结果**、**`lm_eval` 关键输出**;全部结束后在该文件内写**最终汇总**(是否成功、主要指标或失败原因)。可与用户口头摘要对照,但以日志目录中 **`summary.txt`** 为归档准绳。 +5. **全部完成后**:确认日志目录下的 **`summary.txt`** 已包含完整最终总结;原始 server / eval 日志保留在同目录(或子目录)中备查。 + +## 输出文件 + +- **`summary.txt`**:仅位于**本轮日志目录**,作为本次 **Base–TP** 评测的**最终总结**文档。 +- **服务与评测日志**:全部落在**同一日志目录**(建议按任务命名文件或分子目录),不得与未指定目录混写。 diff --git a/skills/test_model/deepseekr1-mtp-ep/SKILL.md b/skills/test_model/deepseekr1-mtp-ep/SKILL.md new file mode 100644 index 0000000000..dd6da77c3b --- /dev/null +++ b/skills/test_model/deepseekr1-mtp-ep/SKILL.md @@ -0,0 +1,149 @@ +--- +name: test-model-deepseekr1-mtp-ep +description: >- + Runs LightLLM DeepSeek-R1 EP MoE + MTP (EAGLE) server variants and GSM8K lm_eval + against localhost. Requires each full run to use a dedicated log directory: persist every + api_server process log under that tree (per-variant subdirectories recommended), + write the consolidated summary to summary.txt in that same log directory, and keep artifacts + separated from other test runs. Use when running DeepSeek-R1 MTP EP accuracy workflows + or when the user asks to run these four server configurations one-by-one with logged results. +--- + +# DeepSeek-R1 MTP + EP MoE 串行评测流程 + +按固定顺序依次启动四种 `api_server` 配置;每次待服务就绪后执行 `lm_eval`。整轮评测须落在**同一日志目录**内归档日志与最终结论(见「日志目录」);具体操作见「启动说明」。 + +## 日志目录(含 `summary.txt`) + +- 每次完整评测(四种变体串行)先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开,便于区分管理。 +- **所有 `api_server` 进程的标准输出/错误**须写入该目录下文件(建议每种变体单独子目录,如 `variant_01_baseline/`、`variant_02_tpsp_mix/`;或同级命名 `server_01_baseline.log` 等,团队任选其一,保持可追溯)。 +- **`summary.txt` 固定放在该日志目录下**,汇总整轮测试:各变体启动参数摘要、`lm_eval` 关键结果、失败原因与最终对比;**不再**把「最终总结」散落在当前工作目录或其它路径。 +- `lm_eval` 终端输出也要有单独的日志文件(如 `eval_gsm8k.log`),**`summary.txt`** 仍承担**总览结论**角色。 + +## 启动说明 + +本节包含:启动前检查 → 启动服务的命令模板(可变项说明)→ 四种完整 server 命令 → 评测命令。 + +### 启动前检查 + +开跑前先确认资源可用;**不满足则先清理相关进程,再进入后续变体**。 + +1. **显卡占用**:用 `nvidia-smi`(或与集群一致的占用查看方式)检查目标 GPU 是否被无关任务占满;若有冲突进程,结束后再启动本评测。 +2. **端口**:服务固定 **`8089`**;用 `ss -tlnp`、`lsof -i :8089` 等确认**无进程监听**该端口;若已被占用,查出 PID 并结束占用进程后再启动。 + +### 启动服务的命令模板(可变项) + +下列命令中出现的可变项含义如下(其余为固定写法): + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮评测日志目录,建议**绝对路径**;执行前 `export LOG_DIR=…`。 | +| `MODEL_DIR` | 主模型目录,对应 `--model_dir`;与 `lm_eval` 的 `tokenizer` 必须一致。 | +| `MTP_DRAFT_DIR` | MTP 草稿模型目录,对应 `--mtp_draft_model_dir`。 | +| `server_*.log`、`eval_*.log` | 仅文件名示例,可按变体重命名。 | + +开跑前在同一 shell 中导出三类路径(将引号内整段替换为本机绝对路径;**勿写死下文未给出的机器路径**): + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈主模型目录,对应 --model_dir〉' +export MTP_DRAFT_DIR='〈MTP 草稿目录,对应 --mtp_draft_model_dir〉' +``` + +首次试跑可用的**默认路径组合**见「执行约定」;与当前环境不符时再改为用户提供的目录。 + +### 四种 server 启动命令(按顺序逐个测) + +每条 **单独** 跑完「启动 → 等就绪 → 评测 → 写入日志目录下的日志 → 停服务」再进入下一条,不要并行多个 server。以下为**可直接执行**的后台启动形式(已含 `nohup` 与日志重定向);若暂时不需落盘,可自行去掉 `nohup`、`>> … 2>&1 &` 并在前台调试。命令中 **`${MODEL_DIR}`、`${MTP_DRAFT_DIR}`** 须已由上文 `export` 赋值。 + +#### 变体 1:基线(EP + MTP) + +```bash +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 \ +nohup python -m lightllm.server.api_server \ + --enable_ep_moe --model_dir "${MODEL_DIR}" --tp 8 --dp 8 --port 8089 \ + --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 \ + --max_req_total_len 56000 \ + --mtp_mode eagle_with_att --mtp_draft_model_dir "${MTP_DRAFT_DIR}" --mtp_step 2 \ + >> "${LOG_DIR}/server_01_baseline.log" 2>&1 & +``` + +#### 变体 2:`--enable_tpsp_mix_mode` + +```bash +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 \ +nohup python -m lightllm.server.api_server \ + --enable_ep_moe --model_dir "${MODEL_DIR}" --tp 8 --dp 8 --port 8089 \ + --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 \ + --max_req_total_len 56000 \ + --mtp_mode eagle_with_att --mtp_draft_model_dir "${MTP_DRAFT_DIR}" --mtp_step 2 \ + --enable_tpsp_mix_mode \ + >> "${LOG_DIR}/server_02_tpsp_mix.log" 2>&1 & +``` + +#### 变体 3:prefill / decode microbatch overlap + +```bash +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 \ +nohup python -m lightllm.server.api_server \ + --enable_ep_moe --model_dir "${MODEL_DIR}" --tp 8 --dp 8 --port 8089 \ + --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 \ + --max_req_total_len 56000 \ + --mtp_mode eagle_with_att --mtp_draft_model_dir "${MTP_DRAFT_DIR}" --mtp_step 2 \ + --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap \ + >> "${LOG_DIR}/server_03_overlap.log" 2>&1 & +``` + +#### 变体 4:overlap + `--enable_dp_prefill_balance` + +```bash +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 \ +nohup python -m lightllm.server.api_server \ + --enable_ep_moe --model_dir "${MODEL_DIR}" --tp 8 --dp 8 --port 8089 \ + --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 \ + --max_req_total_len 56000 \ + --mtp_mode eagle_with_att --mtp_draft_model_dir "${MTP_DRAFT_DIR}" --mtp_step 2 \ + --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap \ + --enable_dp_prefill_balance \ + >> "${LOG_DIR}/server_04_overlap_dp_balance.log" 2>&1 & +``` + +### 评测命令(每个变体各执行一次) + +服务就绪后执行(本地回环走代理时用 `no_proxy` / `NO_PROXY` 排除本机)。**`model_args` 中 `tokenizer` 必须与本次 server 的 `--model_dir`(即 **`${MODEL_DIR}`**)为同一字符串路径**。以下为带日志落盘的**完整命令**(`--model_args` 使用双引号以便展开 **`${MODEL_DIR}`**): + +```bash +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=127.0.0.1,localhost,::1 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"deepseek-ai/DeepSeek-R1\", \"base_url\":\"http://localhost:8089/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 32 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- **`LOG_DIR`**:与启动服务一节相同;若仅调试不重定向,去掉 `\` 续行及最后的 `>> "${LOG_DIR}/eval_gsm8k.log" 2>&1` 即可在前台查看输出。 +- **`MODEL_DIR`**:须与 server 启动命令中的 `--model_dir` 一致;路径随环境变化时的默认试跑与向用户确认见「执行约定」。 +- 若环境需要,可同时设置 `NO_PROXY=127.0.0.1,localhost,::1`(或与团队约定一致的列表)。 + +## 执行约定(不要额外写“专用启动脚本”) + +**模型与 MTP 目录(随环境变化)**:`MODEL_DIR`(主模型)、`MTP_DRAFT_DIR`(MTP 草稿)在不同机器上路径不同。**首轮试跑**可先用下列默认组合(与本文档常见部署对应;若本机不存在则跳过默认、直接执行下一步「向用户确认」): + +```bash +export MODEL_DIR=/mtc/models/DeepSeek-R1 +export MTP_DRAFT_DIR=/mtc/models/DeepSeek-R1-NextN +``` + +若按默认路径 **export** 后仍无法启动服务,或日志中出现**明确的模型路径 / 权重加载 / 文件不存在**等错误,**不要反复盲试**:根据日志判断为路径问题时,**请用户提供**当前环境下实际的主模型目录与 MTP 草稿目录,更新 `export MODEL_DIR=…`、`export MTP_DRAFT_DIR=…` 后再执行(且保证 **`MODEL_DIR` 与 `lm_eval` 的 `tokenizer` 仍为同一路径**)。 + +1. **后台启动 server**:用 shell 后台或终端任务跑当前变体的 `python -m lightllm.server.api_server ...`,**并将该进程输出重定向到本轮日志目录下的日志文件**(见上文「日志目录(含 summary.txt)」);排查问题时 tail 该文件,而不是依赖未落盘的终端缓冲。 +2. **不要用 health 接口** 判断就绪;改为探测 **端口 8089 是否处于 listen**(例如 `ss -tlnp` / `lsof -i :8089` 等,与系统一致即可)。 +3. **等待启动**:若端口未就绪,约 **每 20 秒** 查看一次**该变体对应的服务日志文件**,区分仍在启动还是已报错退出;报错则写入日志目录下的 `summary.txt`(或先写变体日志再在该汇总文件中引用)并停止该变体,不要继续盲等。 +4. **维护 `summary.txt`**:位于**日志目录**;随进度追加每个变体的标记块——**本条使用的完整启动命令**(或等价摘要)、**端口检测结果**、**lm_eval 关键输出**;全部结束后在该文件内写**最终汇总**(各配置成败、指标对比或失败原因)。可与用户口头摘要对照,但以日志目录中 **`summary.txt`** 为归档准绳。 +5. **变体之间**:停止上一进程的 server,再启动下一变体(避免端口占用)。 +6. **全部完成后**:确认日志目录下的 **`summary.txt`** 已包含完整最终总结;原始 server / eval 日志保留在同目录(或子目录)中备查。 + +## 输出文件 + +- **`summary.txt`**:仅位于**本轮日志目录**,作为整次四变体测试的**最终总结**文档。 +- **服务与评测日志**:全部落在**同一日志目录**(建议按变体分子目录或分文件名),不得与未指定目录混写。 diff --git a/skills/test_model/deepseekr1-mtp-tp/SKILL.md b/skills/test_model/deepseekr1-mtp-tp/SKILL.md new file mode 100644 index 0000000000..275d9316a6 --- /dev/null +++ b/skills/test_model/deepseekr1-mtp-tp/SKILL.md @@ -0,0 +1,104 @@ +--- +name: test-model-deepseekr1-mtp-tp +description: >- + DeepSeek-R1 MTP-TP test: LightLLM api_server with MTP (EAGLE) draft, tensor parallel + only (--tp 8, no --dp, no EP MoE), plus GSM8K lm_eval on localhost. Distinct from the + MTP-EP-TPDP skill which uses --tp 8 --dp 8 and EP MoE. Requires a dedicated log directory, + summary.txt, tokenizer aligned with MODEL_DIR. Use for TP-only MTP gsm8k accuracy runs. +--- + +# DeepSeek-R1 **MTP–TP**(仅张量并行 `--tp 8`,无 DP / 无 EP)本地 GSM8K 评测 + +**测试标识**:并行方式为 **`--tp 8` 单路 TP**,不包含 **`--dp`** 与 **`--enable_ep_moe`**。用于与 **MTP–EP–TPDP**(`--tp 8 --dp 8` + EP MoE)流水线区分。 + +启动一组 `api_server`(`eagle_with_att` MTP),待就绪后对同一进程执行一次 `lm_eval`(任务 `gsm8k`)。全过程产物落在**同一日志目录**(见「日志目录」);命令与流程见「启动说明」。 + +## 日志目录(含 `summary.txt`) + +- 先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开。 +- **`api_server` 的标准输出/错误**写入该目录下文件(示例文件名 `server_mtp_tp.log`;可按团队习惯改名或分子目录)。 +- **`summary.txt` 固定放在该日志目录下**,写入本轮启动参数摘要、`lm_eval` 关键结果与简要结论。 +- `lm_eval` 终端输出建议单独落盘(如 `eval_gsm8k.log`);**`summary.txt`** 仍为整次任务的**总览结论**。 + +## 启动说明 + +本节包含:启动前检查 → 启动服务的命令模板(可变项说明)→ 一条完整 server 命令 → 评测命令。 + +### 启动前检查 + +开跑前先确认资源可用;**不满足则先清理相关进程**。 + +1. **显卡占用**:用 `nvidia-smi`(或与集群一致的占用查看方式)检查目标 GPU 是否被无关任务占满;若有冲突进程,结束后再启动本评测。 +2. **端口**:服务固定 **`8089`**;用 `ss -tlnp`、`lsof -i :8089` 等确认**无进程监听**该端口;若已被占用,查出 PID 并结束占用进程后再启动。 + +### 启动服务的命令模板(可变项) + +下列符号与 EP–TPDP 版评测共用含义: + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮评测日志目录,建议**绝对路径**;执行前 `export LOG_DIR=…`。 | +| `MODEL_DIR` | 主模型目录,对应 `--model_dir`;与 `lm_eval` 的 `tokenizer` 必须一致。 | +| `MTP_DRAFT_DIR` | MTP 草稿模型目录,对应 `--mtp_draft_model_dir`。 | + +开跑前在同一 shell 中导出路径(引号内替换为本机绝对路径): + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈主模型目录,对应 --model_dir〉' +export MTP_DRAFT_DIR='〈MTP 草稿目录,对应 --mtp_draft_model_dir〉' +``` + +首次试跑可用的**默认路径组合**见「执行约定」。 + +### 一条 server 启动命令(后台落盘) + +以下为 **MTP–TP** 固定形态:**`--tp 8`**,**无 `--dp`**。可直接执行的后台形式(已含 `nohup` 与日志重定向);调试时可去掉 `nohup` 与 `>> … 2>&1 &` 改前台。**`${MODEL_DIR}`、`${MTP_DRAFT_DIR}`、`${LOG_DIR}`** 须已由上文 `export` 赋值。 + +```bash +LOADWORKER=18 \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" --tp 8 --port 8089 \ + --mem_fraction 0.75 --batch_max_tokens 6000 \ + --mtp_mode eagle_with_att --mtp_draft_model_dir "${MTP_DRAFT_DIR}" --mtp_step 2 \ + >> "${LOG_DIR}/server_mtp_tp.log" 2>&1 & +``` + +### 评测命令(服务就绪后执行一次) + +本地回环需排除代理:`no_proxy` / `NO_PROXY`。**`tokenizer` 与 `--model_dir`(`${MODEL_DIR}`)须为同一路径**。以下为带日志落盘的**完整命令**: + +```bash +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=127.0.0.1,localhost,::1 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"deepseek-ai/DeepSeek-R1\", \"base_url\":\"http://localhost:8089/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- **`LOG_DIR`**:与 server 一节一致;若仅调试不重定向,可去掉末尾 `>> "${LOG_DIR}/eval_gsm8k.log" 2>&1`。 +- **`MODEL_DIR`**:与 server 的 `--model_dir` 一致;默认试跑与用户确认路径见「执行约定」。 +- 若环境需要,可同时设置 `NO_PROXY=127.0.0.1,localhost,::1`。 + +## 执行约定(不要额外写“专用启动脚本”) + +**模型与 MTP 目录(随环境变化)**:`MODEL_DIR`、`MTP_DRAFT_DIR` 在不同机器上路径不同。**首轮试跑**可先使用: + +```bash +export MODEL_DIR=/mtc/models/DeepSeek-R1 +export MTP_DRAFT_DIR=/mtc/models/DeepSeek-R1-NextN +``` + +若默认路径不存在或服务报错指向路径/权重加载失败,**请用户提供**本机实际目录并更新两个 `export`;**保持 `MODEL_DIR` 与 `lm_eval` 中 `tokenizer` 一致**。 + +1. **后台启动 server**:将 `api_server` 输出重定向到日志目录下文件(见「日志目录」);排查时用 `tail` 查看该日志。 +2. **不要用 health 接口** 判断就绪;改为探测 **端口 8089 是否 listen**(例如 `ss -tlnp` / `lsof -i :8089`)。 +3. **等待启动**:端口未就绪时约 **每 20 秒** 查看服务日志,区分仍在启动或已报错;路径类错误按上文向用户确认目录。 +4. **维护 `summary.txt`**:记录完整启动命令摘要(须能看出 **`--tp 8`、无 `--dp`**)、端口检测结果、`lm_eval` 关键输出与最终结论。 +5. **全部完成后**:确认 **`summary.txt`** 完整;server / eval 原始日志保留在同一日志目录备查。 + +## 输出文件 + +- **`summary.txt`**:位于**本轮日志目录**,作为本次 **MTP–TP** 评测的**最终总结**。 +- **服务与评测日志**:与 **`summary.txt`** 落在**同一日志目录**。 diff --git a/skills/test_model/deepseekv32-ep/SKILL.md b/skills/test_model/deepseekv32-ep/SKILL.md new file mode 100644 index 0000000000..63fe3aed77 --- /dev/null +++ b/skills/test_model/deepseekv32-ep/SKILL.md @@ -0,0 +1,118 @@ +--- +name: test-model-deepseekv32-ep +description: >- + Runs LightLLM DeepSeek-V3.2 EP MoE gsm8k: api_server with --tp 8 --dp 8 --enable_ep_moe, + tool_call_parser deepseekv32, reasoning_parser deepseek-v3, graph_max_batch_size 32, + mem_fraction 0.8, LOADWORKER 14, port 8000 aligned with lm_eval base_url. Requires a + dedicated log directory, api_server and eval logs, summary.txt consolidated report, + tokenizer aligned with MODEL_DIR. Distinct from R1 MTP/Base flows. Use for V3.2 EP MoE + gsm8k accuracy on LightLLM. +--- + +# DeepSeek-V3.2 **EP**(`--tp 8`、`--dp 8`、`--enable_ep_moe`)本地 GSM8K 评测 + +**测试标识**:本流程针对 **DeepSeek-V3.2**,启用 **EP MoE**(**`--enable_ep_moe`**)与 **TP+DP**(**`--tp 8 --dp 8`**),并包含 **`tool_call_parser deepseekv32`**、**`reasoning_parser deepseek-v3`**、**`graph_max_batch_size 32`**、**`mem_fraction 0.8`** 等与推理栈相关的参数。与 **Base–R1**、**MTP–TP / MTP–EP**(R1 系列)区分。 + +**监听端口**:`api_server` 与 `lm_eval` 的 **`base_url` 必须使用同一端口**;本流程固定为 **`8000`**(下文 server 命令含 **`--port 8000`**,评测 URL 为 `http://localhost:8000/v1/completions`)。 + +启动一组 `api_server`,待端口就绪后执行一次 `lm_eval`(任务 **`gsm8k`**,`batch_size` **500**)。整轮产物须落在**同一日志目录**内归档日志与 **`summary.txt`**(见「日志目录」);具体操作见「启动说明」。 + +## 日志目录(含 `summary.txt`) + +- 每次评测先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开,便于区分管理。 +- **所有 `api_server` 进程的标准输出/错误**须写入该目录下文件(示例同级命名 **`server_v32_ep.log`**;也可分子目录,团队任选其一,保持可追溯)。 +- **`summary.txt` 固定放在该日志目录下**,写入本轮启动参数摘要、`lm_eval` 关键结果、失败原因或简要对比;**不再**把「最终总结」散落在当前工作目录或其它路径。 +- `lm_eval` 终端输出也要有单独的日志文件(如 **`eval_gsm8k.log`**);**`summary.txt`** 仍承担**总览结论**角色。 + +## 启动说明 + +本节包含:启动前检查 → 启动服务的命令模板(可变项说明)→ 一条完整 server 命令 → 评测命令。 + +### 启动前检查 + +开跑前先确认资源可用;**不满足则先清理相关进程**,再启动服务与评测。 + +1. **显卡占用**:用 `nvidia-smi`(或与集群一致的占用查看方式)检查目标 GPU 是否被无关任务占满;若有冲突进程,结束后再启动本评测(本配置为 **TP+DP**,需足够 GPU 资源)。 +2. **端口**:服务固定 **`8000`**(与下文 `lm_eval` 的 `base_url` 端口一致);用 `ss -tlnp`、`lsof -i :8000` 等确认**无进程监听**该端口;若已被占用,查出 PID 并结束占用进程后再启动。 + +### 启动服务的命令模板(可变项) + +下列命令中出现的可变项含义如下(其余为固定写法): + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮评测日志目录,建议**绝对路径**;执行前 `export LOG_DIR=…`。 | +| `MODEL_DIR` | 主模型目录,对应 `--model_dir`;与 `lm_eval` 的 `tokenizer` 必须一致。 | +| `server_*.log`、`eval_*.log` | 仅文件名示例,可按任务重命名。 | + +开跑前在同一 shell 中导出路径(将引号内整段替换为本机绝对路径;**勿写死下文未给出的机器路径**): + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈主模型目录,对应 --model_dir〉' +``` + +首次试跑可用的**默认 `MODEL_DIR`** 见「执行约定」;与当前环境不符时再改为用户提供的目录。 + +### 一条 server 启动命令(后台落盘) + +本条为 **DeepSeek-V3.2 EP** 固定形态:**`LOADWORKER=14`**,**`--tp 8 --dp 8 --enable_ep_moe`**,**`--port 8000`**,以及 **`tool_call_parser` / `reasoning_parser` / `graph_max_batch_size` / `mem_fraction`** 等与脚本一致的参数。以下为**可直接执行**的后台启动形式(已含 `nohup` 与日志重定向);若暂时不需落盘,可自行去掉 `nohup`、`>> … 2>&1 &` 并在前台调试。命令中 **`${MODEL_DIR}`、`${LOG_DIR}`** 须已由上文 `export` 赋值。 + +```bash +LOADWORKER=14 \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" --tp 8 \ + --graph_max_batch_size 32 \ + --tool_call_parser deepseekv32 \ + --mem_fraction 0.6 \ + --reasoning_parser deepseek-v3 \ + --dp 8 --enable_ep_moe \ + --port 8000 \ + >> "${LOG_DIR}/server_v32_ep.log" 2>&1 & +``` + +### 评测命令(服务就绪后执行一次) + +服务就绪后执行(本地回环走代理时用 `no_proxy` / `NO_PROXY` 排除本机)。**`model_args` 中 `tokenizer` 必须与本次 server 的 `--model_dir`(即 **`${MODEL_DIR}`**)为同一字符串路径**。**`base_url` 中的端口须为 `8000`,与 `api_server` 的 `--port` 一致。** 以下为带日志落盘的**完整命令**(`--model_args` 使用双引号以便展开 **`${MODEL_DIR}`**): + +```bash +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=127.0.0.1,localhost,::1 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"deepseek-ai/DeepSeek-V3.2\", \"base_url\":\"http://localhost:8000/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- **`LOG_DIR`**:与启动服务一节相同;若仅调试不重定向,去掉 `\` 续行及最后的 `>> "${LOG_DIR}/eval_gsm8k.log" 2>&1` 即可在前台查看输出。 +- **`MODEL_DIR`**:须与 server 启动命令中的 `--model_dir` 一致;路径随环境变化时的默认试跑与向用户确认见「执行约定」。 +- 若环境需要,可同时设置 `NO_PROXY=127.0.0.1,localhost,::1`(或与团队约定一致的列表)。 + +## 执行约定(不要额外写“专用启动脚本”) + +**模型目录(随环境变化)**:`MODEL_DIR` 在不同机器上路径不同。**首轮试跑**可先用下列默认(与本文档常见部署对应;若本机不存在则跳过默认、直接执行下一步「向用户确认」): + +```bash +export MODEL_DIR=/mtc/models/DeepSeek-V3.2 +``` + +若按默认路径 **export** 后仍无法启动服务,或日志中出现**明确的模型路径 / 权重加载 / 文件不存在**等错误,**不要反复盲试**:根据日志判断为路径问题时,**请用户提供**当前环境下实际的主模型目录,更新 `export MODEL_DIR=…` 后再执行(且保证 **`MODEL_DIR` 与 `lm_eval` 的 `tokenizer` 仍为同一路径**)。 + +1. **后台启动 server**:用 shell 后台或终端任务跑 `python -m lightllm.server.api_server ...`,**并将该进程输出重定向到本轮日志目录下的日志文件**(见上文「日志目录(含 summary.txt)」);排查问题时 **tail** 该文件,而不是依赖未落盘的终端缓冲。 +2. **不要用 health 接口** 判断就绪;改为探测 **端口 8000 是否处于 listen**(例如 `ss -tlnp` / `lsof -i :8000` 等,与系统一致即可)。 +3. **等待启动**:若端口未就绪,约 **每 20 秒** 查看一次**服务日志文件**,区分仍在启动还是已报错退出;报错则写入日志目录下的 **`summary.txt`**(或先写服务日志再在 `summary.txt` 引用)并停止,不要继续盲等。 +4. **维护 `summary.txt`**:位于**日志目录**;记录**本条使用的完整启动命令**(须能看出 **`--tp 8`、`--dp 8`、EP MoE**)、**端口检测结果**、**`lm_eval` 关键输出**;全部结束后在该文件内写**最终汇总**(是否成功、主要指标或失败原因)。可与用户口头摘要对照,但以日志目录中 **`summary.txt`** 为归档准绳。 +5. **全部完成后**:确认日志目录下的 **`summary.txt`** 已包含完整最终总结;原始 server / eval 日志保留在同目录(或子目录)中备查。 + +### 服务启动 OK 判定经验(本流程补充) + +- **不要只看“主进程在不在”**:`python -m lightllm.server.api_server` 进程存活不代表可用;必须至少满足“`8000` 已 listen”再进入评测。 +- **长时间加载不等于失败**:DeepSeek-V3.2 EP 首次加载可能持续数分钟。若日志持续出现 `Loading model weights ...` 进度推进,视为“仍在启动”,继续按 20 秒间隔观察。 +- **判定“启动 OK”建议三要素**:① `8000` 端口监听;② 服务日志无新的 `OutOfMemoryError`/Traceback;③ 用一条最小请求(如 1 条 completions/chat 请求)拿到 200 或有效响应,再跑 `lm_eval`。 +- **出现 OOM 要先清残留再重试**:一旦日志出现 `torch.OutOfMemoryError`,先结束该轮 `api_server` 及其派生进程(含 `hypercorn`/`lightllm::...` 子进程),确认 `8000` 释放后再重启,避免“旧进程占资源导致假失败”。 +- **重试优先调启动参数而非盲等**:若 OOM 发生在权重加载阶段,优先降低加载/显存压力(例如使用更保守的 `mem_fraction`),并在 `summary.txt` 记录“失败参数 -> 重试参数 -> 结果”。 + +## 输出文件 + +- **`summary.txt`**:仅位于**本轮日志目录**,作为本次 **DeepSeek-V3.2 EP** 评测的**最终总结**文档。 +- **服务与评测日志**:全部落在**同一日志目录**(建议按任务命名文件或分子目录),不得与未指定目录混写。 diff --git a/skills/test_model/qwen2.5-14b-fp8kv-gsm8k/SKILL.md b/skills/test_model/qwen2.5-14b-fp8kv-gsm8k/SKILL.md new file mode 100644 index 0000000000..6c932e43e2 --- /dev/null +++ b/skills/test_model/qwen2.5-14b-fp8kv-gsm8k/SKILL.md @@ -0,0 +1,137 @@ +--- +name: test-model-qwen2.5-14b-fp8kv-gsm8k +description: >- + LightLLM Qwen2.5-14B-Instruct GSM8K with FP8 KV cache quantization: either fp8kv_sph + (per-head calibration JSON) or fp8kv_spt (per-tensor calibration JSON). Single api_server + tp 2 fixed HTTP port 8089 (not configurable), lm_eval local-completions. Assign GPUs via nvidia-smi then export + CUDA_VISIBLE_DEVICES. Before starting api_server, cwd must be LightLLM repo root; pass + --kv_quant_calibration_config_path as the repo-relative path from the table row that matches + --llm_kv_type (fp8kv_sph with per-head JSON only; fp8kv_spt with per-tensor JSON only; no absolute path, + no REPO_ROOT/CALIB_JSON shell concatenation). If default MODEL_DIR path is missing or + load fails with path errors, ask the user for the correct MODEL_DIR. LOG_DIR, + summary.txt, port listen checks (not health), no_proxy, background server with log redirect. + Two variants documented in one skill. +--- + +# Qwen2.5-14B-Instruct **FP8 KV Cache(`fp8kv_sph` / `fp8kv_spt`)** GSM8K 评测 + +**测试标识**:同一 **`Qwen2.5-14B-Instruct`** 权重下,用 **`api_server`** 跑 **单机 TP=2**;通过 **`--llm_kv_type`** 区分两种 **FP8 KV 量化形态**,每种形态对应 **不同的标定 JSON**(**per-head** vs **per-tensor**)。**每一轮只选其中一种形态**跑通:先起服务,再 **`lm_eval`**。 + +| 形态 | `--llm_kv_type` | 标定配置(相对 LightLLM 仓库根目录) | +|------|-----------------|--------------------------------------| +| **SPH**(per-head) | **`fp8kv_sph`** | **`test/advanced_config/fp8_calibration_per_head/test_kv_cache_calib_per_head_qwen2.5_14b.json`** | +| **SPT**(per-tensor) | **`fp8kv_spt`** | **`test/advanced_config/fp8_calibration_per_tensor/test_kv_cache_calib_per_tensor_qwen2.5_14b.json`** | + +**配对规则(必守)**:**`--llm_kv_type` 与 `--kv_quant_calibration_config_path` 必须取自上表同一行**。 **`fp8kv_sph` 只能** 搭配 **per_head** 标定 JSON;**`fp8kv_spt` 只能** 搭配 **per_tensor** 标定 JSON。只改其一会导致启动或运行时报错。**不要**在命令里写 **`--llm_kv_type "${LLM_KV_TYPE}"`** 却**固定**另一条 `--kv_quant_calibration_config_path`(二者会漂移);应像下文 **按形态分块**:每一块内两条参数**字面一致、成对出现**。 + +**端口**:**固定 `8089`**,**不可改**(与脚本一致;**`--port`** 与 **`lm_eval` 的 `base_url`** 均须为 **`8089`**)。**`--tp 2`** 需要 **2 张 GPU**。 + +整轮产物落在**同一日志目录**:**`summary.txt`**、**`server.log`**、**`eval_gsm8k.log`**;**不要**写复杂聚合启动脚本,按下面块**手动**或复制为独立命令执行。 + +## 日志目录(含 `summary.txt`) + +- 每次评测新建或选定 **`LOG_DIR`**(建议带任务名与时间戳,例如 `…/qwen25_fp8kv_sph_〈时间〉` 与 `…/qwen25_fp8kv_spt_〈时间〉` **分开**,便于对比两种形态)。 +- **`api_server`** 标准输出/错误 → **`"${LOG_DIR}/server.log"`**(后台 **`nohup … >> … 2>&1 &`**)。 +- **`lm_eval`** → **`"${LOG_DIR}/eval_gsm8k.log"`**。 +- **`summary.txt`**:本轮 **`--llm_kv_type`(`fp8kv_sph` / `fp8kv_spt`)**、启动命令摘要、端口检测结果、**`lm_eval` 要点**、失败原因与结论。 + +## 启动前检查 + +1. **显卡**:**`--tp 2`**,需 **2 张物理 GPU**。**不要写死卡号**:先 **`nvidia-smi`**,再 **`export CUDA_VISIBLE_DEVICES='i,j'`**。 +2. **端口**:**`8089`** 未被占用(**`ss -tlnp`** / **`lsof -i :8089`**)。 +3. **标定文件与 KV 形态**:**`--kv_quant_calibration_config_path`** 须为 **与本轮 `--llm_kv_type` 上表同一行** 的相对路径(**不要**写成磁盘绝对路径;**不要** `fp8kv_sph` 配 per_tensor 或 `fp8kv_spt` 配 per_head)。启动 **`python -m lightllm.server.api_server` 时,shell 当前目录须已是仓库根**(先由 Agent **`cd` 到检出根** 再执行 `nohup`;或在一行里 **`cd '…根…' && nohup python …`**)。确认 `os.path.exists` 意义下该相对路径可读。**禁止** `export CALIB_JSON="${REPO_ROOT}/…"` 这类环境变量拼接。 +4. **模型目录 `MODEL_DIR`**:启动前确认路径存在(例如 **`test -d "${MODEL_DIR}"`**)且内含权重;默认可用 **`/mtc/models/Qwen2.5-14B-Instruct`**。若默认不存在、或服务 / 日志出现 **找不到模型目录、权重文件缺失、路径类加载失败** 等,**不要盲换路径重试**:**向用户询问**本机正确的 **`MODEL_DIR` 绝对路径**,待用户回复后更新 **`export MODEL_DIR=…`**,并在 **`summary.txt`** 中记录最终采用的路径;**`--model_dir` 与 `lm_eval` 的 `tokenizer` 必须始终为同一字符串**。 +5. **代理**:启动 server 前 **`export http_proxy=`**、**`export https_proxy=`**;评测时设置 **`no_proxy`**(见评测命令)。 + +## 可变项 + +| 变量 | 含义 | +|------|------| +| `LOG_DIR` | 本轮日志目录(绝对路径)。 | +| `MODEL_DIR` | **`--model_dir`** 与 **`lm_eval` 的 `tokenizer`**,须为**同一路径**。默认试跑 **`/mtc/models/Qwen2.5-14B-Instruct`**;**不可用或报错时向用户询问**正确目录后再 `export`(见「执行约定」与启动前检查第 4 条)。 | +| `LLM_KV_TYPE` | 即 **`--llm_kv_type`**:**`fp8kv_sph`**(上表 **SPH / per-head**)或 **`fp8kv_spt`**(上表 **SPT / per-tensor**);本轮只选其一;**须与下一行的标定文件同表同行成对**。 | +| 标定 JSON(**相对仓库根**) | **`--kv_quant_calibration_config_path`**:仅允许为上表中 **与当前 `LLM_KV_TYPE` 同一行** 的那一个相对路径;依赖 **`cd` 到仓库根** 后的 cwd,**不要**写绝对路径,勿用 **`${REPO_ROOT}/…`** 拼接;**禁止**与 **`--llm_kv_type` 交叉混用**(见上文配对规则)。 | +| `CUDA_VISIBLE_DEVICES` | 两张卡,**`nvidia-smi` 后 export**。 | + +**标定路径写法**:**`--kv_quant_calibration_config_path`** 里 **只写相对路径**,且 **必须是上表与本轮 `--llm_kv_type` 同一行的那一个**。由 Agent 保证 **`nohup` 所在进程的工作目录为 LightLLM 根**(先 `cd` 再启动,或与 `nohup` 写在同一行的 `cd … &&`)。 + +## 启动服务(后台 + 日志) + +**不要用 health 接口**判断就绪;以 **端口 listen**(**`8089`**)结合 **`server.log`** 为准;约 **每 20 秒**看日志直至就绪或报错。 + +以下为 **两种成对配置**,**每次整段复制其一**;**不要**混用「变量展开的 `--llm_kv_type` + 写死的标定路径」以免与上表不一致。 + +### 形态 A:**SPH**(`fp8kv_sph` + per-head 标定) + +```bash +export http_proxy= +export https_proxy= + +export LOG_DIR='〈本轮日志目录〉' +export MODEL_DIR='/mtc/models/Qwen2.5-14B-Instruct' + +# 〈LightLLM 仓库根〉由 Agent 改为本机检出目录的绝对路径,仅用于 cd +cd '〈LightLLM 仓库根〉' + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 \ + --llm_kv_type fp8kv_sph \ + --kv_quant_calibration_config_path test/advanced_config/fp8_calibration_per_head/test_kv_cache_calib_per_head_qwen2.5_14b.json \ + >> "${LOG_DIR}/server.log" 2>&1 & +``` + +### 形态 B:**SPT**(`fp8kv_spt` + per-tensor 标定) + +```bash +export http_proxy= +export https_proxy= + +export LOG_DIR='〈本轮日志目录〉' +export MODEL_DIR='/mtc/models/Qwen2.5-14B-Instruct' + +cd '〈LightLLM 仓库根〉' + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 \ + --llm_kv_type fp8kv_spt \ + --kv_quant_calibration_config_path test/advanced_config/fp8_calibration_per_tensor/test_kv_cache_calib_per_tensor_qwen2.5_14b.json \ + >> "${LOG_DIR}/server.log" 2>&1 & +``` + +(**`--kv_quant_calibration_config_path`** 均为 **相对仓库根**;**不要**写成绝对路径。) + +- **`lm_eval` 的 `base_url`**:本 skill 约定 **`http://127.0.0.1:8089/v1/completions`**(**端口固定**,评测与 **`no_proxy`** 均按 **`127.0.0.1`**);**`api_server` 须 `--port 8089`**(默认不显式 **`--host`** 时一般为 `0.0.0.0`,本机访问用 **`127.0.0.1`** 即可)。 + +## 评测命令(服务就绪后) + +**`tokenizer` 与 `MODEL_DIR` 对齐**(与其它 test_model skill 一致): + +```bash +export http_proxy= +export https_proxy= + +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=localhost,127.0.0.1,0.0.0.0,::1 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"Qwen/Qwen2.5-14B-Instruct\", \"base_url\":\"http://127.0.0.1:8089/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 64 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +## 执行约定 + +### 模型目录(`MODEL_DIR`) + +- 不同机器上路径不同。**首轮**可 **`export MODEL_DIR=/mtc/models/Qwen2.5-14B-Instruct`**(与命令模板一致)。 +- **在启动 `api_server` 之前**:若该路径**不存在**,或启动后日志明确为 **模型路径 / 权重 / 文件不存在** 等问题,**停止盲试**,**向用户询问**当前环境下 **Qwen2.5-14B-Instruct** 的实际目录绝对路径;用户给出后更新 **`export MODEL_DIR='…用户提供的绝对路径…'`**,并保证后续 **`--model_dir`** 与 **`lm_eval` 的 `tokenizer`** 使用该同一变量;将最终采用的 **`MODEL_DIR`** 写入 **`summary.txt`**。 + +1. **两种形态分两轮测**:先完整跑 **形态 A(SPH)**(含 **`summary.txt`**),再换 **`LOG_DIR`** 并完整使用 **形态 B(SPT)** 启动块(**`--llm_kv_type fp8kv_spt` 与 per-tensor 标定路径须同时来自上表 SPT 行**);不要混在同一 **`server.log`** 里,也不要只改 **`--llm_kv_type`** 而不换标定 JSON。 +2. **端口**:确认 **`8089`** 进入 **LISTEN** 后再跑 **`lm_eval`**(**勿改端口**)。 +3. **结束后**:关闭 **`api_server`** 进程,释放 GPU 与端口。 +4. **错误**:将摘要写入 **`summary.txt`**,并在对话中说明关键日志行。 diff --git a/skills/test_model/qwen3-8b-gsm8k-scenarios/SKILL.md b/skills/test_model/qwen3-8b-gsm8k-scenarios/SKILL.md new file mode 100644 index 0000000000..632e3c4121 --- /dev/null +++ b/skills/test_model/qwen3-8b-gsm8k-scenarios/SKILL.md @@ -0,0 +1,196 @@ +--- +name: test-model-qwen3-8b-gsm8k-scenarios +description: >- + LightLLM Qwen3-8B GSM8K multi-scenario regression: seven isolated api_server configs + (baseline, vllm-fp8w8a8 quant, tpsp mix, tpsp with dp2 and dp prefill balance, cpu cache, + int8kv on top of cpu cache, disk cache with LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH). + Each scenario then lm_eval gsm8k batch 500. Scenarios 5–7 run lm_eval twice for cache + hit. Per-scenario LOG_DIR, server.log, eval logs, summary.txt. Default MODEL_DIR + /mtc/models/qwen3-8b; DISK_CACHE_DIR /mtc/test/tmp/ for scenario 7; ask user if paths + invalid. Fixed HTTP port 8089 (not configurable). nvidia-smi GPUs, port listen not health, + clear proxies and no_proxy. +--- + +# Qwen3-8B **多场景 GSM8K 回归** + +同一 **`MODEL_DIR`(Qwen3-8B 权重)** 下,按 **七种 `api_server` 配置** 依次各跑一轮:**启动服务 → 端口与日志就绪 → `lm_eval`**。场景 **5、6、7** 在相同服务配置下 **`lm_eval` 连续执行两次**(缓存预热与命中后效率/精度对照,与历史脚本注释一致)。 + +**端口**:**固定 `8089`**(与 **`--port`**、**`lm_eval` 的 `base_url`** 一致;**不作为环境变量**)。 + +**评测**:**`lm_eval`**,**`tasks gsm8k`**,**`batch_size 500`**,**`model`:`qwen/qwen3-8b`**。**`tokenizer` 与 `MODEL_DIR` 须为同一目录路径**。 + +## 场景总览 + +| # | 名称 | `api_server` 要点 | `lm_eval` | +|---|------|-------------------|-----------| +| 1 | 基线 | **`--tp 2`**,无额外开关 | 1 次 | +| 2 | FP8 量化 | **`--quant_type vllm-fp8w8a8`**(在场景 1 基础上) | 1 次 | +| 3 | TP-SP 混合 | **`--enable_tpsp_mix_mode`**(**`--tp 2`**,无 **`--dp`**) | 1 次 | +| 4 | TP-SP + DP2 + DP prefill 均衡 | **`--tp 2 --dp 2`**、**`--enable_tpsp_mix_mode`**、**`--enable_dp_prefill_balance`** | 1 次 | +| 5 | CPU Cache | **`--tp 2 --dp 2`**,**`--max_total_token_num 200000`**,**`--enable_cpu_cache`**,**`--cpu_cache_storage_size 128`**,**`--cpu_cache_token_page_size 128`** | **2 次** | +| 6 | CPU Cache + INT8 KV | 在场景 5 基础上增加 **`--llm_kv_type int8kv`** | **2 次** | +| 7 | Disk Cache | **`LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128`**;**`--tp 2 --dp 2`**,**`--max_total_token_num 200000`**,CPU cache 与 **disk cache** 一组参数(见命令块) | **2 次** | + +**算力说明**:历史脚本使用 **`CUDA_VISIBLE_DEVICES`** 指向 **2 张卡**;场景 **4–7** 含 **`--dp 2`**。执行前须结合 **`nvidia-smi`** 与 **LightLLM 对 tp/dp 的资源说明** 确认本机 GPU 数与映射是否满足;不满足时 **向用户询问** 正确启动方式,**不要盲试**。 + +## 日志目录(含 `summary.txt`) + +- **每个场景**使用独立 **`LOG_DIR`**。 +- **`api_server`** → **`"${LOG_DIR}/server.log"`**(推荐 **`nohup … >> … 2>&1 &`**)。 +- **`lm_eval`**:第一次 **`"${LOG_DIR}/eval_gsm8k.log"`**;第二次(场景 5–7)**`"${LOG_DIR}/eval_gsm8k_run2.log"`**。 +- **`summary.txt`**:本场景完整启动参数、**`lm_eval` 摘要**、端口与日志就绪情况、两轮评测说明(若适用)、结论与失败原因。 + +## 启动前检查 + +1. **显卡**:**`nvidia-smi`** 后 **`export CUDA_VISIBLE_DEVICES`**;**不要写死卡号**;**`--tp` / `--dp`** 与卡数须匹配本机规范。 +2. **端口**:每轮前确认 **`8089`** 空闲;上一轮结束后 **终止 `api_server`** 再启下一轮。 +3. **`MODEL_DIR`**:见 **「路径约定」**;**`test -d "${MODEL_DIR}"`**。 +4. **`DISK_CACHE_DIR`(仅场景 7)**:见 **「路径约定」**;**`mkdir -p`** 后须可写。 +5. **代理**:**`api_server` / `lm_eval` 前** 置空 **`http_proxy` / `https_proxy`**;**`lm_eval`** 配置 **`no_proxy`**(见评测块)。 + +## 路径约定(`MODEL_DIR` 与 `DISK_CACHE_DIR`) + +- **`MODEL_DIR`**:**首轮试跑默认** **`/mtc/models/qwen3-8b`**。若目录不存在或加载失败,**向用户询问** 本机正确路径;**`--model_dir` 与 `lm_eval` 的 `tokenizer` 保持一致**。 +- **`DISK_CACHE_DIR`(场景 7)**:**默认** **`/mtc/test/tmp/`**;不可写或不存在时 **向用户询问** 可写目录;**`summary.txt`** 记录最终路径。 + +## 可变项 + +| 变量 | 含义 | +|------|------| +| `LOG_DIR` | 当前场景日志根目录。 | +| `MODEL_DIR` | **`--model_dir`**;**`lm_eval` 的 `tokenizer`**。 | +| `BIND_URL_HOST` | **`base_url` 主机**;常用 **`127.0.0.1`**。 | +| `CUDA_VISIBLE_DEVICES` | 由 **`nvidia-smi`** 决定;与 tp/dp 组合须匹配环境。 | +| `DISK_CACHE_DIR` | 场景 7 的 **`--disk_cache_dir`**;默认 **`/mtc/test/tmp/`**。 | + +**开跑前导出示例**: + +```bash +export LOG_DIR='〈本场景日志目录〉' +export MODEL_DIR='/mtc/models/qwen3-8b' +export DISK_CACHE_DIR='/mtc/test/tmp/' +export BIND_URL_HOST='127.0.0.1' +# export CUDA_VISIBLE_DEVICES='6,7' +``` + +## 服务就绪判定 + +**不要使用 HTTP health 作为唯一依据**。结合 **`8089` 是否 LISTEN** 与 **`server.log`**;可约 **每 20 秒** 查看一次直至可评测或确认失败。 + +## `lm_eval` 命令模板(单次) + +```bash +export http_proxy= +export https_proxy= + +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${BIND_URL_HOST} + +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"qwen/qwen3-8b\", \"base_url\":\"http://${BIND_URL_HOST}:8089/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +场景 **5–7** 第二次:将重定向改为 **`>> "${LOG_DIR}/eval_gsm8k_run2.log" 2>&1`**。 + +## 各场景 `api_server` 命令模板 + +以下省略 **`export http_proxy=` / `export https_proxy=`**、**`LOADWORKER=18`**、**`CUDA_VISIBLE_DEVICES`**、**`nohup`** 与 **`>> "${LOG_DIR}/server.log" 2>&1 &`**;实际执行时与其它 acc skill 一致自行补全。 + +### 场景 1:基线 + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 +``` + +### 场景 2:FP8 量化(`vllm-fp8w8a8`) + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 \ + --quant_type vllm-fp8w8a8 +``` + +### 场景 3:TP-SP 混合 + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 \ + --enable_tpsp_mix_mode +``` + +### 场景 4:TP-SP + DP2 + DP prefill 均衡 + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --dp 2 \ + --port 8089 \ + --enable_tpsp_mix_mode \ + --enable_dp_prefill_balance +``` + +### 场景 5:CPU Cache(`lm_eval` 两次) + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --dp 2 \ + --port 8089 \ + --max_total_token_num 200000 \ + --enable_cpu_cache \ + --cpu_cache_storage_size 128 \ + --cpu_cache_token_page_size 128 +``` + +### 场景 6:CPU Cache + INT8 KV(`lm_eval` 两次) + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --dp 2 \ + --port 8089 \ + --max_total_token_num 200000 \ + --enable_cpu_cache \ + --cpu_cache_storage_size 128 \ + --cpu_cache_token_page_size 128 \ + --llm_kv_type int8kv +``` + +### 场景 7:Disk Cache(`lm_eval` 两次) + +与历史脚本一致:在 **`python`** 前加 **`LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128`**。 + +```bash +LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128 \ +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --dp 2 \ + --port 8089 \ + --max_total_token_num 200000 \ + --enable_cpu_cache \ + --cpu_cache_storage_size 64 \ + --cpu_cache_token_page_size 128 \ + --enable_disk_cache \ + --disk_cache_storage_size 256 \ + --disk_cache_dir "${DISK_CACHE_DIR}" +``` + +## 执行约定 + +1. **顺序**:**1 → 7** 严格递增;每步 **新 `LOG_DIR`**,**先停旧服务**。 +2. **场景 5–7**:**`lm_eval` 各执行两次**,并在 **`summary.txt`** 说明 run1 / run2 目的。 +3. **`MODEL_DIR` / `DISK_CACHE_DIR`**:遵循 **「路径约定」**。 +4. **收尾**:全部结束后释放进程、端口与 GPU。 diff --git a/skills/test_model/qwen3-8b-pd-nccl/SKILL.md b/skills/test_model/qwen3-8b-pd-nccl/SKILL.md new file mode 100644 index 0000000000..fdf559a27e --- /dev/null +++ b/skills/test_model/qwen3-8b-pd-nccl/SKILL.md @@ -0,0 +1,187 @@ +--- +name: test-model-qwen3-8b-pd-nccl +description: >- + LightLLM Qwen3-8b PD disaggregation gsm8k: pd_master on 8089, prefill on 8001, decode on + 8002, tp 2 each. Assign four GPUs by running nvidia-smi and deciding prefill/decode pairs + (no fixed card IDs; no complex shell automation). lm_eval hits pd_master URL. HOST vs + PD_MASTER_IP when co-located. Requires LOG_DIR, MODEL_DIR, proxy cleared, no_proxy, summary.txt. + Use for PD NCCL-style separation tests. +--- + +# Qwen3-8B **PD 分离**(`pd_master` + `prefill` + `decode`)本地 GSM8K 评测 + +**测试标识**:同一 **`--model_dir`**(Qwen3-8B)下拆 **三条** `api_server` 进程——**调度/入口(pd_master)**、**prefill 节点**、**decode 节点**;评测 **`lm_eval`** 只访问 **`pd_master` 的 HTTP 端口(8089)**,由调度转发到 PD 链路。与单机单进程 Base–TP、MTP 等流程区分。 + +**端口约定**:**`pd_master`:`8089`**;**prefill:`8001`**;**decode:`8002`**。启动与就绪探测须覆盖这三处(以及日志中的 PD 注册/报错信息)。 + +**绑定 IP(`HOST` / `PD_MASTER_IP`)**:各进程的 **`--host`** 表示 **本服务监听绑定的 IP**(与其它集群「逻辑 hostname」概念区分时,此处一律按 **绑定地址** 理解)。当 **`pd_master`、`prefill`、`decode` 部署在同一台机器上时**,三者使用的绑定 IP **相同**:此时可只做一次赋值 **`export HOST="${PD_MASTER_IP}"`**(或先将本机对外/LAN IP 赋给 **`PD_MASTER_IP`**,再 **`export HOST="${PD_MASTER_IP}"`**),保证 **`pd_master` 的 `--host`** 与 **prefill/decode 的 `--host`** 一致;**`lm_eval` 的 `base_url` 仍指向 `pd_master`**,故 **`PD_MASTER_IP`** 也同时作为评测 URL 中的主机名。 + +整轮产物落在**同一日志目录**,写入 **`summary.txt`** 与各进程日志(见「日志目录」);**不要**写聚合启动脚本,按「启动说明」逐条手动启动并在后台落盘。 + +## 日志目录(含 `summary.txt`) + +- 每次评测先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开。 +- **三个 `api_server` 的标准输出/错误**分别写入该目录,建议命名:**`pd_master.log`**、**`prefill.log`**、**`decode.log`**(或分子目录 `pd_master/`、`prefill/`、`decode/`)。 +- **`summary.txt` 固定放在该日志目录下**,汇总:三台进程的启动参数摘要、端口与就绪情况、`lm_eval` 关键结果、失败原因与最终结论。 +- **`eval_gsm8k.log`**:`lm_eval` 终端输出;**`summary.txt`** 仍为**总览结论**。 + +## 启动说明 + +本节包含:启动前检查 → 可变项说明 → 显卡分配 → **按顺序**三条完整 server 命令 → 评测命令。 + +### 启动前检查 + +开跑前先确认资源与环境可用;**不满足则先清理占用端口的进程或释放 GPU**,再按顺序启动。 + +1. **显卡**:prefill / decode 各需 **2 张物理 GPU**(**`--tp 2`**),共 **4 张互不重复**的卡。**不要写死卡号**:先 **`nvidia-smi`**(见下文「显卡分配」),由执行者根据占用与集群情况选定 **prefill 两张、decode 两张**,再 **`export PREFILL_CUDA_DEVICES`**、**`DECODE_CUDA_DEVICES`** 后启动。 +2. **端口**:**`8089`、`8001`、`8002`** 均须未被监听(`ss -tlnp`、`lsof -i :端口` 等);若被占用,结束占用进程后再启动。 +3. **网络 / IP**:**`HOST`** 为 **prefill / decode 的服务绑定 IP**;**`PD_MASTER_IP`** 为 **`pd_master` 的 `--host`**,且与 **`lm_eval` 访问地址**一致。**单机三进程同机时**:**`HOST` 与 `PD_MASTER_IP` 取同一值**(见上文「绑定 IP」);多机分发时再按各节点真实监听地址分别设置。 +4. **代理**:启动 **任一 server 前**将 **`http_proxy` / `https_proxy` 置空**(见各命令块前 `export`);避免代理干扰本地 PD 通信。**评测阶段**使用 **`no_proxy`** 排除本机(见评测命令);若需先用代理下载 `lm_eval` 缓存,见「执行约定」。 + +### 启动服务的命令模板(可变项) + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮日志根目录,建议**绝对路径**;`export LOG_DIR=…`。 | +| `MODEL_DIR` | 模型目录,对应三条命令中的 **`--model_dir`**;`lm_eval` 的 **`tokenizer` 须与此路径一致**。 | +| `PD_MASTER_IP` | **`pd_master` 进程 `--host`** 所使用的 **绑定 IP**;同时也是 **`lm_eval` 里 `base_url` 的主机部分**(评测客户端访问 pd_master 的地址)。 | +| `HOST` | **`prefill` / `decode` 进程 `--host`** 所使用的 **绑定 IP**(本服务监听地址)。**与 `pd_master` 同机时**:与 **`PD_MASTER_IP` 相同**,可 **`export HOST="${PD_MASTER_IP}"`**。 | +| `PREFILL_CUDA_DEVICES` | **prefill** 的 **`CUDA_VISIBLE_DEVICES`**,形如 `a,b`(两张物理卡索引);由 **`nvidia-smi`** 判断后 **`export`**。 | +| `DECODE_CUDA_DEVICES` | **decode** 的 **`CUDA_VISIBLE_DEVICES`**,形如 `c,d`;与 prefill **四卡互不重复**。 | +| `pd_master.log` 等 | 文件名示例,可改名。 | + +开跑前导出(引号内替换为本机实际值): + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈Qwen3-8B 模型目录〉' +export PD_MASTER_IP='〈本机绑定 IP:pd_master --host,且供 lm_eval 访问〉' +# 单机:prefill/decode 与 pd_master 同机时,绑定同一 IP +export HOST="${PD_MASTER_IP}" +# 多机:若 prefill/decode 监听地址不同,再单独 export HOST='〈该机上绑定 IP〉' +``` + +首次试跑可用的**默认 `MODEL_DIR`** 见「执行约定」。 + +### 显卡分配(`nvidia-smi` + 人工/Agent 决策,不用复杂脚本) + +约束:**prefill**、**decode** 各 **2 张物理 GPU**(**`--tp 2`**),共 **4 张互不重复**;**不要**默认写死 `0,1` / `2,3`。 + +1. **查看占用**:在启动 **prefill** 之前(**`pd_master` 已起来之后**即可),执行 **`nvidia-smi`**,需要时可带列表输出便于比对: + `nvidia-smi --query-gpu=index,name,memory.used,memory.free --format=csv` + 或先看总览再决定。 +2. **选定四卡**:由**执行本 skill 的 Agent(或操作者)**根据上述输出、机器上其它任务占用、是否需避开某几张卡等因素,**自行决定**哪 **2** 张给 **prefill**、哪 **2** 张给 **decode**(两组索引不得重叠)。 +3. **写入环境变量**:在同一 shell 中 **`export`**(示例数值仅作格式说明): + +```bash +export PREFILL_CUDA_DEVICES='〈物理索引1〉,〈物理索引2〉' +export DECODE_CUDA_DEVICES='〈物理索引3〉,〈物理索引4〉' +``` + +4. **记录**:把最终 **`PREFILL_CUDA_DEVICES`**、**`DECODE_CUDA_DEVICES`** 及当时 **`nvidia-smi` 要点**记入 **`summary.txt`**。 + +**禁止**:不必编写 **awk / mapfile / 长段 bash** 自动选卡脚本;以 **`nvidia-smi` 事实 + 明确决策**为准。 + +### 1)启动 `pd_master`(须最先就绪监听) + +每条命令前清空代理;以下为 **可直接执行** 的后台形式(含 **`nohup`** 与重定向)。若调试可去掉 `nohup` 与 `>> … &`。 + +```bash +export http_proxy= +export https_proxy= + +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode pd_master \ + --host "${PD_MASTER_IP}" \ + --port 8089 \ + >> "${LOG_DIR}/pd_master.log" 2>&1 & +``` + +### 2)启动 `prefill` 节点 + +**须在 pd_master 已监听且日志无致命错误后再启动**(见「执行约定」)。启动本命令前须已完成 **`nvidia-smi` 决策并 `export PREFILL_CUDA_DEVICES=…`**(见「显卡分配」)。 + +```bash +export http_proxy= +export https_proxy= + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${PREFILL_CUDA_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode prefill \ + --tp 2 \ + --dp 1 \ + --host "${HOST}" \ + --port 8001 \ + --disable_cudagraph \ + --pd_master_ip "${PD_MASTER_IP}" \ + --pd_master_port 8089 \ + >> "${LOG_DIR}/prefill.log" 2>&1 & +``` + +### 3)启动 `decode` 节点 + +启动前须已完成 **`export DECODE_CUDA_DEVICES=…`**(见「显卡分配」)。 + +```bash +export http_proxy= +export https_proxy= + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${DECODE_CUDA_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode decode \ + --tp 2 \ + --dp 1 \ + --host "${HOST}" \ + --port 8002 \ + --pd_master_ip "${PD_MASTER_IP}" \ + --pd_master_port 8089 \ + >> "${LOG_DIR}/decode.log" 2>&1 & +``` + +### 评测命令(prefill / decode 已与 pd_master 建立 PD 链路后执行) + +**`base_url` 指向 `pd_master`**:`http://${PD_MASTER_IP}:8089/v1/completions`。以下为带日志落盘的**完整命令**(`--model_args` 使用双引号以展开变量;**`tokenizer` 与 `MODEL_DIR` 一致**): + +```bash +export http_proxy= +export https_proxy= + +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${PD_MASTER_IP} \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"qwen/qwen3-8b\", \"base_url\":\"http://${PD_MASTER_IP}:8089/v1/completions\", \"max_length\": 16384, \"tokenized_requests\": false, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- **`no_proxy`**:须包含本机与 **`PD_MASTER_IP`**(及脚本中的 `0.0.0.0`、`::1` 等),避免评测流量误走 HTTP 代理。 +- 若环境需要,可同时设置 **`NO_PROXY`** 与 **`no_proxy`** 一致。 +- **`tokenized_requests`: `false`** 与脚本一致。 +- 调试可不重定向:去掉末尾 `>> "${LOG_DIR}/eval_gsm8k.log" 2>&1`。 + +## 执行约定(不要额外写“专用启动脚本”) + +**模型目录**:**首轮试跑**可先: + +```bash +export MODEL_DIR=/mtc/models/qwen3-8b +``` + +无法启动或路径类报错时,**请用户提供**本机实际 **`MODEL_DIR`**;保持 **`tokenizer` 与 `--model_dir` 同路径**。 + +**`lm_eval` 与代理 / 缓存**:若评测依赖首次下载缓存,可先**保留代理**单独跑一次 `lm_eval` 完成缓存下载,再**清空代理**并按上文 **`no_proxy`** 跑正式评测(与脚本注释一致)。 + +1. **启动顺序**:先 **`pd_master`** → 再 **`nvidia-smi` 决策并 `export PREFILL_CUDA_DEVICES` / `DECODE_CUDA_DEVICES`** → 再 **prefill** → 再 **decode**;不要颠倒。每一步将输出重定向到 **`LOG_DIR`** 下对应日志。 +2. **不要用 health 接口** 作为唯一依据;改为:**端口 listen**(8089 / 8001 / 8002)并结合日志判断是否已与 pd_master 建立 PD 链路或是否报错。 +3. **等待 / 轮询**:若端口未就绪或链路未建立,约 **每 20 秒** 查看 **`pd_master.log`、`prefill.log`、`decode.log`**,区分仍在启动还是已报错;异常写入 **`summary.txt`** 并停止后续步骤。 +4. **维护 `summary.txt`**:记录三条启动命令摘要(或等价)、**本次 `PREFILL_CUDA_DEVICES` / `DECODE_CUDA_DEVICES` 及选卡依据(`nvidia-smi` 要点)**、各端口检测结果、`lm_eval` 关键输出;结束后写**最终汇总**。 +5. **测试结束后**:**关闭本次启动的所有相关进程**(`pd_master`、prefill、decode),释放端口与 GPU。 +6. **错误记录**:启动或评测失败时,将错误摘要记入 **`summary.txt`**,并在对话中说明关键信息。 + +## 输出文件 + +- **`summary.txt`**:位于**本轮日志目录**,作为本次 PD 分离评测的**最终总结**。 +- **服务与评测日志**:**`pd_master.log`、`prefill.log`、`decode.log`、`eval_gsm8k.log`** 均落在**同一日志目录**。 diff --git a/skills/test_model/qwen3-8b-pd-nixl/SKILL.md b/skills/test_model/qwen3-8b-pd-nixl/SKILL.md new file mode 100644 index 0000000000..cf62a3a4dd --- /dev/null +++ b/skills/test_model/qwen3-8b-pd-nixl/SKILL.md @@ -0,0 +1,200 @@ +--- +name: test-model-qwen3-8b-pd-nixl +description: >- + LightLLM Qwen3-8b PD disaggregation over NIXL gsm8k: pd_master on 8089, nixl_prefill on 8001, + nixl_decode on 8002, tp 2 each. Assign four GPUs via nvidia-smi then export + PREFILL_CUDA_DEVICES / DECODE_CUDA_DEVICES (no fixed card IDs; no complex shell automation). + UCX_NET_DEVICES and TLS for RDMA per cluster. lm_eval hits pd_master URL. HOST vs + PD_MASTER_IP when co-located. Before lm_eval, must POST one completion via curl to + pd_master for warmup verification. Requires LOG_DIR, MODEL_DIR, proxy cleared, no_proxy, + summary.txt. Use for PD NIXL-style separation tests. +--- + +# Qwen3-8B **PD 分离(NIXL)**(`pd_master` + `nixl_prefill` + `nixl_decode`)本地 GSM8K 评测 + +**测试标识**:同一 **`--model_dir`**(Qwen3-8B)下拆 **三条** `api_server` 进程——**调度/入口(`pd_master`)**、**`nixl_prefill` 节点**、**`nixl_decode` 节点**;评测 **`lm_eval`** 只访问 **`pd_master` 的 HTTP 端口(8089)**。与 **NCCL 版 PD**(`prefill` / `decode`)区分之处在于 **`--run_mode`** 与 **prefill/decode 前须配置 UCX/RDMA 环境变量**。 + +**端口约定**:**`pd_master`:`8089`**;**prefill:`8001`**;**decode:`8002`**。启动与就绪探测须覆盖这三处(以及日志中的 PD 注册/报错信息)。 + +**绑定 IP(`HOST` / `PD_MASTER_IP`)**:各进程的 **`--host`** 表示 **本服务监听绑定的 IP**。当 **`pd_master`、`nixl_prefill`、`nixl_decode` 部署在同一台机器上时**,三者使用的绑定 IP **相同**:可 **`export HOST="${PD_MASTER_IP}"`**;**`lm_eval` 的 `base_url` 仍指向 `pd_master`**。 + +整轮产物落在**同一日志目录**,写入 **`summary.txt`** 与各进程日志;**不要**写聚合启动脚本,按「启动说明」逐条手动启动并在后台落盘。 + +## 日志目录(含 `summary.txt`) + +- 每次评测先选定或新建**一个日志目录**(例如带时间戳或任务名),与其它测试轮次分开。 +- **三个 `api_server` 的标准输出/错误**分别写入该目录,建议命名:**`pd_master.log`**、**`prefill.log`**、**`decode.log`**(文件名可沿用习惯,与 NCCL 测试一致便于对比)。 +- **`summary.txt` 固定放在该日志目录下**,汇总:三台进程的启动参数摘要、端口与就绪情况、**UCX 配置要点**、`lm_eval` 关键结果、失败原因与最终结论。 +- **`eval_gsm8k.log`**:`lm_eval` 终端输出;**`curl_warmup.log`**:测试前 **`curl`** 打 **`pd_master`** 的留档(建议);**`summary.txt`** 仍为**总览结论**。 + +## 启动说明 + +本节包含:启动前检查 → 可变项说明 → 显卡分配 → UCX → **按顺序**三条完整 server 命令 → **curl warmup** → 评测命令。 + +### 启动前检查 + +1. **显卡**:prefill / decode 各需 **2 张物理 GPU**(**`--tp 2`**),共 **4 张互不重复**。**不要写死卡号**:先 **`nvidia-smi`**(见「显卡分配」),再 **`export PREFILL_CUDA_DEVICES`**、**`DECODE_CUDA_DEVICES`**。 +2. **端口**:**`8089`、`8001`、`8002`** 均须未被占用。 +3. **网络 / IP**:**`HOST`** 与 **`PD_MASTER_IP`** 约定同 NCCL PD skill;单机三进程 **`export HOST="${PD_MASTER_IP}"`**。 +4. **代理**:启动 **任一 server 前**将 **`http_proxy` / `https_proxy` 置空**;评测使用 **`no_proxy`**(见评测命令)。 +5. **RDMA / UCX**:prefill 与 decode 进程在启动 Python 前须设置 **`UCX_NET_DEVICES`**(及可选 **`UCX_LOG_LEVEL`**、**`UCX_TLS`**),取值依赖本机 **`ibv_devinfo`** 与机房拓扑(见「UCX / RDMA」);**不要**默认照抄他机上的设备名或排除列表。 + +### 启动服务的命令模板(可变项) + +| 可变项 | 含义 | +|--------|------| +| `LOG_DIR` | 本轮日志根目录;`export LOG_DIR=…`。 | +| `MODEL_DIR` | **`--model_dir`**;`lm_eval` 的 **`tokenizer` 须与此路径一致**。 | +| `PD_MASTER_IP` | **`pd_master` 的 `--host`**;**`lm_eval` 的 `base_url` 主机**。 | +| `HOST` | **`nixl_prefill` / `nixl_decode` 的 `--host`**。同机时 **`export HOST="${PD_MASTER_IP}"`**。 | +| `PREFILL_CUDA_DEVICES` | prefill 的 **`CUDA_VISIBLE_DEVICES`**(两张物理索引);**`nvidia-smi` 后 export**。 | +| `DECODE_CUDA_DEVICES` | decode 的 **`CUDA_VISIBLE_DEVICES`**;与 prefill **四卡互不重复**。 | +| `UCX_NET_DEVICES` | UCX 使用的 HCA 列表,形如 `mlx5_0:1,mlx5_1:1`;**按本机 `ibv_devinfo` 与规划填写**。 | +| `UCX_LOG_LEVEL` / `UCX_TLS` | 常见为 **`info`** 与 **`rc,cuda,gdr_copy`**;可按环境调整。 | + +开跑前导出示例: + +```bash +export LOG_DIR='〈日志根目录〉' +export MODEL_DIR='〈Qwen3-8B 模型目录〉' +export PD_MASTER_IP='〈本机绑定 IP〉' +export HOST="${PD_MASTER_IP}" +export UCX_NET_DEVICES='〈按 ibv_devinfo 填写,逗号分隔 port :1〉' +export UCX_LOG_LEVEL=info +export UCX_TLS=rc,cuda,gdr_copy +``` + +### 显卡分配(`nvidia-smi` + 人工/Agent 决策,不用复杂脚本) + +与 **qwen3-8b-pd-nccl** skill 相同:**prefill**、**decode** 各 **2** 张 GPU,共 **4** 张互不重复。 + +1. 执行 **`nvidia-smi`**(可选用 `--query-gpu=index,name,memory.used,memory.free --format=csv`)。 +2. 由执行者选定哪 2 张给 prefill、哪 2 张给 decode(不重叠)。 +3. **`export PREFILL_CUDA_DEVICES='…','…'`**、**`export DECODE_CUDA_DEVICES='…','…'`**。 +4. 将选卡依据记入 **`summary.txt`**。 + +**禁止**:为选卡编写 **awk / mapfile / 长段 bash** 自动化;以 **`nvidia-smi` 事实 + 明确决策**为准。 + +### UCX / RDMA(NIXL 传输) + +- **`UCX_NET_DEVICES`**:须覆盖本进程要用的 **RDMA 设备**;是否排除某些 HCA(例如数据面网卡)由**本机拓扑**决定,在 **`summary.txt`** 中写明依据。 +- **`UCX_TLS`**:常见 **`rc,cuda,gdr_copy`**;若环境不支持再按报错调整。 + +### 1)启动 `pd_master`(须最先就绪监听) + +```bash +export http_proxy= +export https_proxy= + +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode pd_master \ + --host "${PD_MASTER_IP}" \ + --port 8089 \ + >> "${LOG_DIR}/pd_master.log" 2>&1 & +``` + +### 2)启动 `nixl_prefill` 节点 + +**须在 `pd_master` 就绪后**再启动。启动前已完成 **`nvidia-smi` 决策**并 **`export PREFILL_CUDA_DEVICES`**,且已设置 **UCX**。 + +```bash +export http_proxy= +export https_proxy= + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${PREFILL_CUDA_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode nixl_prefill \ + --tp 2 \ + --dp 1 \ + --host "${HOST}" \ + --port 8001 \ + --disable_cudagraph \ + --pd_master_ip "${PD_MASTER_IP}" \ + --pd_master_port 8089 \ + >> "${LOG_DIR}/prefill.log" 2>&1 & +``` + +(若需显式传入 UCX,可在同一 shell 中于本块之前 **`export UCX_NET_DEVICES`** 等;**`nohup` 会继承当前 shell 的环境变量**。) + +### 3)启动 `nixl_decode` 节点 + +启动前 **`export DECODE_CUDA_DEVICES`**,并确保 **UCX** 已设置。 + +```bash +export http_proxy= +export https_proxy= +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${PD_MASTER_IP} + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${DECODE_CUDA_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --run_mode nixl_decode \ + --tp 2 \ + --dp 1 \ + --host "${HOST}" \ + --port 8002 \ + --pd_master_ip "${PD_MASTER_IP}" \ + --pd_master_port 8089 \ + >> "${LOG_DIR}/decode.log" 2>&1 & +``` + +### 测试前 curl warmup(**须执行**,再走 `lm_eval`) + +NIXL PD 链路在首次真实推理前易出现冷启动与传输路径问题。**在跑 `lm_eval` 正式评测之前**,必须先对 **`pd_master`** 的 **`/v1/completions`** 发 **至少一次** HTTP 请求,确认返回 **2xx** 且响应体含正常 completion(再走长评测)。 + +1. **时机**:**`nixl_prefill` 与 `nixl_decode` 均已启动**,且日志显示已与 **`pd_master`** 建立 PD 链路后再执行(可与端口 listen、日志轮询结合判断)。 +2. **代理**:执行 **`curl` 前**同样 **`export http_proxy=` / `export https_proxy=`**;若评测机对 **`PD_MASTER_IP`** 走代理会失败,可对本次 shell 设置 **`no_proxy`**(与下文 `lm_eval` 一致,须包含 **`${PD_MASTER_IP}`**)。 +3. **记录**:将 **`curl` 使用的命令、HTTP 状态码、若失败则错误摘要** 写入 **`summary.txt`**;成功后再启动 **`lm_eval`**。 + +示例(**`model` 与 `lm_eval` 中 `model` 字段保持一致**,一般为 **`qwen/qwen3-8b`**;可按需改 **`prompt` / `max_tokens`**): + +```bash +export http_proxy= +export https_proxy= +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${PD_MASTER_IP} + +curl -sS -w "\nhttp_code:%{http_code}\n" -X POST "http://${PD_MASTER_IP}:8089/v1/completions" \ + -H "Content-Type: application/json" \ + -d "{\"model\":\"qwen/qwen3-8b\",\"prompt\":\"warmup\",\"max_tokens\":32}" \ + | tee "${LOG_DIR}/curl_warmup.log" +``` + +- 期望 **`http_code:200`**(或环境约定的成功码);非 2xx 时先查 **`pd_master.log` / `prefill.log` / `decode.log`**,**不要**直接开大批量 `lm_eval`。 +- 可将 **`curl` 输出**保留为 **`curl_warmup.log`**(如上),便于与 **`eval_gsm8k.log`** 对照。 + +### 评测命令(**curl warmup 成功后**执行) + +**`base_url` 指向 `pd_master`**;**`tokenizer` 与 `MODEL_DIR` 一致**: + +```bash +export http_proxy= +export https_proxy= + +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${PD_MASTER_IP} \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"qwen/qwen3-8b\", \"base_url\":\"http://${PD_MASTER_IP}:8089/v1/completions\", \"max_length\": 16384, \"tokenized_requests\": false, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 64 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +- 若需 **`lm_eval` 侧**再跑一次小样本,可加 **`--limit 1`**;**不能替代**上文 **`curl` warmup**。 +- 若需先用代理下载 `lm_eval` 缓存,见「执行约定」。 + +## 执行约定 + +**模型目录**:首轮可 **`export MODEL_DIR=/mtc/models/qwen3-8b`**;路径报错时由用户提供本机 **`MODEL_DIR`**。 + +1. **启动顺序**:**`pd_master`** → **`nvidia-smi` + export 四卡** → **设置 UCX** → **`nixl_prefill`** → **`nixl_decode`** → **`curl` warmup(须成功)** → **`lm_eval`**。 +2. **不要用 health 接口**作为唯一依据;结合 **端口 listen** 与 **`pd_master.log` / `prefill.log` / `decode.log`**。 +3. **约每 20 秒**查看日志直至就绪或报错;异常写入 **`summary.txt`**。 +4. **`summary.txt`**:记录启动摘要、**`PREFILL_CUDA_DEVICES` / `DECODE_CUDA_DEVICES`** 与选卡依据、**`UCX_NET_DEVICES` 等**、**`curl` warmup 结果(或 `curl_warmup.log` 路径)**、评测关键输出、最终结论。 +5. **结束后**关闭 **`pd_master`、`nixl_prefill`、`nixl_decode`** 相关进程。 +6. 当用户说明是压测的时候,将lmeval 的 --batch_size 修改为 500 +7. 发现 connetion to pd_master has error 错误的时候,可以先容忍一会,这种网络状态错误有时是可以自行恢复的。 + +## 输出文件 + +- **`summary.txt`**、**`pd_master.log`、`prefill.log`、`decode.log`**、**`curl_warmup.log`(建议)**、**`eval_gsm8k.log`** 均落在**同一 `LOG_DIR`**。 diff --git a/skills/test_model/qwen3-vl-8b-mmmu-val/SKILL.md b/skills/test_model/qwen3-vl-8b-mmmu-val/SKILL.md new file mode 100644 index 0000000000..5db4754500 --- /dev/null +++ b/skills/test_model/qwen3-vl-8b-mmmu-val/SKILL.md @@ -0,0 +1,114 @@ +--- +name: test-model-qwen3-vl-8b-mmmu-val +description: >- + LightLLM Qwen3-VL-8B-Instruct: api_server tp 2 on port 8089, then lmms-eval CLI + (python -m lmms_eval, model openai_compatible, tasks mmmu_val, batch_size 900) + with OPENAI_API_BASE pointing at LightLLM OpenAI-compatible /v1. Restore https_proxy for Hub + while no_proxy includes 127.0.0.1. Requires lmms-eval install, OPENAI_API_KEY placeholder, + LOG_DIR and MODEL_DIR, nvidia-smi GPU choice, pipefail with tee, summary.txt. No wrapper + script; use command line only. +--- + +# Qwen3-VL-8B-Instruct **MMMU 验证集(`mmmu_val`)** 评测 + +**测试标识**:先在本机启动 **`lightllm.server.api_server`**(**Qwen3-VL-8B-Instruct**,**`--tp 2`**,HTTP **`8089`**);服务就绪后,在已安装 **`lmms-eval`** 的环境中直接执行 **`python3 -m lmms_eval`**(**`openai_compatible`**,任务 **`mmmu_val`**),通过环境变量 **`OPENAI_API_BASE`** 指向 **`api_server`** 的 OpenAI 兼容前缀(**含 `/v1`**)。 + +**依赖(评测侧)**:**`lmms-eval`**(版本示例): + +```text +git clone --branch v0.3.3 --depth 1 https://github.com/EvolvingLMMs-Lab/lmms-eval.git +pip install -e lmms-eval/ +``` + +执行 **`python3 -m lmms_eval`** 的 Python 环境须已安装上述包;**不要求**在 LightLLM 仓库根目录下执行(除非你的数据或配置依赖 **`cwd`**)。 + +## 日志目录(含 `summary.txt`) + +- 选定 **`LOG_DIR`**(绝对路径建议带时间戳)。 +- **`api_server`** → **`"${LOG_DIR}/server.log"`**(推荐 **`nohup`** 后台)。 +- **`lmms_eval`** 的 **`--output_path`**:**建议 `"${LOG_DIR}/lmms_eval_out"`**;控制台输出可 **`tee`** 到 **`"${LOG_DIR}/lmms_eval_console.log"`**。 +- **`summary.txt`**:模型路径、**`OPENAI_API_BASE`**、完整 **`lmms_eval` 命令**、端口检测结果、输出目录路径、失败原因。 + +## 启动前检查 + +1. **显卡**:**`--tp 2`** → **2 张物理 GPU**;先 **`nvidia-smi`**,再 **`export CUDA_VISIBLE_DEVICES`**(**不要写死**)。 +2. **端口**:**`8089`** 未被占用。 +3. **`MODEL_DIR`**:**`api_server --model_dir`** 与 **`--model_args` 里的 `model_version=`** 须为**同一 Qwen3-VL-8B-Instruct 权重路径**(默认示例 **`/mtc/models/Qwen3-VL-8B-Instruct`**;不存在时向用户询问本机路径)。 +4. **`lmms-eval` 已安装**且 **`python3 -m lmms_eval`** 可用。 +5. **代理**:启动 **`api_server` 前**清空 **`http_proxy` / `https_proxy`**;跑 **`lmms_eval` 前**将 **`no_proxy`** 设为包含本机 **`127.0.0.1`**(见下文评测块);**若需从 Hugging Face Hub 拉取 `lmms-lab/MMMU`,评测阶段应恢复可用的 `https_proxy`(或等价镜像)**,否则清空代理后可能出现 **`ConnectionError: Couldn't reach 'lmms-lab/MMMU' on the Hub`**。 + +## 可变项 + +| 变量 | 含义 | +|------|------| +| `LOG_DIR` | 本轮日志与 **`lmms_eval --output_path`** 父目录。 | +| `MODEL_DIR` | **`api_server --model_dir`**;**`--model_args` 中 `model_version=`** 与之相同。 | +| `PORT` | 默认 **`8089`**。 | +| `BIND_URL_HOST` | 与 **`OPENAI_API_BASE`** 主机一致;本机常用 **`127.0.0.1`**。 | +| `OPENAI_API_BASE` | 形如 **`http://${BIND_URL_HOST}:${PORT}/v1`**(**末尾含 `/v1`**)。 | +| `OPENAI_API_KEY` | 占位即可(常用 **`lightllm123`**);若服务端校验密钥,与用户环境对齐。 | +| `CUDA_VISIBLE_DEVICES` | 两张卡。 | + +## 启动 `api_server` + +**不要用 health 作为唯一依据**;以 **端口 listen** + **`server.log`** 为准;可约 **每 20 秒**查看日志。 + +```bash +export http_proxy= +export https_proxy= + +export LOG_DIR='〈日志目录〉' +export MODEL_DIR='/mtc/models/Qwen3-VL-8B-Instruct' +export PORT=8089 + +LOADWORKER=18 CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES}" \ +nohup python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" \ + >> "${LOG_DIR}/server.log" 2>&1 & +``` + +## 运行 `lmms_eval`(服务就绪后,仅命令行) + +设置 **`OPENAI_API_*`** 与代理后,直接 **`python3 -m lmms_eval`**(**`timeout` 可选**,例如单次上限 **3600 秒**): + +```bash +# 若启动 api_server 时曾清空代理,请先保存并在评测前恢复 Hub 代理,例如: +# export ORIG_HTTPS_PROXY="${https_proxy-}" +# export http_proxy=; export https_proxy= +# … 启动 api_server … +# export https_proxy="${ORIG_HTTPS_PROXY}" + +export BIND_URL_HOST='127.0.0.1' +export PORT=8089 +export OPENAI_API_BASE="http://${BIND_URL_HOST}:${PORT}/v1" +export OPENAI_API_KEY="${OPENAI_API_KEY:-lightllm123}" +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${BIND_URL_HOST} + +export LOG_DIR='〈与上文同一日志目录〉' +export MODEL_DIR='/mtc/models/Qwen3-VL-8B-Instruct' + +mkdir -p "${LOG_DIR}/lmms_eval_out" + +timeout 3600 python3 -m lmms_eval \ + --model openai_compatible \ + --model_args "model_version=${MODEL_DIR},tp=1" \ + --tasks mmmu_val \ + --batch_size 900 \ + --log_samples \ + --log_samples_suffix openai_compatible \ + --output_path "${LOG_DIR}/lmms_eval_out" \ + 2>&1 | tee "${LOG_DIR}/lmms_eval_console.log" +``` + +说明:**`model_args` 中的 `tp=1`** 为 **`lmms_eval` / `openai_compatible` 侧参数**,与 **`api_server` 的 `--tp 2`** 不同;**不要**混用含义。 + +若环境无 **`timeout`** 命令,可去掉 **`timeout 3600`**。 + +## 执行约定 + +1. **顺序**:**`api_server` 就绪** → 再 **`lmms_eval`**。 +2. **`model_version` 与 `MODEL_DIR` 必须一致**。 +3. 超时或失败将摘要写入 **`summary.txt`**。 +4. 结束后关闭 **`api_server`**,释放 GPU 与端口。 diff --git a/skills/test_model/qwen3-vl-8b-vit-sep-mode/SKILL.md b/skills/test_model/qwen3-vl-8b-vit-sep-mode/SKILL.md new file mode 100644 index 0000000000..2224c35ae3 --- /dev/null +++ b/skills/test_model/qwen3-vl-8b-vit-sep-mode/SKILL.md @@ -0,0 +1,180 @@ +--- +name: test-model-qwen3-vl-8b-vit-sep-mode +description: >- + LightLLM Qwen3-VL-8B-Instruct visual separation (ViT sep / proxy): three processes in + order—config_server on 8090; internal Redis on 6000; visual_only with visual_rpyc 8091 + and afs_image_embed_dir; normal api_server tp 2 port 8089 with visual_use_proxy_mode. + After HTTP /v1/models on normal, lmms_eval mmmu_val (openai_compatible, batch 900, + OPENAI_API_BASE http://HOST:8089/v1); restore https_proxy for Hub while no_proxy includes 127.0.0.1. + lmms_eval_out, console log, mmmu_acc in summary. pipefail for tee exit code. +--- + +# Qwen3-VL-8B-Instruct **视觉分离(`visual_only` + `normal` + `config_server`)** + +**测试标识**:按顺序启动 **三条** `api_server` 进程——**`config_server`**(配置与元数据;**进程内部会启动 Redis 服务,并通过 `--config_server_visual_redis_port`(默认 `6000`)对外暴露**)、**`visual_only`**(独立视觉 / ViT 侧)、**`normal`**(主 LLM,**`--visual_use_proxy_mode`** 经 config 访问视觉侧)。**`6000` 不是本机另行安装的 `redis-server`**,勿与系统包管理器里的 Redis 混为一谈。本流程验证 **ViT 分离 + AFS 嵌入目录** 的联调,并在 **`normal` 就绪后须强制跑通 MMMU 验证集 `mmmu_val`**(**`lmms_eval` + `openai_compatible`**,命令与 **`skills/test_model/qwen3-vl-8b-mmmu-val/SKILL.md`** 评测块一致;仅 **`api_server` 拓扑** 为本文的 **visual 分离三进程**)。 + +**端口约定(固定,与脚本一致)**: + +| 用途 | 端口 | +|------|------| +| **`config_server`** | **`8090`**(**`--config_server_port`**) | +| **Redis(由 `config_server` 内部启动并对外暴露)** | **`6000`**(**`--config_server_visual_redis_port`**;与系统独立安装的 Redis 无关) | +| **`visual_only` RPyC** | **`8091`**(**`--visual_rpyc_port`**) | +| **`normal` HTTP** | **`8089`**(**`--port`**) | + +**算力**:**`visual_only`** 默认 **1 张 GPU**;**`normal`** 默认 **`--tp 2`** → **2 张 GPU**;**三组进程不得争抢同一物理 GPU**(脚本示例为 **visual:`0`**,**LLM:`6,7`**;实际以 **`nvidia-smi`** 选定)。 + +## 依赖 + +- **Python 环境**:与运行 **`lightllm.server.api_server`** 的虚拟环境一致。 +- **`mmmu_val` 评测(必须)**:已安装 **`lmms-eval`**,**`python3 -m lmms_eval`** 可用(安装示例见 **`skills/test_model/qwen3-vl-8b-mmmu-val/SKILL.md`**);未完成 **`mmmu_val`** 则本轮 **不算通过**。 +- **`6000` 端口**:由 **`config_server` 在启动后内部拉起 Redis 并监听**;**无需**、也**不应**依赖「事先在本机 **`apt install redis-server`** 并独占 **`6000`**」——若系统已有其它服务占用 **`6000`**,须释放或改 **`--config_server_visual_redis_port`**(**`visual_only` / `normal` 须同步同一端口参数**)。 + +## 日志目录(含 `summary.txt`) + +- 选定 **`LOG_DIR`**,三条进程日志建议:**`"${LOG_DIR}/config_server.log"`**、**`"${LOG_DIR}/visual_only.log"`**、**`"${LOG_DIR}/normal.log"`**(**`nohup … >> … 2>&1 &`**)。 +- **`summary.txt`**:三条命令摘要、各端口 listen 情况、**`MODEL_DIR` / `AFS_IMAGE_EMBED_DIR`** 最终取值;**`mmmu_val` 必记**:**`OPENAI_API_BASE`**、完整 **`lmms_eval` 命令**、**`lmms_eval_console.log`** 与 **`lmms_eval_out`** 路径、**`mmmu_acc`**(见下文「精度」);失败时写清原因与结论。 +- **`lmms_eval_console.log`**(**必须**):**`lmms_eval`** 终端输出(**`tee`**)。 +- **`lmms_eval_out/`**(**必须**):**`--output_path`** 下的 **`*_results.json`**、**`*_samples_mmmu_val.jsonl`**(**`--log_samples`** 生成样本日志)。 + +## 启动前检查 + +1. **端口**:本机 **`8090`、`6000`、`8091`、`8089`** 未被其它进程占用(**`8090` / `6000` 在 `config_server` 启动后由其占用**)。 +2. **`config_server` 已就绪**:**`8090`** 与 **`6000`** 均已 **LISTEN**(表明 **HTTP 配置面** 与 **内部 Redis 暴露面** 已起来),再启动 **`visual_only`**。 +3. **`MODEL_DIR`**:指向 **Qwen3-VL-8B-Instruct**;默认试跑 **`/mtc/models/Qwen3-VL-8B-Instruct`**;不存在或加载失败时 **向用户询问** 本机路径。 +4. **`AFS_IMAGE_EMBED_DIR`**:**`--afs_image_embed_dir`** 指向的目录须存在或可创建;默认试跑 **`/mtc/afs/vit_embed_dir`**;不可用时 **向用户询问**。 +5. **显卡**:**`visual_only`** 与 **`normal`** 的 **`CUDA_VISIBLE_DEVICES`** **不得重叠**;先 **`nvidia-smi`** 再 **`export`**(**不要写死**示例卡号)。 +6. **`CONFIG_SERVER_HOST`**:各进程 **`--config_server_host`** 须能访问 **`config_server` 的 HTTP 服务**。**三进程同机**时常见为 **`0.0.0.0`**(与历史脚本一致);多机时改为 **对端可达的 IP**,并保证防火墙放行 **`config_server` 端口(8090)**、**其内部 Redis 暴露端口(6000)**、**`8091`** 等。 +7. **代理**:每条 **`python`(LightLLM)** 前 **`export http_proxy=`**、**`export https_proxy=`**(与仓库其它 acc 测试一致)。**`lmms_eval` 拉取 `lmms-lab/MMMU` 时**若需经企业代理访问 Hugging Face,应在 **`no_proxy` 已包含 `127.0.0.1`** 的前提下**恢复 `https_proxy`(或等价镜像)**;否则易出现 Hub **`ConnectionError`**。仅当本机已有完整离线缓存且确认 **`datasets` 可纯离线命中**时,才可全程无代理。 +8. **`lmms-eval`**:**`python3 -m lmms_eval --help`** 可执行;否则无法完成必跑 **`mmmu_val`**。 + +## 可变项 + +| 变量 | 含义 | +|------|------| +| `LOG_DIR` | 本轮日志根目录。 | +| `MODEL_DIR` | **`--model_dir`**(三条中涉及模型的命令一致)。 | +| `AFS_IMAGE_EMBED_DIR` | **`--afs_image_embed_dir`**;**`visual_only` 与 `normal` 须一致**。 | +| `CONFIG_SERVER_HOST` | **`--config_server_host`**;同机试跑常用 **`0.0.0.0`**。 | +| `VISUAL_CUDA_DEVICES` | **`visual_only`** 的 **`CUDA_VISIBLE_DEVICES`**(1 张卡)。 | +| `LLM_CUDA_DEVICES` | **`normal`** 的 **`CUDA_VISIBLE_DEVICES`**(**`--tp 2`** → 2 张卡)。 | +| `AFS_EMBED_CAPACITY` | **`--afs_embed_capacity`**;默认 **`250000`**;调试替换逻辑时可改为较小值(例如 **`100`**),见「调试提示」。 | +| `ORIG_HTTP_PROXY` / `ORIG_HTTPS_PROXY` | 在清空代理启动 LightLLM **之前**备份(见 **`lmms_eval` 命令块**),评测阶段恢复以便访问 Hugging Face Hub。 | + +**开跑前导出示例**: + +```bash +export ORIG_HTTP_PROXY="${http_proxy-}" +export ORIG_HTTPS_PROXY="${https_proxy-}" +export LOG_DIR='〈日志目录〉' +export MODEL_DIR='/mtc/models/Qwen3-VL-8B-Instruct' +export AFS_IMAGE_EMBED_DIR='/mtc/afs/vit_embed_dir' +export CONFIG_SERVER_HOST='0.0.0.0' +export AFS_EMBED_CAPACITY=250000 +# export VISUAL_CUDA_DEVICES='0' +# export LLM_CUDA_DEVICES='6,7' +``` + +## 服务就绪判定 + +**不要使用 HTTP health 作为唯一依据**。依次确认:**`config_server` 已占用 `8090` 与 `6000`(内部 Redis)** → **`8091`(`visual_only` RPyC)** → **`8089`(`normal`)** 的 **LISTEN** 状态,并结合各 **`*.log`**;可约 **每 20 秒** 查看日志直至就绪或报错。 + +## 启动命令(须按顺序) + +以下块前均须 **`export http_proxy=`**、**`export https_proxy=`**;生产式跑法请自行加 **`nohup`** 与 **`>> "${LOG_DIR}/….log" 2>&1 &`**。 + +### 1)`config_server`(最先) + +```bash +python -m lightllm.server.api_server \ + --run_mode config_server \ + --config_server_host 0.0.0.0 \ + --config_server_port 8090 \ + --config_server_visual_redis_port 6000 +``` + +若仅需绑定到 **`CONFIG_SERVER_HOST`**,将 **`--config_server_host`** 改为 **`"${CONFIG_SERVER_HOST}"`**(须与 **`visual_only` / `normal` 中的 `--config_server_host`** 指向同一可达地址)。 + +### 2)`visual_only`(**`config_server` 已在 8090 / 6000 就绪后**) + +**`--visual_rpyc_port 8091`** 为 **visual_only 模式必需**,供其它服务调用本机视觉推理接口。 + +```bash +CUDA_VISIBLE_DEVICES="${VISUAL_CUDA_DEVICES}" python -m lightllm.server.api_server \ + --run_mode visual_only \ + --host 0.0.0.0 \ + --config_server_host "${CONFIG_SERVER_HOST}" \ + --config_server_port 8090 \ + --config_server_visual_redis_port 6000 \ + --model_dir "${MODEL_DIR}" \ + --visual_dp 1 \ + --visual_tp 1 \ + --afs_image_embed_dir "${AFS_IMAGE_EMBED_DIR}" \ + --afs_embed_capacity "${AFS_EMBED_CAPACITY}" \ + --visual_rpyc_port 8091 +``` + +**`--host`** 为 **本进程监听地址**;与 **`--config_server_host`** 含义不同:后者为 **config_server 的可达地址**。 + +### 3)`normal`(visual 就绪后) + +```bash +CUDA_VISIBLE_DEVICES="${LLM_CUDA_DEVICES}" python -m lightllm.server.api_server \ + --run_mode normal \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port 8089 \ + --config_server_host "${CONFIG_SERVER_HOST}" \ + --config_server_port 8090 \ + --config_server_visual_redis_port 6000 \ + --visual_dp 1 \ + --afs_image_embed_dir "${AFS_IMAGE_EMBED_DIR}" \ + --afs_embed_capacity "${AFS_EMBED_CAPACITY}" \ + --visual_use_proxy_mode +``` + +## **`mmmu_val` 评测(`normal` 已监听 `8089` 后,必须执行)** + +在 **`config_server` / `visual_only` / `normal` 均就绪**、**`normal`** 仍占用 **`8089`** 时执行;**关停任一服务前须跑完本节**。评测流量只打 **`normal` HTTP**;**`OPENAI_API_BASE`** 须指向 **`http://〈可达主机〉:8089/v1`**(**末尾含 `/v1`**)。**`--model_args` 中 `model_version=` 与三进程共用的 `MODEL_DIR` 须为同一权重目录**。 + +```bash +export BIND_URL_HOST='127.0.0.1' +export PORT=8089 +export OPENAI_API_BASE="http://${BIND_URL_HOST}:${PORT}/v1" +export OPENAI_API_KEY="${OPENAI_API_KEY:-lightllm123}" +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${BIND_URL_HOST} + +# 若启动 LightLLM 时清空了代理,此处恢复 Hub 代理(勿把 127.0.0.1 放进 ALL_PROXY) +export http_proxy="${ORIG_HTTP_PROXY:-}" +export https_proxy="${ORIG_HTTPS_PROXY:-}" + +export LOG_DIR='〈与上文同一日志目录〉' +export MODEL_DIR='/mtc/models/Qwen3-VL-8B-Instruct' + +mkdir -p "${LOG_DIR}/lmms_eval_out" + +timeout 3600 python3 -m lmms_eval \ + --model openai_compatible \ + --model_args "model_version=${MODEL_DIR},tp=1" \ + --tasks mmmu_val \ + --batch_size 900 \ + --log_samples \ + --log_samples_suffix openai_compatible \ + --output_path "${LOG_DIR}/lmms_eval_out" \ + 2>&1 | tee "${LOG_DIR}/lmms_eval_console.log" +``` + +说明:**`model_args` 中的 `tp=1`** 为 **`lmms_eval` / `openai_compatible` 侧参数**,与 **`normal` 的 `--tp 2`** 不同。若环境无 **`timeout`**,去掉 **`timeout 3600`**。仅本地冒烟可在命令中加 **`--limit`**;**正式回归不得省略全量 `mmmu_val`**。 + +**精度(必须写入 `summary.txt`)**:最新 **`"${LOG_DIR}/lmms_eval_out"/*_results.json`** 中 **`results.mmmu_val["mmmu_acc,none"]`**(**0~1**);无 **`jq`** 时打开 JSON 或对照 **`lmms_eval_console.log`** 末尾汇总表。 + +## 调试提示(可选) + +- 将 **`AFS_EMBED_CAPACITY`** 设为较小值(例如 **`100`**)可更快触发 **嵌入目录替换 / 淘汰** 相关逻辑,便于缩短调试周期;正式回归再恢复 **`250000`**(或业务约定值)。 + +## 执行约定 + +1. **顺序**:**`config_server` → `visual_only` → `normal` → `mmmu_val`(`lmms_eval`)**,前三步不可颠倒;**`mmmu_val` 未完成不得视为本轮通过**。 +2. **`mmmu_val`**:须在 **`normal` 就绪** 之后、**关停 `normal` 之前** 跑完(依赖 **`8089`** 与 **`OPENAI_API_BASE`**)。**`model_version` 与 `MODEL_DIR` 必须一致**。 +3. **关停**:**`mmmu_val` 成功或失败均已落盘**(日志与 **`summary.txt`**)后,依次结束 **`normal`、`visual_only`、`config_server`**;**`config_server` 退出后,其内部在 `6000` 上暴露的 Redis 随之停止**,释放端口与 GPU。 +4. **失败**:将摘要写入 **`summary.txt`**(含 **`lmms_eval` 退出码**、**`lmms_eval_console.log`** 末尾),并在对话中给出关键日志与端口状态。 diff --git a/skills/test_model/qwen3.5-0.8b-gsm8k-scenarios/SKILL.md b/skills/test_model/qwen3.5-0.8b-gsm8k-scenarios/SKILL.md new file mode 100644 index 0000000000..15f79285d3 --- /dev/null +++ b/skills/test_model/qwen3.5-0.8b-gsm8k-scenarios/SKILL.md @@ -0,0 +1,199 @@ +--- +name: test-model-qwen3.5-0.8b-gsm8k-scenarios +description: >- + LightLLM Qwen3.5-0.8B GSM8K multi-scenario regression: five isolated runs (baseline + api_server, prefill cudagraph, linear-attention cache flags, CPU cache plus linear-att, + disk cache with LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH). Each scenario uses api_server + tp 2 port 8089, then lm_eval local-completions gsm8k batch 500. Scenarios 4 and 5 run + lm_eval twice for cache warm hit. Per-scenario LOG_DIR, server.log, eval logs, summary.txt. + GPUs from nvidia-smi; port listen readiness not health; clear proxies and set no_proxy. + Default MODEL_DIR HuggingFace hub snapshot path; default DISK_CACHE_DIR /mtc/test/tmp/ + for scenario 5; ask user for paths if missing or not writable. +--- + +# Qwen3.5-0.8B **多场景 GSM8K 回归** + +覆盖五种 **`api_server` 配置**:**基线**、**Prefill CUDA Graph**、**Linear-Attention 缓存参数**、**CPU Cache 与 Linear-Att 组合**、**Disk Cache(含环境变量)**。每种配置单独起服务并完成 **`lm_eval`**,互不混用日志。 + +**测试标识**:同一 **`MODEL_DIR`**(Qwen3.5-0.8B 权重)下,按场景顺序执行:**启动 `api_server` → 确认端口监听与服务日志正常 → 执行 `lm_eval`**。场景 **4、5** 在相同服务配置下 **`lm_eval` 连续执行两次**(缓存预热与命中后行为/耗时对照)。 + +**端口**:**`8089`**(默认,与 **`PORT`** 一致)。 + +**算力**:**`--tp 2`**,需要 **2 张物理 GPU**。 + +**评测**:**`lm_eval`**,**`--tasks gsm8k`**,**`--batch_size 500`**,**`model`** 为 **`qwen/Qwen3.5-0.8B`**。**`--model_dir` 与 `model_args` 中的 `tokenizer` 必须为同一目录路径(即 `MODEL_DIR`)**。 + +## 场景总览 + +| # | 名称 | `api_server` 相对上一场景的增量 | `lm_eval` | +|---|------|----------------------------------|-----------| +| 1 | 基线 | **`--model_dir` / `--tp 2` / `--port`** | 1 次 | +| 2 | Prefill CUDA Graph | **`--enable_prefill_cudagraph`** | 1 次 | +| 3 | Linear-Attention 参数 | **`--linear_att_cache_size 10`**、**`--linear_att_hash_page_size 256`**、**`--linear_att_page_block_num 2`**、**`--max_total_token_num 270000`** | 1 次 | +| 4 | CPU Cache + Linear-Att | 在场景 3 同类参数基础上增加 **`--enable_cpu_cache`**、**`--cpu_cache_storage_size 128`**(**`--max_total_token_num` 仍为 `270000`**) | **2 次** | +| 5 | Disk Cache | **`LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128`**;**`--linear_att_cache_size 128`** 等一组参数,及 **`--enable_cpu_cache`**、**`--enable_disk_cache`**、**`--disk_cache_dir`** 等(见下文命令块) | **2 次** | + +## 日志目录(含 `summary.txt`) + +- **每个场景**使用独立 **`LOG_DIR`**(建议绝对路径,并带场景编号或时间戳)。 +- **`api_server`**:标准输出与标准错误写入 **`"${LOG_DIR}/server.log"`**(推荐使用 **`nohup … >> … 2>&1 &`**)。 +- **`lm_eval`**:默认写入 **`"${LOG_DIR}/eval_gsm8k.log"`**;同一服务下的第二次评测写入 **`"${LOG_DIR}/eval_gsm8k_run2.log"`**(场景 4、5)。 +- **`summary.txt`**:记录本场景完整启动参数、**`lm_eval` 命令摘要**、端口与日志就绪情况、两轮评测目的与结论(若适用)、异常与最终结论。 + +## 启动前检查 + +1. **显卡**:执行 **`nvidia-smi`**,按占用选定 2 张卡后 **`export CUDA_VISIBLE_DEVICES='i,j'`**(**不要写死卡号**)。 +2. **端口**:每轮启动前确认 **`8089`**(或当前 **`PORT`**)未被占用(例如 **`ss -tlnp`**、**`lsof -i :8089`**);上一轮结束后须 **终止对应 `api_server` 进程** 再启动下一轮。 +3. **`MODEL_DIR`**:见 **「路径约定」**;启动前执行 **`test -d "${MODEL_DIR}"`**;若路径无效或服务报路径类错误,按该节处理。 +4. **`DISK_CACHE_DIR`(仅场景 5)**:见 **「路径约定」**;须为可写目录;先 **`mkdir -p "${DISK_CACHE_DIR}"`**,仍不可写则按该节处理。 +5. **代理**:每次启动 **`api_server`** 或执行 **`lm_eval`** 之前,将 **`http_proxy` / `https_proxy` 置空**;执行 **`lm_eval`** 时配置 **`no_proxy`**(见评测命令块)。 + +## 路径约定(`MODEL_DIR` 与 `DISK_CACHE_DIR`) + +**原则**:下列 **默认路径** 与历史 **`test/acc/test_qwen3.5.sh`** 一致,可作为首轮试跑起点。若目录不存在、不可读、权重加载失败,或磁盘缓存路径不可写,**不得在未向用户确认的情况下反复更换路径盲试**;应 **向用户询问** 本机可用的 **`MODEL_DIR` / `DISK_CACHE_DIR` 绝对路径**,在收到答复后更新环境变量,并在 **`summary.txt`** 中记录最终采用的路径。 + +### `MODEL_DIR` + +- **`--model_dir`** 与 **`lm_eval` 的 `tokenizer` 字段** 必须为 **同一字符串**(本 skill 中均记为 **`MODEL_DIR`**)。 +- **默认路径(HuggingFace Hub 本地缓存示例)**:以下 **`snapshots/` 下目录名随实际下载版本可能变化**;若本机不存在该路径,则默认值不适用,须改用本机真实路径或询问用户。 + +```bash +export MODEL_DIR='/root/.cache/huggingface/hub/models--Qwen--Qwen3.5-0.8B/snapshots/2fc06364715b967f1860aea9cf38778875588b17' +``` + +- **备选**:若权重部署在统一管理目录(例如 **`/mtc/models/Qwen3.5-0.8B`**),且 **`test -d`** 通过,可 **`export MODEL_DIR='/mtc/models/Qwen3.5-0.8B'`**。 + +### `DISK_CACHE_DIR`(仅场景 5:`--disk_cache_dir`) + +- **默认路径**: + +```bash +export DISK_CACHE_DIR='/mtc/test/tmp/' +``` + +- 场景 5 启动 **`api_server`** 前执行 **`mkdir -p "${DISK_CACHE_DIR}"`**。若父目录不可创建、无写权限或不符合运维规范,**向用户询问** 合适的可写目录后再 **`export`**。 + +## 可变项 + +| 变量 | 含义 | +|------|------| +| `LOG_DIR` | 当前场景的日志根目录(**`server.log` / `eval_gsm8k*.log` / `summary.txt`**)。 | +| `MODEL_DIR` | **`--model_dir`**;**`lm_eval` 的 `tokenizer`**。默认路径与失败时处理见 **「路径约定」**。 | +| `PORT` | HTTP 端口,默认 **`8089`**。 | +| `BIND_URL_HOST` | **`lm_eval` 中 `base_url` 的主机名**;本机常用 **`127.0.0.1`** 或 **`localhost`**。 | +| `CUDA_VISIBLE_DEVICES` | 2 个物理 GPU 索引(逗号分隔)。 | +| `DISK_CACHE_DIR` | 场景 5 的 **`--disk_cache_dir`**。默认 **`/mtc/test/tmp/`**;不可写或不可用时见 **「路径约定」**。 | + +**开跑前导出示例**(按需修改引号内路径): + +```bash +export LOG_DIR='〈场景日志目录,每场景换新目录〉' +export MODEL_DIR='/root/.cache/huggingface/hub/models--Qwen--Qwen3.5-0.8B/snapshots/2fc06364715b967f1860aea9cf38778875588b17' +export DISK_CACHE_DIR='/mtc/test/tmp/' +export PORT=8089 +export BIND_URL_HOST='127.0.0.1' +# export CUDA_VISIBLE_DEVICES='6,7' +``` + +## 服务就绪判定 + +**不要使用 HTTP health 接口作为唯一就绪依据**。应结合:**`PORT` 是否处于 LISTEN 状态**、**`server.log` 是否出现致命错误**;可约 **每 20 秒** 查看一次日志直至可接受评测或确认失败。 + +## `lm_eval` 命令模板(单次) + +服务就绪后执行;场景 **4、5** 在**同一 `api_server` 生命周期内**再执行一次,并将第二次输出重定向到 **`eval_gsm8k_run2.log`**。 + +```bash +export http_proxy= +export https_proxy= + +export no_proxy=localhost,127.0.0.1,0.0.0.0,::1,${BIND_URL_HOST} + +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 \ +lm_eval --model local-completions \ + --model_args "{\"model\":\"qwen/Qwen3.5-0.8B\", \"base_url\":\"http://${BIND_URL_HOST}:${PORT}/v1/completions\", \"max_length\": 16384, \"tokenizer\":\"${MODEL_DIR}\"}" \ + --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ + >> "${LOG_DIR}/eval_gsm8k.log" 2>&1 +``` + +第二次(场景 4、5):将末尾重定向改为 **`>> "${LOG_DIR}/eval_gsm8k_run2.log" 2>&1`**,并在 **`summary.txt`** 中说明两次运行的目的(例如缓存预热与命中后对照)。 + +## 各场景 `api_server` 命令模板 + +以下命令块仅列出 **`api_server` 参数差异**。实际执行时须在 **`export http_proxy=`、`export https_proxy=`** 之后,按仓库其它 acc 测试惯例自行补全:**`LOADWORKER=18 CUDA_VISIBLE_DEVICES=…`**、**`nohup`**、以及 **`>> "${LOG_DIR}/server.log" 2>&1 &`**。 + +### 场景 1:基线 + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" +``` + +### 场景 2:Prefill CUDA Graph + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" \ + --enable_prefill_cudagraph +``` + +### 场景 3:Linear-Attention 参数 + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" \ + --linear_att_cache_size 10 \ + --linear_att_hash_page_size 256 \ + --linear_att_page_block_num 2 \ + --max_total_token_num 270000 +``` + +### 场景 4:CPU Cache + Linear-Attention(`lm_eval` 两次) + +```bash +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" \ + --linear_att_cache_size 10 \ + --linear_att_hash_page_size 256 \ + --linear_att_page_block_num 2 \ + --max_total_token_num 270000 \ + --enable_cpu_cache \ + --cpu_cache_storage_size 128 +``` + +### 场景 5:Disk Cache(环境变量 + `lm_eval` 两次) + +在 **`python`** 进程前设置 **`LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128`**(与历史脚本一致,使子进程继承该变量): + +```bash +LIGHTLLM_DISK_CACHE_PROMPT_LIMIT_LENGTH=128 \ +python -m lightllm.server.api_server \ + --model_dir "${MODEL_DIR}" \ + --tp 2 \ + --port "${PORT}" \ + --linear_att_cache_size 128 \ + --linear_att_hash_page_size 256 \ + --linear_att_page_block_num 32 \ + --max_total_token_num 270000 \ + --enable_cpu_cache \ + --cpu_cache_storage_size 32 \ + --enable_disk_cache \ + --disk_cache_storage_size 512 \ + --disk_cache_dir "${DISK_CACHE_DIR}" +``` + +## 执行约定 + +1. **场景顺序**:按 **1 → 2 → 3 → 4 → 5** 执行;每步 **先停止上一场景的 `api_server`**,使用 **新的 `LOG_DIR`**。 +2. **`MODEL_DIR` 与 `DISK_CACHE_DIR`**:遵循 **「路径约定」**;**`summary.txt`** 记录最终采用的路径。 +3. **场景 4、5**:在同一服务配置下 **`lm_eval` 执行两次**,并保留两次日志文件以便对比。 +4. **收尾**:全部场景结束后,确保 **`api_server` 进程已结束**,释放 GPU 与端口。 +5. **失败处理**:将错误摘要写入 **`summary.txt`**,并在对话中给出关键日志信息。 \ No newline at end of file diff --git a/test/acc/test_deepseekr1.sh b/test/acc/test_deepseekr1.sh index 899020ce42..0d2df72d20 100644 --- a/test/acc/test_deepseekr1.sh +++ b/test/acc/test_deepseekr1.sh @@ -2,4 +2,4 @@ LOADWORKER=18 python -m lightllm.server.api_server --batch_max_tokens 6000 --mod -HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ No newline at end of file +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384, "tokenizer":"/mtc/models/DeepSeek-R1"}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ No newline at end of file diff --git a/test/acc/test_deepseekr1_mtp.sh b/test/acc/test_deepseekr1_mtp.sh index ec4ce71984..7b511e41ac 100644 --- a/test/acc/test_deepseekr1_mtp.sh +++ b/test/acc/test_deepseekr1_mtp.sh @@ -1,6 +1,6 @@ LOADWORKER=18 python -m lightllm.server.api_server --model_dir /mtc/models/DeepSeek-R1 --tp 8 --port 8089 --mem_fraction 0.75 --batch_max_tokens 6000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 -HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384, "tokenizer":"/mtc/models/DeepSeek-R1"}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code # 帮我写一段提示词,告诉AI单独一个一个的进行上述测试的启动服务,然后再执行评测脚本,将结果写入out.txt 中,注意需要标记启动的参数和结果信息。不要用health 接口去判断服务是否启动,直接探测端口是否处于listen状态即可, 执行评测命令的时候,需要用no_proxy 将本地local ip 排除。 # 不要写额外的脚本来启动服务,就是单独一个一个的按照上面的描述启动服务,然后再执行评测脚本,然后注意等待服务启动完成,可以20s检测一次其控制台输出,看是否启动完成,还是启动报错。 diff --git a/test/acc/test_deepseekr1_mtp_ep.sh b/test/acc/test_deepseekr1_mtp_ep.sh index c1dd3bc508..29c7515b27 100644 --- a/test/acc/test_deepseekr1_mtp_ep.sh +++ b/test/acc/test_deepseekr1_mtp_ep.sh @@ -1,19 +1,19 @@ -LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --max_req_total_len 56000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 32 --confirm_run_unsafe_code -LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_tpsp_mix_mode +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --max_req_total_len 56000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_tpsp_mix_mode HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 32 --confirm_run_unsafe_code -LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --max_req_total_len 56000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 32 --confirm_run_unsafe_code -LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap --enable_dp_prefill_balance +LOADWORKER=18 NUM_MAX_DISPATCH_TOKENS_PER_RANK=256 python -m lightllm.server.api_server --enable_ep_moe --model_dir /mtc/models/DeepSeek-R1 --tp 8 --dp 8 --port 8089 --max_total_token_num 60000 --graph_max_batch_size 16 --batch_max_tokens 6000 --max_req_total_len 56000 --mtp_mode eagle_with_att --mtp_draft_model_dir /mtc/models/DeepSeek-R1-NextN --mtp_step 2 --enable_prefill_microbatch_overlap --enable_decode_microbatch_overlap --enable_dp_prefill_balance HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-R1", "base_url":"http://localhost:8089/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 32 --confirm_run_unsafe_code diff --git a/test/acc/test_deepseekv32_ep.sh b/test/acc/test_deepseekv32_ep.sh index 815d31c5e8..c34f546022 100644 --- a/test/acc/test_deepseekv32_ep.sh +++ b/test/acc/test_deepseekv32_ep.sh @@ -1,6 +1,4 @@ -LOADWORKER=14 python -m lightllm.server.api_server --model_dir /mtc/sufubao/DeepSeek-V3.2 --tp 8 --graph_max_batch_size 32 --tool_call_parser deepseekv32 --mem_fraction 0.8 --reasoning_parser deepseek-v3 --dp 4 --enable_ep_moe +LOADWORKER=14 python -m lightllm.server.api_server --model_dir /mtc/models/DeepSeek-V3.2 --tp 8 --graph_max_batch_size 32 --tool_call_parser deepseekv32 --mem_fraction 0.8 --reasoning_parser deepseek-v3 --dp 8 --enable_ep_moe --port 8000 -HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-V3.2", "base_url":"http://localhost:8000/v1/completions", "max_length": 16384}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code - -export no_proxy="localhost,127.0.0.1,::1" \ No newline at end of file +HF_ALLOW_CODE_EVAL=1 HF_DATASETS_OFFLINE=0 no_proxy=127.0.0.1,localhost,::1 lm_eval --model local-completions --model_args '{"model":"deepseek-ai/DeepSeek-V3.2", "base_url":"http://localhost:8000/v1/completions", "max_length": 16384, "tokenizer":"/mtc/models/DeepSeek-V3.2"}' --tasks gsm8k --batch_size 500 --confirm_run_unsafe_code \ No newline at end of file