Files

259 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 | ❌ 违规 | 改变组网结构 |
| 序列采样/截断 | ❌ 违规 | |
| 对测试集训练 | ❌ 违规 | |
#### 剪枝细则(来自 Q&A #3
- **结构化剪枝(❌ 不允许)**: 删除整层、整行/整列权重、减少 channel 数等,会改变张量形状或网络拓扑
- **非结构化剪枝(✅ 允许)**: 仅将单个权重置零或 mask 掉,不改变权重矩阵形状;可删除对输出贡献较小、冗余度高的部分,前提是结构不被破坏
> 关键边界:Linear 权重矩阵大小不变、Layer 数量不变、Attention head 数量不变、FFN 维度不变 → 属于合规的参数级剪枝
#### 评测细节
- **计时范围**: 仅 `model(batch)` 逐 batch 累加,`move_batch_to_device` 不计入
- **硬件**: NVIDIA A800 (80GB, SM80)
- **软件**: Python 3.10 + PyTorch 2.6.0
- **评测数据集 ≠ baseline 数据集**(AUC 天然有差异)
- **策略指标以 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.**SMoE 消除 GPU 同步** — 移除 mask.any()64 次 GPU→CPU 同步/forward),88.1s
6.**Expert 权重相似度合并** — 余弦相似度 >0.90 的 expert 合并(权重平均),86.5s
7.**稠密向量化 MoE** — einsum 并行算 8 个 expert + gather 选取,消除 nonzero 同步(PR #1
8.**RepEncoder 融合查表** — 28 slot 值拼成一条做单次 segment_reduce,减 per-batch kernel 启动(PR #1
9.**Searchsorted 因果 mask** — 替代 repeat_interleave(张量repeats),消除最后同步点(PR #1
10.**过滤无关用户** — 跳过不含测试样本的用户,省算力(PR #1
11.**torch.compile** — 四种模式全验证,均反效果。CONFIG 默认 compile=false(注释:实测慢5×)
12.**MoE Top-1 gating** — PCOC 炸毁
13.**2:4 结构化稀疏** — 两次尝试均炸 PCOC
14.**INT8 量化** — CUDA 后端不支持
15.**varlen attention** — 本地 10.3s 但评测端 148s(慢 65%),已回退
16.**FlexAttention** — 比 SDPA 慢,未启用
已验证无效/失败:torch.compile(×4)、2:4 稀疏(×2)、MoE k=1(×2)、INT8、varlen attention、FlexAttention
## 关键文件
| 路径 | 用途 |
|------|------|
| `代码/code/infer.py` | 推理主脚本(提交的核心文件) |
| `代码/code/requirements.txt` | 服务端依赖(torch 2.6.0 + CUDA 12.4 |
| `代码/code/build_env.sh` | 环境构建脚本(目前为空壳) |
| `代码/任务提交接口说明.md` | 官方接口规范 |
| `推理优化方案.md` | 完整优化方案(含合规审查) |
| `论文/GRAB.pdf` | GRAB 论文 OCR markdown |
| `论文/HSTU.pdf` | HSTU 论文 OCR markdown |
| `论文/GRAB_*.pdf` | GRAB 论文(baseline 模型) |
| `论文/HSTU_*.pdf` | HSTU 论文(架构基础) |
| `.gitignore` | 排除 ckpt.pt, dataset/, *.zip, .venv/ |
## 提交记录
| 团队成员用户名 | score | pcoc | score_latency | score_model | latency | auc | 提交状态 | 提交时间 | 备注 |
|--------------|-------|------|---------------|-------------|---------|------|----------|----------|------|
| 刘航宇 | — | — | — | — | — | — | 异常 | 2026-06-12 20:46 | requirements.txt 含 nvidia-* 包,无 Windows 轮子 |
| 刘航宇 | — | — | — | — | — | — | 异常 | 2026-06-12 21:24 | |
| 刘航宇 | 43.55 | 1.0589 | 0.4931 | 0.3013 | 152.08s | 0.7525 | 已完成 | 2026-06-12 21:30 | ✨ 首次 FP16 量化成功(仅 infer.py 提交) |
| 刘航宇 | — | — | — | — | — | — | 异常 | 2026-06-12 21:40 | |
| 刘航宇 | 56.98 | 1.0589 | 0.6849 | 0.3013 | 94.54s | 0.7526 | 已完成 | 2026-06-12 21:44 | SDPA 替换 scaled_dot_product |
| 刘航宇 | 32.54 | 1.0587 | 0.3357 | 0.3013 | 199.28s | 0.7525 | 已完成 | 2026-06-12 21:54 | torch.compile 实验(反效果) |
| 刘航宇 | 0 | 2.0749 | 0.6013 | 0 | 119.62s | 0.7361 | 已完成 | 2026-06-12 22:12 | 2:4 结构化稀疏 → PCOC 炸毁 |
| 刘航宇 | 51.42 | 1.0587 | 0.6055 | 0.3013 | 118.35s | 0.7525 | 已完成 | 2026-06-13 11:54 | inference_mode() 替代 no_grad() |
| 刘航宇 | 57.45 | 1.0589 | 0.6916 | 0.3013 | 92.53s | 0.7526 | 已完成 | 2026-06-13 12:07 | 参数调优 |
| 刘航宇 | 0 | 2.0672 | 0.1150 | 0 | 265.51s | 0.7484 | 已完成 | 2026-06-13 12:21 | 2:4 稀疏第二次 → PCOC 再次炸毁 |
| 刘航宇 | 57.04 | 1.0589 | 0.6858 | 0.3013 | 94.27s | 0.7526 | 已完成 | 2026-06-13 12:41 | 回退稀疏,恢复调优 |
| 刘航宇 | 58.49 | 1.0589 | 0.7065 | 0.3013 | 88.06s | 0.7526 | 已完成 | 2026-06-13 13:17 | 消除 MoE mask.any() GPU 同步 |
| 刘航宇 | 58.45 | 0.9889 | 0.7244 | 0.2579 | 82.67s | 0.7336 | 已完成 | 2026-06-13 13:32 | AUC 骤降 0.019PCOC 0.989 偏低),回退 |
| 刘航宇 | — | — | — | — | — | — | 异常 | 2026-06-13 13:55 | build_env.sh CUDA warmup device='cuda' 失败 |
| 刘航宇 | 0 | 1.3450 | 0 | 0 | 307.44s | 0.7506 | 已完成 | 2026-06-13 14:10 | MoE k=1 → PCOC 炸毁 |
| 刘航宇 | 53.71 | 1.0589 | 0.6381 | 0.3013 | 108.57s | 0.7524 | 已完成 | 2026-06-13 14:21 | 回退 k=2,恢复 |
| 刘航宇 | 55.10 | 1.0587 | 0.6580 | 0.3013 | 102.59s | 0.7525 | 已完成 | 2026-06-13 14:38 | compile 实验 |
| 刘航宇 | 58.47 | 1.0589 | 0.7062 | 0.3013 | 88.13s | 0.7526 | 已完成 | 2026-06-13 14:46 | 关闭 compile,最优基线确认 |
| 刘航宇 | 55.19 | 1.0589 | 0.6594 | 0.3013 | 102.19s | 0.7526 | 已完成 | 2026-06-14 11:18 | Expert 相似度合并 th=0.97(阈值过高,几乎未合并) |
| 刘航宇 | **58.86** | 1.0589 | 0.7117 | 0.3013 | 86.49s | 0.7526 | 已完成 | 2026-06-14 11:32 | Expert 合并 th=0.90,旧版最优分 |
| 刘航宇 | 58.52 | 1.0589 | 0.7068 | 0.3013 | 87.95s | 0.7526 | 已完成 | 2026-06-14 11:46 | 微调 th=0.85 |
| 刘航宇 | 58.25 | 1.0589 | 0.7030 | 0.3013 | 89.11s | 0.7526 | 已完成 | 2026-06-14 12:11 | 微调 th=0.80 |
| 刘航宇 | 58.38 | 1.0589 | 0.7049 | 0.3013 | 88.54s | 0.7526 | 已完成 | 2026-06-14 12:25 | 旧版回退(PR#1 合并前基线) |
| qianban139 | 58.05 | 1.0589 | 0.7001 | 0.3013 | 89.96s | 0.7526 | 已完成 | 2026-06-14 23:09 | 张君硕首次提交(PR#1 代码基线) |
| qianban139 | 44.40 | 1.0589 | 0.5052 | 0.3013 | 148.44s | 0.7525 | 已完成 | 2026-06-15 09:19 | varlen attention 实验 → 评测端慢 65%,回退 |
| qianban139 | 62.81 | 1.0589 | 0.7682 | 0.3013 | 69.55s | 0.7525 | 已完成 | 2026-06-15 09:43 | 回退 SDPA,恢复调优 |
| qianban139 | 63.03 | 1.0589 | 0.7713 | 0.3013 | 68.60s | 0.7525 | 已完成 | 2026-06-15 11:59 | 参数调优 |
| qianban139 | 63.29 | 1.0589 | 0.7750 | 0.3013 | 67.49s | 0.7525 | 已完成 | 2026-06-15 12:16 | 参数调优 |
| qianban139 | 63.20 | 1.0589 | 0.7737 | 0.3013 | 67.88s | 0.7525 | 已完成 | 2026-06-15 12:40 | 参数调优 |
| qianban139 | 63.67 | 1.0589 | 0.7805 | 0.3013 | 65.86s | 0.7525 | 已完成 | 2026-06-15 12:48 | 参数调优 |
| qianban139 | 65.17 | 1.0589 | 0.8019 | 0.3013 | 59.44s | 0.7524 | 已完成 | 2026-06-15 13:47 | 参数调优(AUC 微降 0.0001 |
| qianban139 | **67.87** | 1.0589 | 0.8404 | 0.3013 | **47.88s** | 0.7524 | 已完成 | 2026-06-15 14:23 | 🔥 当前最高分!参数调优(AUC 微降 0.0002 |
| qianban139 | 67.21 | 1.0589 | 0.8311 | 0.3013 | 50.68s | 0.7524 | 已完成 | 2026-06-15 15:37 | 继续调参,略有回退 |
| 刘航宇 | 62.95 | 1.0589 | 0.7702 | 0.3013 | 68.93s | 0.7525 | 已完成 | 2026-06-15 17:19 | PR#1 代码(稠密MoE+融合查表+syncfree mask |
### 团队成员
| AI Studio 用户名 | 真实姓名 |
|------------------|----------|
| qianban139 | 张君硕 |
| sidny1988 | 谢松熹 |
| (队长账号) | 刘航宇 |