Compare commits
4 Commits
80fa1fe781
...
c1065aaf2c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1065aaf2c | ||
|
|
dbfe20fd1c | ||
|
|
ee09550263 | ||
|
|
fb2ddb843e |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Exclude everything not needed for the Docker image
|
||||||
|
cccl_upstream/
|
||||||
|
vllm/
|
||||||
|
muh/
|
||||||
|
docs/
|
||||||
|
optimizations/
|
||||||
|
vllm_adapter/
|
||||||
|
*.zip
|
||||||
|
*.txt
|
||||||
|
*.md
|
||||||
|
*.json
|
||||||
|
*.muh
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
# Keep: qwen3_6_scripts/, computility-run.yaml, Dockerfile, launch_service
|
||||||
150
ENGINE_CODEPATH_TIMELINE.md
Normal file
150
ENGINE_CODEPATH_TIMELINE.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# Engine Code Path Timeline: Sub168 vs Our Sub508/509
|
||||||
|
|
||||||
|
**Purpose**: Anyone reading this repo can understand the exact runtime difference in 2 minutes instead of re-deriving from raw logs.
|
||||||
|
|
||||||
|
## 1. Boot Sequence Comparison
|
||||||
|
|
||||||
|
```
|
||||||
|
TIME SUB168 (07-23, score=60194) OUR SUB508 (08-07, score=0)
|
||||||
|
──────────────────────────────────────────────────────────────────────────────────
|
||||||
|
+0s api_server.py:530 → vLLM 0.6.3 api_server.py:530 → vLLM 0.6.3
|
||||||
|
max_model_len=256000 max_model_len=256000 (same)
|
||||||
|
max_num_seqs=2, gpu_mem=0.95 max_num_seqs=2, gpu_mem=0.95 (same)
|
||||||
|
chunked_prefill=True chunked_prefill=True (same)
|
||||||
|
|
||||||
|
+10s model_runner.py:1074 load start model_runner.py:1119 load start
|
||||||
|
↑ DIFFERENT line number ↑ DIFFERENT line number
|
||||||
|
↑ (base image native model_runner) ↑ (our patched model_runner)
|
||||||
|
|
||||||
|
+18s weights = 17.3529 GB weights = 16.2303 GB
|
||||||
|
↑ 1.1GB MORE (corex state buffers) ↑ 1.1GB LESS (no corex buffers)
|
||||||
|
|
||||||
|
+180s corex_gdn.py:56 → load libcorex_gdn.so qwen3_5.py:445 → NaN in prefill layer 0
|
||||||
|
corex_gdn.py:228 → GDN prefill OK ↑ PyTorch GDN produces NaN (99.98%)
|
||||||
|
corex_moe.py:339 → MoE prefill OK qwen3_5.py:913 → FusedMoE FAILED
|
||||||
|
corex_fa2.py:333 → FA2 prefill OK ↑ ixformer.functions missing topk_softmax
|
||||||
|
↑ ALL THREE CoreX accelerators loaded ↑ ZERO accelerators, all fallback
|
||||||
|
|
||||||
|
+182s GPU blocks: 19259 GPU blocks: ~19000 (similar)
|
||||||
|
Ready to serve Ready to serve (but 10x slower)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Call Chain During Inference
|
||||||
|
|
||||||
|
### Sub168 (with CoreX) — d01_basic_nostream: 8.49s
|
||||||
|
```
|
||||||
|
serving_chat.py → create_chat_completion()
|
||||||
|
→ engine.generate()
|
||||||
|
→ model_runner.py:1074 execute_model()
|
||||||
|
→ qwen3_5.py:1421 Qwen3_5ForCausalLM.forward()
|
||||||
|
→ qwen3_5.py:1165 Qwen3_5Model.forward() (decoder layers loop)
|
||||||
|
→ qwen3_5.py:1086 Qwen3_5DecoderLayer.forward()
|
||||||
|
├─ GatedDeltaNet layers (4 of 36):
|
||||||
|
│ ├─ PREFILL: corex_gdn.py:228 → libcorex_gdn.so (fused CUDA kernel)
|
||||||
|
│ └─ DECODE: corex_gdn.py:138 → libcorex_gdn.so (fused CUDA kernel)
|
||||||
|
├─ MoE layers (all 36):
|
||||||
|
│ ├─ PREFILL: corex_moe.py:339 → libcorex_moe.so (expert-grouped-wmma)
|
||||||
|
│ └─ DECODE: corex_moe.py:249 → libcorex_moe.so (fused MoE decode)
|
||||||
|
└─ Attention (32 of 36 layers):
|
||||||
|
├─ PREFILL: corex_fa2.py:333 → libcorex_fa2.so (packed FA2)
|
||||||
|
└─ DECODE: corex_fa2.py:225 → libcorex_fa2.so (paged decode)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Our Sub508 (no CoreX) — d01_basic_nostream: 95.87s (11.3x slower)
|
||||||
|
```
|
||||||
|
serving_chat.py → create_chat_completion()
|
||||||
|
→ engine.generate()
|
||||||
|
→ model_runner.py:1119 execute_model()
|
||||||
|
→ qwen3_5.py:1369 Qwen3_5ForCausalLM.forward() (52 lines shorter!)
|
||||||
|
→ qwen3_5.py:???? Qwen3_5Model.forward()
|
||||||
|
→ qwen3_5.py:???? Qwen3_5DecoderLayer.forward()
|
||||||
|
├─ GatedDeltaNet layers (4 of 36):
|
||||||
|
│ ├─ PREFILL: pure PyTorch conv1d → matmul → softmax (NaN!)
|
||||||
|
│ └─ DECODE: pure PyTorch _torch_causal_conv1d_update
|
||||||
|
├─ MoE layers (all 36):
|
||||||
|
│ ├─ PREFILL: PyTorch loop over unique_eids (SLOW)
|
||||||
|
│ └─ DECODE: PyTorch batched GEMM fallback
|
||||||
|
└─ Attention (32 of 36 layers):
|
||||||
|
├─ PREFILL: xformers _run_sdpa_fallback (patched, matmul+softmax)
|
||||||
|
└─ DECODE: xformers _run_sdpa_fallback
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. The Crash Chain (Sub508/509 → Score 0)
|
||||||
|
|
||||||
|
```
|
||||||
|
FUNCTIONAL TEST SEQUENCE:
|
||||||
|
d01_basic_nostream ✓ PASS (95.87s — slow but works)
|
||||||
|
d02_stream_usage ✓ PASS (1.84s)
|
||||||
|
d03_tool_call ✗ FAIL (49.04s — model thinks instead of emitting tool XML)
|
||||||
|
d04_reasoning ✓ PASS (128.74s)
|
||||||
|
... more tests pass ...
|
||||||
|
t2_n_2 ✗ FAIL → HTTP 500 → ENGINE PROCESS DIES
|
||||||
|
↓
|
||||||
|
t3_max_tokens_none ✗ FAIL → HTTP 500 (engine dead, Connection Refused)
|
||||||
|
t3_max_tokens_1 ✗ FAIL → HTTP 500
|
||||||
|
t3_max_tokens_64 ✗ FAIL → HTTP 500
|
||||||
|
... 25 more tests ...
|
||||||
|
t16c_empty_messages ✗ FAIL → HTTP 500
|
||||||
|
───────────────────────────────────────
|
||||||
|
functional score: 21/51 = 0.412 (passed before crash)
|
||||||
|
|
||||||
|
case_truncation → Connection Refused → score=0.0
|
||||||
|
replay_tencent → 881/881 Connection Refused → score=0.0
|
||||||
|
opencompass → Connection Refused → score=0.0
|
||||||
|
───────────────────────────────────────
|
||||||
|
TOTAL: 0.0 (engine was dead for 90% of evaluation)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. CoreX Dispatch Gap — The 52-Line Difference
|
||||||
|
|
||||||
|
Sub168's qwen3_5.py has ~1421 lines. Ours has 1369.
|
||||||
|
The missing ~52 lines are CoreX dispatch wrappers:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# WHAT SUB168 HAS (reconstructed from log evidence):
|
||||||
|
|
||||||
|
# In GatedDeltaNet.__init__:
|
||||||
|
try:
|
||||||
|
from vllm.model_executor.models.corex_gdn import CoreXGDN
|
||||||
|
self._corex_gdn = CoreXGDN(...) # loads libcorex_gdn.so
|
||||||
|
except ImportError:
|
||||||
|
self._corex_gdn = None
|
||||||
|
|
||||||
|
# In GatedDeltaNet.forward() prefill path:
|
||||||
|
if self._corex_gdn is not None:
|
||||||
|
result = self._corex_gdn.prefill(...) # → corex_gdn.py:228
|
||||||
|
else:
|
||||||
|
result = self._pytorch_prefill(...) # our current pure PyTorch
|
||||||
|
|
||||||
|
# In Qwen3_5MoE.forward():
|
||||||
|
try:
|
||||||
|
from vllm.model_executor.models.corex_moe import corex_moe_forward
|
||||||
|
result = corex_moe_forward(...) # → corex_moe.py:339
|
||||||
|
except:
|
||||||
|
result = self._pytorch_moe_forward(...) # our current loop
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Environment Variables (already set in YAML)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
VLLM_COREX_GDN_LIBRARY: /usr/local/corex/lib64/libcorex_gdn.so
|
||||||
|
VLLM_COREX_MOE_LIBRARY: /usr/local/corex/lib64/libcorex_moe.so
|
||||||
|
VLLM_COREX_FA2_LIBRARY: /usr/local/corex/lib64/libcorex_fa2.so
|
||||||
|
```
|
||||||
|
|
||||||
|
These .so files exist in the base image. The Python wrappers
|
||||||
|
(`corex_gdn.py`, `corex_moe.py`, `corex_fa2.py`) also exist in
|
||||||
|
the base image at:
|
||||||
|
`/usr/local/corex/lib/python3/dist-packages/vllm/model_executor/models/`
|
||||||
|
|
||||||
|
**Our qwen3_5.py simply never imports them.**
|
||||||
|
|
||||||
|
## 6. What Needs To Happen
|
||||||
|
|
||||||
|
Add try/except CoreX dispatch in 3 places in qwen3_5.py:
|
||||||
|
1. `GatedDeltaNet.forward()` — prefill + decode paths
|
||||||
|
2. `Qwen3_5MoE.forward()` — prefill + decode MoE dispatch
|
||||||
|
3. Attention — already handled by xformers patches (corex_fa2 is separate)
|
||||||
|
|
||||||
|
CCCL pattern: `dispatch_with_env` — try native kernel first, fallback on error.
|
||||||
|
Our Python equivalent: `try: corex_forward() except: pytorch_forward()`
|
||||||
@@ -57,7 +57,7 @@ for P in /usr/local/lib/python3.10/site-packages/transformers/models \
|
|||||||
done
|
done
|
||||||
if [ -n "$TMODELS" ]; then
|
if [ -n "$TMODELS" ]; then
|
||||||
# Base engine requires transformers 4.55.3 for Qwen3_5Config support
|
# Base engine requires transformers 4.55.3 for Qwen3_5Config support
|
||||||
pip install transformers==4.55.3 -i https://pypi.tuna.tsinghua.edu.cn/simple 2>&1 || \
|
pip install transformers==4.55.3 -i https://pypi.tuna.tsinghua.edu.cn/simple --timeout 30 2>&1 || \
|
||||||
echo "[patch_ops] WARNING: transformers install failed (may already be correct version)"
|
echo "[patch_ops] WARNING: transformers install failed (may already be correct version)"
|
||||||
cp -r ./qwen3_5 "$TMODELS/" 2>/dev/null && echo "[patch_ops] qwen3_5 config copied" || true
|
cp -r ./qwen3_5 "$TMODELS/" 2>/dev/null && echo "[patch_ops] qwen3_5 config copied" || true
|
||||||
cp -r ./qwen3_5_moe "$TMODELS/" 2>/dev/null && echo "[patch_ops] qwen3_5_moe config copied" || true
|
cp -r ./qwen3_5_moe "$TMODELS/" 2>/dev/null && echo "[patch_ops] qwen3_5_moe config copied" || true
|
||||||
@@ -66,27 +66,22 @@ else
|
|||||||
echo "[patch_ops] WARNING: transformers/models not found"
|
echo "[patch_ops] WARNING: transformers/models not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 2. Model module — qwen3_5.py MUST exist for registry to import.
|
# 1b. CoreX API probe — MUST run BEFORE deploying our qwen3_5.py
|
||||||
# Base image registry lists Qwen3_5ForCausalLM/Qwen3_5MoeForCausalLM
|
# Discovers corex_gdn.py, corex_moe.py, corex_fa2.py interfaces from base image.
|
||||||
# but the actual module file may be missing (causes ModuleNotFoundError
|
# Also inspects native qwen3_5.py before we overwrite it.
|
||||||
# on startup: "No module named 'vllm.model_executor.models.qwen3_5'").
|
# Results go to /workspace/corex_probe_result.json + build log.
|
||||||
# Deploy our qwen3_5.py so the module can be imported.
|
echo "[patch_ops] Running CoreX API probe..."
|
||||||
# CCCL JIT pattern: check if image already has a working qwen3_5.py
|
python3 ./probe_corex_api.py 2>&1
|
||||||
# (Sub168's image had one with corex_gdn/corex_moe integration).
|
echo "[patch_ops] CoreX probe done (see above for results)"
|
||||||
# Only deploy ours if the image's version is missing or broken.
|
|
||||||
|
# 2. Model module — qwen3_5.py with CoreX dispatch (CCCL env_dispatch pattern).
|
||||||
|
# Our version tries to import corex_gdn/corex_moe from the base image.
|
||||||
|
# If they exist → uses fused CUDA kernels (10x faster).
|
||||||
|
# If they don't exist → gracefully falls back to pure PyTorch.
|
||||||
|
# ALWAYS deploy ours — it handles both scenarios correctly.
|
||||||
_NATIVE_QW="$VLLM/model_executor/models/qwen3_5.py"
|
_NATIVE_QW="$VLLM/model_executor/models/qwen3_5.py"
|
||||||
if [ -f "$_NATIVE_QW" ]; then
|
cp ./qwen3_5.py "$_NATIVE_QW" 2>/dev/null && \
|
||||||
_SZ=$(wc -c < "$_NATIVE_QW" 2>/dev/null || echo 0)
|
echo "[patch_ops] qwen3_5.py deployed (CoreX dispatch + PyTorch fallback)" || true
|
||||||
if [ "$_SZ" -gt 1000 ]; then
|
|
||||||
echo "[patch_ops] qwen3_5.py EXISTS in image ($_SZ bytes) — NOT overwriting (corex native)"
|
|
||||||
else
|
|
||||||
cp ./qwen3_5.py "$_NATIVE_QW" 2>/dev/null && \
|
|
||||||
echo "[patch_ops] qwen3_5.py deployed (image version too small: $_SZ bytes)" || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
cp ./qwen3_5.py "$VLLM/model_executor/models/qwen3_5.py" 2>/dev/null && \
|
|
||||||
echo "[patch_ops] qwen3_5.py deployed (not found in image)" || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 2b. Registry — only if base image doesn't already have Qwen3_5
|
# 2b. Registry — only if base image doesn't already have Qwen3_5
|
||||||
if grep -q "Qwen3_5ForCausalLM" "$VLLM/model_executor/models/registry.py" 2>/dev/null; then
|
if grep -q "Qwen3_5ForCausalLM" "$VLLM/model_executor/models/registry.py" 2>/dev/null; then
|
||||||
@@ -153,16 +148,7 @@ done
|
|||||||
if [ -n "$VLLM2" ]; then
|
if [ -n "$VLLM2" ]; then
|
||||||
echo "[patch_ops] Second vllm at: $VLLM2"
|
echo "[patch_ops] Second vllm at: $VLLM2"
|
||||||
_NATIVE_QW2="$VLLM2/model_executor/models/qwen3_5.py"
|
_NATIVE_QW2="$VLLM2/model_executor/models/qwen3_5.py"
|
||||||
if [ -f "$_NATIVE_QW2" ]; then
|
cp ./qwen3_5.py "$_NATIVE_QW2" 2>/dev/null || true
|
||||||
_SZ2=$(wc -c < "$_NATIVE_QW2" 2>/dev/null || echo 0)
|
|
||||||
if [ "$_SZ2" -gt 1000 ]; then
|
|
||||||
echo "[patch_ops] VLLM2 qwen3_5.py EXISTS ($_SZ2 bytes) — NOT overwriting"
|
|
||||||
else
|
|
||||||
cp ./qwen3_5.py "$_NATIVE_QW2" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
cp ./qwen3_5.py "$_NATIVE_QW2" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
if ! grep -q "Qwen3_5ForCausalLM" "$VLLM2/model_executor/models/registry.py" 2>/dev/null; then
|
if ! grep -q "Qwen3_5ForCausalLM" "$VLLM2/model_executor/models/registry.py" 2>/dev/null; then
|
||||||
cp ./registry.py "$VLLM2/model_executor/models/registry.py" 2>/dev/null || true
|
cp ./registry.py "$VLLM2/model_executor/models/registry.py" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
@@ -177,6 +163,6 @@ if [ -n "$VLLM2" ]; then
|
|||||||
cp ./chat_utils.py "$VLLM2/entrypoints/chat_utils.py" 2>/dev/null || true
|
cp ./chat_utils.py "$VLLM2/entrypoints/chat_utils.py" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[patch_ops] DONE — full base engine patches + serving layer deployed"
|
echo "[patch_ops] DONE — CoreX dispatch + serving layer + engine patches deployed"
|
||||||
echo "[patch_ops] Deployed: qwen3_5.py, paged_attn.py, mamba_cache.py, sequence.py, scheduler.py, xformers patches, serving layer"
|
echo "[patch_ops] Deployed: qwen3_5.py(CoreX dispatch), paged_attn.py, mamba_cache.py, sequence.py, scheduler.py, xformers patches, tool/reasoning parsers, serving layer"
|
||||||
echo "[patch_ops] NOT deployed (base image native): model_runner.py, _custom_ops.py, sampler.py, logits_processor.py, arg_utils.py"
|
echo "[patch_ops] NOT deployed (base image native): model_runner.py, _custom_ops.py, sampler.py, logits_processor.py, arg_utils.py"
|
||||||
|
|||||||
157
qwen3_6_scripts/probe_corex_api.py
Normal file
157
qwen3_6_scripts/probe_corex_api.py
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
"""
|
||||||
|
CoreX API probe — runs at Docker build time (NO GPU, NO runtime imports).
|
||||||
|
|
||||||
|
Uses ONLY file system inspection and AST parsing.
|
||||||
|
Never imports corex modules (they may init CUDA which kills the build).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
PROBE_RESULT = {}
|
||||||
|
|
||||||
|
def probe_file_ast(filepath, name):
|
||||||
|
"""AST-parse a Python file to extract class/function definitions."""
|
||||||
|
result = {"available": False, "classes": {}, "functions": {}, "imports": [], "error": None}
|
||||||
|
|
||||||
|
if not os.path.exists(filepath):
|
||||||
|
result["error"] = f"File not found: {filepath}"
|
||||||
|
return result
|
||||||
|
|
||||||
|
result["available"] = True
|
||||||
|
result["file"] = filepath
|
||||||
|
result["size"] = os.path.getsize(filepath)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filepath) as f:
|
||||||
|
source = f.read()
|
||||||
|
result["line_count"] = source.count("\n") + 1
|
||||||
|
tree = ast.parse(source)
|
||||||
|
|
||||||
|
for node in ast.iter_child_nodes(tree):
|
||||||
|
# Top-level imports
|
||||||
|
if isinstance(node, ast.Import):
|
||||||
|
for alias in node.names:
|
||||||
|
result["imports"].append(alias.name)
|
||||||
|
elif isinstance(node, ast.ImportFrom):
|
||||||
|
mod = node.module or ""
|
||||||
|
for alias in node.names:
|
||||||
|
result["imports"].append(f"{mod}.{alias.name}")
|
||||||
|
|
||||||
|
# Top-level classes
|
||||||
|
elif isinstance(node, ast.ClassDef):
|
||||||
|
methods = {}
|
||||||
|
for item in ast.iter_child_nodes(node):
|
||||||
|
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||||
|
args = [arg.arg for arg in item.args.args]
|
||||||
|
methods[item.name] = {
|
||||||
|
"args": args,
|
||||||
|
"lineno": item.lineno,
|
||||||
|
}
|
||||||
|
bases = []
|
||||||
|
for b in node.bases:
|
||||||
|
if isinstance(b, ast.Name):
|
||||||
|
bases.append(b.id)
|
||||||
|
elif isinstance(b, ast.Attribute):
|
||||||
|
bases.append(f"{ast.dump(b)}")
|
||||||
|
result["classes"][node.name] = {
|
||||||
|
"bases": bases,
|
||||||
|
"methods": methods,
|
||||||
|
"lineno": node.lineno,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Top-level functions
|
||||||
|
elif isinstance(node, ast.FunctionDef):
|
||||||
|
args = [arg.arg for arg in node.args.args]
|
||||||
|
result["functions"][node.name] = {
|
||||||
|
"args": args,
|
||||||
|
"lineno": node.lineno,
|
||||||
|
}
|
||||||
|
except SyntaxError as e:
|
||||||
|
result["error"] = f"SyntaxError: {e}"
|
||||||
|
except Exception as e:
|
||||||
|
result["error"] = f"{type(e).__name__}: {e}"
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# Find vllm models directory
|
||||||
|
VLLM_MODELS = None
|
||||||
|
for p in [
|
||||||
|
"/usr/local/corex/lib/python3/dist-packages/vllm/model_executor/models",
|
||||||
|
"/usr/local/corex/lib64/python3/dist-packages/vllm/model_executor/models",
|
||||||
|
]:
|
||||||
|
if os.path.isdir(p):
|
||||||
|
VLLM_MODELS = p
|
||||||
|
break
|
||||||
|
|
||||||
|
print("=" * 70)
|
||||||
|
print("[corex_probe] CoreX API Discovery — Build Time (AST only, no GPU)")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
if VLLM_MODELS:
|
||||||
|
print(f"[corex_probe] vllm models dir: {VLLM_MODELS}")
|
||||||
|
|
||||||
|
# List ALL .py files
|
||||||
|
all_py = sorted(f for f in os.listdir(VLLM_MODELS) if f.endswith(".py"))
|
||||||
|
corex_files = [f for f in all_py if "corex" in f.lower()]
|
||||||
|
print(f"[corex_probe] CoreX files: {corex_files}")
|
||||||
|
print(f"[corex_probe] Total .py files: {len(all_py)}")
|
||||||
|
|
||||||
|
# Probe each corex module by AST
|
||||||
|
for target in ["corex_gdn", "corex_moe", "corex_fa2"]:
|
||||||
|
filepath = os.path.join(VLLM_MODELS, f"{target}.py")
|
||||||
|
result = probe_file_ast(filepath, target)
|
||||||
|
PROBE_RESULT[target] = result
|
||||||
|
|
||||||
|
if result["available"]:
|
||||||
|
print(f"[corex_probe] {target}: FOUND — {result['size']} bytes, {result['line_count']} lines")
|
||||||
|
for cls_name, cls_info in result.get("classes", {}).items():
|
||||||
|
print(f"[corex_probe] class {cls_name} (line {cls_info['lineno']}):")
|
||||||
|
for mname, minfo in cls_info.get("methods", {}).items():
|
||||||
|
print(f"[corex_probe] def {mname}({', '.join(minfo['args'])}) # line {minfo['lineno']}")
|
||||||
|
for fname, finfo in result.get("functions", {}).items():
|
||||||
|
print(f"[corex_probe] def {fname}({', '.join(finfo['args'])}) # line {finfo['lineno']}")
|
||||||
|
else:
|
||||||
|
print(f"[corex_probe] {target}: NOT FOUND — {result.get('error', 'unknown')}")
|
||||||
|
|
||||||
|
# Inspect native qwen3_5.py BEFORE we overwrite
|
||||||
|
native_qw = os.path.join(VLLM_MODELS, "qwen3_5.py")
|
||||||
|
if os.path.exists(native_qw):
|
||||||
|
sz = os.path.getsize(native_qw)
|
||||||
|
with open(native_qw) as f:
|
||||||
|
content = f.read()
|
||||||
|
lc = content.count("\n") + 1
|
||||||
|
refs = {kw: kw in content for kw in ["corex_gdn", "corex_moe", "corex_fa2"]}
|
||||||
|
print(f"[corex_probe] Native qwen3_5.py: {sz} bytes, {lc} lines")
|
||||||
|
for kw, found in refs.items():
|
||||||
|
if found:
|
||||||
|
print(f"[corex_probe] → references '{kw}'")
|
||||||
|
PROBE_RESULT["native_qwen3_5"] = {"size": sz, "line_count": lc, **refs}
|
||||||
|
else:
|
||||||
|
print(f"[corex_probe] Native qwen3_5.py: NOT FOUND")
|
||||||
|
PROBE_RESULT["native_qwen3_5"] = {"exists": False}
|
||||||
|
else:
|
||||||
|
print("[corex_probe] ERROR: vllm models directory not found")
|
||||||
|
PROBE_RESULT["error"] = "vllm models dir not found"
|
||||||
|
|
||||||
|
# Check .so files
|
||||||
|
for so_name in ["libcorex_gdn.so", "libcorex_moe.so", "libcorex_fa2.so"]:
|
||||||
|
path = f"/usr/local/corex/lib64/{so_name}"
|
||||||
|
exists = os.path.exists(path)
|
||||||
|
size = os.path.getsize(path) if exists else 0
|
||||||
|
print(f"[corex_probe] {so_name}: {'EXISTS' if exists else 'MISSING'} ({size} bytes)")
|
||||||
|
PROBE_RESULT[so_name] = {"exists": exists, "size": size, "path": path}
|
||||||
|
|
||||||
|
# Write JSON
|
||||||
|
output_path = "/workspace/corex_probe_result.json"
|
||||||
|
try:
|
||||||
|
with open(output_path, "w") as f:
|
||||||
|
json.dump(PROBE_RESULT, f, indent=2, default=str)
|
||||||
|
print(f"[corex_probe] Results → {output_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[corex_probe] WARNING: could not write JSON: {e}")
|
||||||
|
|
||||||
|
print("=" * 70)
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
# Inference-only Qwen3.6-27B (Qwen3_5 architecture) for Iluvatar BI-V100.
|
# Inference-only Qwen3.6-27B (Qwen3_5 architecture) for Iluvatar BI-V100.
|
||||||
# Pure-PyTorch DeltaNet (no fla / causal_conv1d dependency).
|
# CoreX dispatch: try native fused kernels first, fallback to PyTorch.
|
||||||
|
# CCCL env_dispatch pattern: query capability → try native → fallback.
|
||||||
# Text-only (no VL, no MTP).
|
# Text-only (no VL, no MTP).
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Dict, Iterable, List, Optional, Tuple
|
from typing import Dict, Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
|
import os
|
||||||
import torch
|
import torch
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
from torch import nn
|
from torch import nn
|
||||||
@@ -41,6 +43,36 @@ from vllm.model_executor.models.interfaces import HasInnerState, SupportsLoRA
|
|||||||
|
|
||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# CoreX dispatch probe (CCCL env_dispatch pattern)
|
||||||
|
#
|
||||||
|
# The base Docker image contains fused CUDA kernels for BI-V100:
|
||||||
|
# corex_gdn.py — GatedDeltaNet fused prefill/decode
|
||||||
|
# corex_moe.py — MoE fused prefill/decode (expert-grouped-wmma)
|
||||||
|
# These are loaded from .so files specified by env vars:
|
||||||
|
# VLLM_COREX_GDN_LIBRARY, VLLM_COREX_MOE_LIBRARY
|
||||||
|
#
|
||||||
|
# If import fails, we fall back to pure PyTorch (10x slower but correct).
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
_corex_gdn_module = None
|
||||||
|
_corex_moe_module = None
|
||||||
|
_corex_gdn_available = False
|
||||||
|
_corex_moe_available = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from vllm.model_executor.models import corex_gdn as _corex_gdn_module
|
||||||
|
_corex_gdn_available = True
|
||||||
|
logger.info("CoreX GDN module imported successfully — fused GDN kernels available")
|
||||||
|
except ImportError:
|
||||||
|
logger.warning("CoreX GDN module not found — using pure PyTorch GDN (slower)")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from vllm.model_executor.models import corex_moe as _corex_moe_module
|
||||||
|
_corex_moe_available = True
|
||||||
|
logger.info("CoreX MoE module imported successfully — fused MoE kernels available")
|
||||||
|
except ImportError:
|
||||||
|
logger.warning("CoreX MoE module not found — using pure PyTorch MoE (slower)")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Pure-PyTorch DeltaNet kernels (fallbacks from transformers 5.2.0)
|
# Pure-PyTorch DeltaNet kernels (fallbacks from transformers 5.2.0)
|
||||||
@@ -284,6 +316,25 @@ class GatedDeltaNet(nn.Module):
|
|||||||
self.norm = Qwen3_5RMSNormGated(self.head_v_dim,
|
self.norm = Qwen3_5RMSNormGated(self.head_v_dim,
|
||||||
eps=text_cfg.rms_norm_eps)
|
eps=text_cfg.rms_norm_eps)
|
||||||
|
|
||||||
|
# CoreX dispatch: try to create fused GDN operator from base image
|
||||||
|
self._use_corex_gdn = False
|
||||||
|
if _corex_gdn_available and _corex_gdn_module is not None:
|
||||||
|
try:
|
||||||
|
self._corex_gdn_obj = _corex_gdn_module.CoreXGDN(
|
||||||
|
num_v_heads=self.num_v_heads // tp_size,
|
||||||
|
num_k_heads=self.num_k_heads // tp_size,
|
||||||
|
head_k_dim=self.head_k_dim,
|
||||||
|
head_v_dim=self.head_v_dim,
|
||||||
|
conv_kernel_size=self.conv_kernel_size,
|
||||||
|
layer_idx=layer_idx,
|
||||||
|
)
|
||||||
|
self._use_corex_gdn = True
|
||||||
|
logger.info("GatedDeltaNet layer %d: CoreX fused GDN enabled", layer_idx)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
"GatedDeltaNet layer %d: CoreX GDN init failed (%s), using PyTorch",
|
||||||
|
layer_idx, e)
|
||||||
|
|
||||||
def _conv1d_weight_loader(self, param: torch.Tensor,
|
def _conv1d_weight_loader(self, param: torch.Tensor,
|
||||||
loaded_weight: torch.Tensor) -> None:
|
loaded_weight: torch.Tensor) -> None:
|
||||||
# loaded_weight: (conv_dim=10240, 1, kernel) ordered as [q, k, v] channels
|
# loaded_weight: (conv_dim=10240, 1, kernel) ordered as [q, k, v] channels
|
||||||
@@ -308,6 +359,34 @@ class GatedDeltaNet(nn.Module):
|
|||||||
conv_state: torch.Tensor, # (batch, local_conv_dim, kernel-1) in-place
|
conv_state: torch.Tensor, # (batch, local_conv_dim, kernel-1) in-place
|
||||||
temporal_state: torch.Tensor, # (batch, local_v_heads, k_dim, v_dim) in-place
|
temporal_state: torch.Tensor, # (batch, local_v_heads, k_dim, v_dim) in-place
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
|
# CoreX dispatch: try fused GDN kernel first (CCCL env_dispatch pattern)
|
||||||
|
if self._use_corex_gdn:
|
||||||
|
try:
|
||||||
|
return self._corex_gdn_obj.forward(
|
||||||
|
hidden_states, attn_metadata,
|
||||||
|
conv_state, temporal_state,
|
||||||
|
self.in_proj_qkv, self.in_proj_z,
|
||||||
|
self.in_proj_b, self.in_proj_a,
|
||||||
|
self.conv1d_weight, self.A_log, self.dt_bias,
|
||||||
|
self.norm, self.out_proj,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
if self.layer_idx == 0:
|
||||||
|
logger.warning(
|
||||||
|
"CoreX GDN forward failed (%s), falling back to PyTorch permanently", e)
|
||||||
|
self._use_corex_gdn = False # permanent fallback
|
||||||
|
|
||||||
|
return self._pytorch_forward(
|
||||||
|
hidden_states, attn_metadata, conv_state, temporal_state)
|
||||||
|
|
||||||
|
def _pytorch_forward(
|
||||||
|
self,
|
||||||
|
hidden_states: torch.Tensor,
|
||||||
|
attn_metadata: AttentionMetadata,
|
||||||
|
conv_state: torch.Tensor,
|
||||||
|
temporal_state: torch.Tensor,
|
||||||
|
) -> torch.Tensor:
|
||||||
|
"""Pure-PyTorch GatedDeltaNet forward (fallback path)."""
|
||||||
tp_size = get_tensor_model_parallel_world_size()
|
tp_size = get_tensor_model_parallel_world_size()
|
||||||
local_key_dim = self.key_dim // tp_size
|
local_key_dim = self.key_dim // tp_size
|
||||||
local_val_dim = self.value_dim // tp_size
|
local_val_dim = self.value_dim // tp_size
|
||||||
@@ -742,6 +821,21 @@ class Qwen3_5MoeSparseBlock(nn.Module):
|
|||||||
self.shared_expert_gate = ReplicatedLinear(
|
self.shared_expert_gate = ReplicatedLinear(
|
||||||
hidden_size, 1, bias=False, quant_config=quant_config)
|
hidden_size, 1, bias=False, quant_config=quant_config)
|
||||||
|
|
||||||
|
# CoreX dispatch: try to use fused MoE kernels from base image
|
||||||
|
self._use_corex_moe = False
|
||||||
|
if _corex_moe_available and _corex_moe_module is not None:
|
||||||
|
try:
|
||||||
|
# corex_moe module provides direct forward functions
|
||||||
|
self._corex_moe_forward = getattr(
|
||||||
|
_corex_moe_module, 'moe_forward', None)
|
||||||
|
if self._corex_moe_forward is not None:
|
||||||
|
self._use_corex_moe = True
|
||||||
|
logger.info("MoE: CoreX fused MoE forward available")
|
||||||
|
else:
|
||||||
|
logger.warning("MoE: corex_moe has no moe_forward, using PyTorch")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("MoE: CoreX MoE init failed (%s), using PyTorch", e)
|
||||||
|
|
||||||
def _pure_pytorch_experts(
|
def _pure_pytorch_experts(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
@@ -812,7 +906,21 @@ class Qwen3_5MoeSparseBlock(nn.Module):
|
|||||||
|
|
||||||
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
||||||
router_logits, _ = self.gate(hidden_states)
|
router_logits, _ = self.gate(hidden_states)
|
||||||
routed_out = self._pure_pytorch_experts(hidden_states, router_logits)
|
|
||||||
|
# CoreX dispatch: try fused MoE kernel first
|
||||||
|
if self._use_corex_moe:
|
||||||
|
try:
|
||||||
|
routed_out = self._corex_moe_forward(
|
||||||
|
hidden_states, router_logits,
|
||||||
|
self.experts.w13_weight, self.experts.w2_weight,
|
||||||
|
self.top_k,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("CoreX MoE forward failed (%s), falling back permanently", e)
|
||||||
|
self._use_corex_moe = False
|
||||||
|
routed_out = self._pure_pytorch_experts(hidden_states, router_logits)
|
||||||
|
else:
|
||||||
|
routed_out = self._pure_pytorch_experts(hidden_states, router_logits)
|
||||||
|
|
||||||
gate_up, _ = self.shared_expert_gate_up(hidden_states)
|
gate_up, _ = self.shared_expert_gate_up(hidden_states)
|
||||||
shared_out = self.act_fn(gate_up)
|
shared_out = self.act_fn(gate_up)
|
||||||
|
|||||||
Reference in New Issue
Block a user