Files
CTI-Inference-Opt/CLAUDE.md
T

201 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 项目概述
百度商业AI技术创新大赛 (CTI) 2026 — **生成式推荐广告排序推理性能优化**
目标:给定 GRAB Transformer 模型,在**不改模型结构、不在测试集训练**的前提下,极致优化推理性能。量化/稀疏/剪枝明确允许。
## 环境与常用命令
```powershell
# 激活虚拟环境
.\.venv\Scripts\Activate.ps1
# 本地运行推理(需要 dataset/ 和 ckpt.pt
.\.venv\Scripts\python.exe 代码\code\infer.py
.\.venv\Scripts\python.exe 代码\code\infer.py --ckpt path/to/ckpt.pt
# AI Studio SDK(下载数据集、提交)
.\.venv\Scripts\aistudio.exe download --dataset <id> --local_dir ./dataset --token <token>
.\.venv\Scripts\aistudio.exe download --model <id> --local_dir . --token <token>
# 打包提交
cd 代码/code && zip -r ../../submit.zip infer.py requirements.txt build_env.sh
```
本地环境仅装 `numpy` + `tqdm` + `aistudio-sdk`(轻量),完整 PyTorch 依赖见 `代码/code/requirements.txt`,训练/推理在服务端跑。
## 代码架构
```
infer.py (单文件,~730 行,所有逻辑集中于此)
├── 数据加载层
│ ├── _detect_has_clk() — 检测 CSV 是否有 clk 列
│ ├── load_sample_files() — 加载 CSV → item_dict + user_seq
│ ├── load_logids_from_file() — 快速提取文件中所有 logid
│ └── CTRUserDataset(Dataset) — 按用户组织的 CTR 数据集
│ └── make_collate_fn() — 将用户样本拼接为 batch(含 slot 特征展开)
├── 模型层
│ ├── RepEncoder — Slot-wise Embedding → LayerNorm → Linear
│ │ └── Embedding(5M vocab, 512d) × 28 slots → segment_reduce(sum) → concat
│ ├── TransformerEncoder (8 层)
│ │ ├── QKV Projection → Multi-Head Attention (scaled_dot_product)
│ │ ├── SMoE FFN8 experts, Top-2 gating, 每层独立)
│ │ └── Pre-LayerNorm + Residual
│ ├── CTRModel — RepEncoder + Transformer → Linear → logit
│ │ └── Causal mask: 同一用户的 tokens 因果遮罩,不同用户隔离
│ └── load_model(ckpt_path, device) — 模型构建 + 权重加载入口
├── 推理循环 (main)
│ ├── 数据加载(优先缓存 shard_*.pt
│ ├── 逐 batch 推理 + 计时(只计 model(batch) 耗时)
│ └── 按 test.csv 顺序写 predict.txt
└── 打分工具
└── _cal_score() — AUC + PCOC + latency → score_all
```
**模型参数规模**Embedding 5M×512 + 8 层 Transformer (d_model=512, n_heads=8, dim_ff=1024) × MoE(8 experts) ≈ ~6.5M~11.3M 参数。
## 关键接口(评测系统调用契约)
评测系统通过 `from infer import ...` 加载代码,以下是**必须**对齐的接口(来自 `代码/任务提交接口说明.md`):
| 接口 | 签名 | 说明 |
|------|------|------|
| `load_sample_files` | `(sample_files_list: List[Path]) -> (item_dict, user_seq)` | 数据加载 |
| `CTRTestSeqDataset` | `(test_logids_ordered, item_dict, user_seq, max_feasign_per_slot, max_ctx_len)` | **必须有 `max_slot_id` 属性** |
| `make_collate_fn` | `(max_slot_id) -> Callable` | DataLoader 的 collate_fn |
| `load_model` | `(ckpt_path: Path) -> (model, device)` | 第一个参数是 Path |
| `move_batch_to_device` | `(batch, device) -> batch` | |
| `model(batch)` | `-> (logits, moe_loss)` | logits 经 sigmoid 后是点击概率 |
**致命不匹配**baseline `infer.py` 当前存在,提交前必须修复):
1. 类名 `CTRUserDataset` → 应为 `CTRTestSeqDataset`
2. 构造参数 `pred_logids` → 应为 `test_logids_ordered`,缺少 `max_ctx_len`
3. `load_model(device='cuda:0', ckpt_path=None)` → 应为 `load_model(ckpt_path, device='cuda:0')`Path 作为第一参数)
## 提交规范
### 压缩包结构
```
submit.zip
├── infer.py # 必需,实现上述全部接口
├── requirements.txt # 可选,阿里云 PyPI 镜像安装
└── build_env.sh # 可选,超时 720s,非 0 退出即失败
```
### 硬约束(任一违反 → 总分 0)
- 推理耗时 < 300s(只计 `model(batch)` 逐 batch 累加)
- AUC ∈ [0.65, 1.0]PCOC ∈ [0.85, 1.15]
- 压缩包内**不能**有 `dataset/``ckpt.pt`
- 包后缀只能是 `.zip`/`.tar.gz`/`.tar`,解压后文件在根目录
- 每天最多提交 10 次
### 总分公式
```
score_latency = max(0, (300 - latency) / 300)
score_model = ((AUC - 0.65) * 1000 + (0.15 - |PCOC - 1|) / 0.15 * 10) / 360
score_all = score_latency * 70 + score_model * 30
```
### 评测环境
- **硬件**: NVIDIA A800 (80GB, SM80)
- **软件**: Python 3.10 + PyTorch 2.6.0
- **评测数据集 ≠ baseline 数据集**(AUC 天然有差异)
### 优化合规边界(来自官方 Q&A)
| 操作 | 状态 | 说明 |
|------|------|------|
| 量化(FP16/INT8 | ✅ 允许 | |
| Flash Attention | ✅ 允许 | 数学等价实现 |
| 参数级剪枝/稀疏化(权重置零/mask,形状不变) | ✅ 允许 | 权重矩阵大小、层数、head 数、FFN 维度均不变 |
| 减少 Transformer 层数 | ❌ 违规 | 改变组网结构 |
| 减少 hidden 维度 | ❌ 违规 | 改变张量形状 |
| 删除 attention head | ❌ 违规 | 改变组网结构 |
| 减少 FFN channel | ❌ 违规 | 改变组网结构 |
| 序列采样/截断 | ❌ 违规 | |
| 对测试集训练 | ❌ 违规 | |
**策略指标以 baseline 为上限**,指标下降会扣分,超出范围直接 0 分。
## 数据分析
### 数据规模
| 维度 | 数值 |
|------|------|
| 历史数据 | 15 文件 × ~650K 行 = **923 万行**15GB |
| 测试集 | **7,774 条预测**13MB |
| 缓存 batch | 9 个 shard17GB,共 **2,039 batch** |
| Slot 数量 | 1-2828 个特征槽) |
### 数据格式
```
# History5 列,含 clk:
logid,userid,adid,clk,timestamp,sign:slot,...
# Test4 列,无 clk:
logid,userid,adid,timestamp,sign:slot,...
```
### 特征分布特征
1. **Slot 28 是瓶颈槽位**:每个样本含 30-50 个 `sign:28` 特征,远超其他 slot。`segment_reduce` 在 slot 28 上占据 RepEncoder 最大开销。
2. **Slot 19 高度冗余**:同一样本内连续出现大量相同 `sign:19`(如 `96:19` 重复 40+ 次)。在 `segment_reduce(sum)` 中,N 个相同 sign 等价于 `N × emb`,但代码独立查表 N 次再求和,浪费 embedding 带宽。
3. **特征极度稀疏**:百万级 sign id,每个样本仅 100-200 个 sign。Embedding 查表是主要内存瓶颈。
### 数据驱动的可优化方向
| 方向 | 合规性 | 预估收益 | 说明 |
|------|--------|----------|------|
| Slot 19 同值合并 | ⚠️ | 小 | N 个相同 sign 合并为 `N × emb`,减少 embedding 查表次数。属数据预处理灰区 |
| Slot 28 segment_reduce 融合 | ✅ | 中 | 将 slot 28 的大量 sign 预先按 offset 分桶,减少 kernel launch |
| Embedding 查表带宽 | ✅ | 小 | 已用 FP16embedding 5M×512 约 5GB |
## 优化路线图(来自 `推理优化方案.md`)
Baseline 数据:推理 229sAUC 0.759PCOC 1.110,得分 25.85。
1.**接口对齐** — 确认能在评测系统跑通(得分 > 0)
2.**FP16 量化**`model.half()`Embedding 保留 FP32152s
3.**Flash Attention** — 替换 `scaled_dot_product``F.scaled_dot_product_attention`94.5s
4.**inference_mode()** — 替代 `no_grad()`92.5s+2s 小幅提升)
5.**torch.compile** — reduce-overhead 和 default 模式均因动态 batch 形状反效果,彻底放弃
6.**MoE Top-1 gating** — PCOC 从 1.059 炸到 2.075,已回退
7.**2:4 结构化稀疏** — PCOC 炸到 2.067,耗时反增 265s。to_sparse_semi_structured 与 nn.Linear 不兼容
8.**SMoE 消除 GPU 同步** — 移除 mask.any()64 次 GPU→CPU 同步/forward),88.1s
CUDA Graph 已评估并放弃(batch 形状不固定,不适用)。
每步完成后必须在 AI Studio 提交验证,AUC/PCOC 不达标立即回退。
## 关键文件
| 路径 | 用途 |
|------|------|
| `代码/code/infer.py` | 推理主脚本(提交的核心文件) |
| `代码/code/requirements.txt` | 服务端依赖(torch 2.6.0 + CUDA 12.4 |
| `代码/code/build_env.sh` | 环境构建脚本(目前为空壳) |
| `代码/任务提交接口说明.md` | 官方接口规范 |
| `推理优化方案.md` | 完整优化方案(含合规审查) |
| `论文/GRAB_*.pdf` | GRAB 论文(baseline 模型) |
| `论文/HSTU_*.pdf` | HSTU 论文(架构基础) |
| `.gitignore` | 排除 ckpt.pt, dataset/, *.zip, .venv/ |
## 提交记录
| 日期 | 提交次数 | 得分 | AUC | PCOC | 耗时 | 优化手段 | 备注 |
|------|----------|------|-----|------|------|----------|------|
| 06/13 | 12 | **58.49** | 0.7526 | 1.059 | 88.1s | + SMoE 消除 GPU 同步 | **当前最优** |
| 06/13 | 11 | 0 | 0.748 | 2.067 | 265.5s | 2:4 sparse | ❌ 炸毁 |
| 06/13 | 10 | 57.45 | 0.7526 | 1.059 | 92.5s | + inference_mode | |
| 06/13 | 9 | 51.42 | 0.7525 | 1.059 | 118.4s | + compile(default) | 反效果 |
| 06/12 | 8 | 0 | 0.736 | 2.075 | 119.6s | MoE k=1 + compile | PCOC 炸毁 |
| 06/12 | 6 | 56.98 | 0.7526 | 1.059 | 94.5s | + Flash Attention | |
| 06/12 | 3 | 43.55 | 0.7525 | 1.059 | 152s | + FP16 量化 | |