10 · 代码地图与入口脚本(System Code Map)
本文档是
code/目录的导航地图:30+ 个脚本各自干什么、谁是入口、谁是被运行时加载的"库"、谁是只能看不能跑的 legacy。读完本文你应当能在 30 秒内回答:"我想改 X,该动哪个文件?""我想重跑最终方法,敲哪条命令?""为什么没有utils.py?" 代码定位以docs_first_principles/_fact_sheet.md§6 为准(状态日期 2026-06-18)。路径相对仓库根,带行号。
目标读者:第一次进仓库、对"importlib 互相加载 + 无共享包"这套非典型工程组织感到困惑的人。先讲为什么这样组织(第一性原理),再给地图与入口。
1. 第一性原理:为什么没有 utils.py,而是"脚本互加载"
1.1 典型工程 vs 本仓库
典型项目会把公共函数抽到 utils.py / common/ 包,其他模块 import。本仓库没有。 它是研究/实验代码,追求"一个脚本跑完一个实验、改完立刻能跑"。于是演化出一种去中心化的代码复用:每个脚本用一段近乎相同的 load_module() helper 把同目录的另一个脚本当模块加载:
def load_module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
1.2 这样设计的后果(读者必须知道)
- 没有显式接口/版本。函数签名、返回顺序全靠"加载方与被加载方的默契"。读下游脚本时,常需要跳到被加载脚本确认函数行为。
- 两个脚本成了事实共享库(de-facto shared library),被 ~14–16 个脚本加载(见 §4)。改这两个文件的任何函数,等于同时改了十几个下游脚本的行为——blast radius 极大。
- 每个脚本各自重定义本地
read_txt等小工具,不统一。
这不是"坏味道"要重构,而是研究代码的合理权衡:快速试错优先于工程整洁。理解了这一点,才不会被"为什么这么乱"绊住,而能专注"数据怎么流"。
2. 脚本分类速览(四类)
| 类别 | 命名模式 | 角色 | 例子 |
|---|---|---|---|
| 训练 | train_val_*.py |
Stage-1 模型训练 + 出验证/测试分数 | train_val_lgcn_ensemble.py |
| 特征/分数消融 | *_ablation.py |
单组特征验证 + 拼特征矩阵 | randomwalk_systematic_ablation.py |
| submission 生成 | generate_*submission.py |
把分数/特征转成提交 CSV | generate_post95_submission.py |
| stacking / 校准 / 搜索 | stack_*、score_level_*、error_group_*、search_*、rich_randomwalk_stack.py |
二阶段融合、阈值/比例搜索、误差分析 | stack_rank_calibration.py |
| (存证) | run_*.py、compare_gnn.py |
legacy,不可直接跑(见 §6) | run_baseline.py 等 9 个 |
3. 三条核心入口命令
3.1 重跑最终方法(出 submission)
python code/high_order_graph_stack.py \
--package-root . --split-seed 202 --seed 202 --n-splits 5 --make-submission
- 命中全部缓存(
feature_cache/、randomwalk_systematic/models/、LightGCN 分数),CPU 秒级出 OOF + submission。 - 不加
--make-submission= 仅验证。 - 详见
03_data_flow_and_artifacts.md§9。
3.2 生成图表
本仓库有两套图表包(见记忆 figures-and-label-alignment):
# ACM 双栏正式版(3.25/6.75 in, pdf.fonttype=42),论文用
python figures_paper/scripts/make_all_figures.py --package-root .
# 早期 seaborn 版(更大字号),探索/汇报用
# (code/figures/ 下各 figN_*.py 独立可跑)
figures_paper/scripts/make_all_figures.py 自动建目录、逐图 try/except 隔离、读真实数据(缺失则优雅跳过)、生成 pdf/png/svg + README_figures.md。单个图失败不会拖垮其余图。
3.3 编译论文 TeX
诚实说明(重要): 本仓库不包含论文
.tex工程或编译命令。docs_first_principles/SUMMARY_FOR_PAPER.md提供的是可直接迁移进 TeX 的成稿段落、表格、公式、caption(中文,保留英文术语),以及建议的\section结构。实际编译发生在用户的独立论文项目里,把 SUMMARY 的段落复制进.tex、按需改\[ \]/equation环境即可。本审计遵循"不覆盖/不改论文模板"的约束,未在仓库内增设任何 TeX 构建。
4. 两大事实共享库(改动 blast radius 最大)
被 ~14–16 个脚本经 load_module() 运行时加载,改它们 = 改全链:
4.1 train_val_lgcn_ensemble.py(数据 + 切分 + 评分)
| 函数/符号 | 行号 | 作用 | 为什么被到处加载 |
|---|---|---|---|
make_notebook_style_split |
132-165 | seed=202 切分 → 1:1 验证集(136,484 对) | 所有下游都要用同一验证 pair/label |
build_parts |
168-236 | 加载 feature.pkl + 度特征 + popular 集 + coauthor_pool(L216 硬编码 range(6611)) |
负采样/特征都依赖这些预计算 |
build_data |
239-270 | PyG HeteroData:4 边类型,引用/合著双向拼接,论文 515→embed 投影 | LightGCN 训练数据装配 |
LightGCNLayer / encode / decode |
49-104 | 纯加权邻居聚合(无 W 无非线性)+ 点积解码 | 模型本体 |
sample_hard_negatives |
273-305 | 硬负采样 random50%/popular25%/coauthor25% | 训练循环 |
best_f1 |
340-346 | PR 曲线 argmax 最优 F1 阈值 + AUC | 所有 stacker 算验证 F1 都用它 |
predict_scores |
308-337 | no_grad 批量打分(cos/dot/neg_l2) | 推断 |
4.2 stack_rank_calibration.py(显式图特征 + rank + OOF)
| 函数/符号 | 行号 | 作用 |
|---|---|---|
ExplicitGraphFeatures.__init__ |
54-106 | 默认 6611 作者 / 79937 论文;预计算 shared_paper_authors(A-P-A) + coauthor_paper_union(A-A-P) |
ExplicitGraphFeatures.transform |
108-145 | 18 维手工特征(L139 与 L130 重复一列,台账 #13) |
add_rank_features |
148-160 | 4 列:score/global_rank/author_pct/author_rank |
fit_oof |
163-184 | 5 折 StratifiedKFold;LGBM(1200, lr0.025, reg_lambda5) |
关键事实:本文件全文无
scipy.sparse(台账 #12)——CLAUDE.md 所指的"sparse-matrix 高阶传播"在high_order_graph_stack.py,不在此文件。meta-path 全用 Python set 交/并集实现。
4.3 其他高频被加载的 peer
| 脚本 | 被加载的关键函数 | 用途 |
|---|---|---|
generate_post95_submission.py |
select_variant_val_scores、topk_content_similarity_fast |
变体选择 + top-k 内容相似 |
post95_ablation.py |
negative_evidence_features |
8 维负证据 |
extra_score_sources_ablation.py |
content_mean_score、score_to_features |
content_mean-cos + BPR-MF |
randomwalk_systematic_ablation.py |
build_base_features、pair_feature_block |
X_base 84 维 + 每块 11 维 RW |
content_rich_ablation.py |
content_rich_features |
从 feature.pkl 产 18 维 rich |
generate_randomwalk_ensemble_submission.py |
aggregate |
11 维 RW 一致性聚合 |
5. 最终入口:high_order_graph_stack.py 为什么是终点
它是唯一同时做三件事的脚本:① 拼接全部 259 维特征;② 训练最终 LightGBM OOF stacker;③ 出 submission。逻辑上它是 Stage-2 的实现 + 决策规则的实现,所以是"最终方法入口"。
| 关键符号 | 作用 | 备注 |
|---|---|---|
build_high_order* |
$H_k=R\cdot C^k$、$G_k=S\cdot R\cdot C^k$,fwd/bwd/undir | scipy.sparse 幂乘 + top-k 剪枝(k=1500);硬编码稀疏矩阵形状 6611×79937(见 §7) |
fit_full_predict |
LightGBM(num_leaves=15, reg_lambda=8, lr=0.022, n_est=1400) 5-fold OOF | 最终超参(事实表 §2.7) |
| 决策 | sort → top 50% = 1 + test_known_mask.npy 强制已知正边 |
rank-cutoff(详见 08) |
输出目录:validation_runs/dynamic_seed202/high_order_graph_stack/(validation_summary.csv、*_oof.npy、*_test_pred.npy、submissions/*.csv)。
6. Legacy 脚本:能看不能跑
以下 9 个是早期原型,硬编码 /home/lzc/cs3319-project 路径、无 argparse,仅作存证(provenance)。要跑必须先改路径,且功能已被现代 train_val_* / generate_* / *_ablation 取代——不要用它们复现结果:
run_baseline.py run_improved.py run_v2.py run_final.py run_ultimate.py
run_lgcn_final.py run_lgcn_v2.py run_graph_features.py compare_gnn.py
它们的价值:记录"从复杂 GNN(
HeteroMeanConv/SAGE)退回轻量 CF(LightGCN)"的方法演进史(见09_experiment_timeline.md§3.1)。notes/experiment_history.md有对应叙事。
7. 完整脚本地图表
"改动影响"列:🔴 共享库(改动影响十几个下游);🟡 多下游加载;🟢 独立入口(改了只影响自己);⚪ legacy(勿动)。 硬编码维度 6611(作者)/79937(论文) 在
high_order_graph_stack.py(稀疏矩阵形状)与train_val_lgcn_ensemble.py(L216 采样循环)字面出现,勿随手"重构"成变量(它们匹配本数据集,见 CLAUDE.md gotchas)。
| 脚本 | 角色 | 主要输入 | 主要输出 | 改动影响 | 备注 |
|---|---|---|---|---|---|
train_val_lgcn_ensemble.py |
LightGCN 训练 + 切分 + 评分 | bipartite_train_ann.txt、feature.pkl |
scores/val_vanilla_ensemble_mean.npy、切分快照 |
🔴 | 两大共享库之一;best_f1/make_notebook_style_split 全链用 |
stack_rank_calibration.py |
显式图/meta-path 特征 + rank + OOF | LightGCN 分数、bipartite_train |
explicit18 + rank4 特征、fit_oof |
🔴 | 两大共享库之一;无 sparse |
high_order_graph_stack.py |
最终 stacker + submission | 全部 259 维特征(命中缓存) | *_oof.npy、*_test_pred.npy、submission_*.csv |
🟢 | 最终入口(§3.1);有 sparse 幂乘 |
generate_post95_submission.py |
变体选择 + top-k 内容 + submission | LightGCN 变体分数、test 镜像 | variant43、topk3、submission | 🟡 | select_variant_val_scores/topk_content_similarity_fast |
post95_ablation.py |
负证据特征 | X_base 前 84 列 | neg8 | 🟡 | negative_evidence_features |
extra_score_sources_ablation.py |
BPR-MF + content_mean-cos | LightGCN 分数、feature.pkl |
val_mf_bpr_s202_d256.npy、content_mean |
🟡 | content_mean_score/score_to_features |
content_rich_ablation.py |
rich content 画像 | feature.pkl |
content_rich_*.npy(18 维,命中 feature_cache) | 🟡 | content_rich_features |
randomwalk_systematic_ablation.py |
7 块 DeepWalk/Node2Vec | 异构图边 | 7× .model + pair_features/*.npz(11 维/块) |
🟡 | build_base_features/pair_feature_block;需 GPU/Word2Vec |
generate_randomwalk_ensemble_submission.py |
RW 一致性聚合 + submission | 7 块 pair 特征 | aggregate 11 维、submission | 🟡 | aggregate() |
score_level_*、error_group_*、search_* |
阈值/比例搜索、误差分桶 | OOF、各 submission | 分析 CSV(出图用) | 🟢 | 如 error_analysis_buckets.csv |
rich_randomwalk_stack.py |
RW 专用 stacker | RW 特征 | RW 阶段 OOF/CSV | 🟢 | 中间实验 |
generate_ens6_submission.py |
早期 6-model ensemble submission | checkpoints/ens6 | 6-model submission | 🟢 | 0.93044 那版(早期) |
run_*.py、compare_gnn.py(9 个) |
legacy 原型 | — | — | ⚪ | 硬编码 /home/lzc、无 argparse,勿直接跑(§6) |
8. 常见问题速答
| 问题 | 答案 |
|---|---|
没有 utils.py 怎么共享代码? |
importlib.util 的 load_module() 运行时加载同目录脚本(§1) |
| 改一个公共函数影响多大? | 改 train_val_lgcn_ensemble.py/stack_rank_calibration.py = 影响十几个下游(🔴);改入口脚本只影响自己(🟢) |
为什么有的脚本没 argparse? |
那是 run_*.py legacy,早期原型,已被现代脚本取代(§6) |
| 最终方法入口是? | high_order_graph_stack.py --make-submission(§3.1) |
| 图表怎么出? | figures_paper/scripts/make_all_figures.py --package-root .(§3.2) |
| 论文 TeX 在哪编译? | 仓库内没有 TeX 工程;SUMMARY_FOR_PAPER 提供可迁移段落,在用户独立项目编译(§3.3) |
| 6611/79937 哪来的? | 数据集固定规模,字面硬编码在两个脚本里,匹配本数据集勿重构(§7) |
可迁移到论文中的写法
实现概述段(Implementation,可直译进 TeX)。 我们的系统由若干 Python 脚本组成,按"训练 / 特征消融 / 提交生成 / 堆叠校准"四类组织。其中两个脚本——
train_val_lgcn_ensemble.py(数据装配、确定性验证切分、最优 F1 阈值)与stack_rank_calibration.py(显式图与元路径特征、排名校准、out-of-fold 训练)——作为共享基础库,被约十余个下游脚本以运行时模块加载的方式复用,故其接口在整条流水线中保持一致。最终的两阶段堆叠与 rank-cutoff 决策由high_order_graph_stack.py实现:它将来自协同过滤、矩阵分解、随机游走、内容画像与有向高阶引用传播的全部 259 维特征横向拼接,以强正则 LightGBM 作二级元学习器融合。关键的高阶传播以稀疏矩阵幂乘实现($H_k=R,C^k$、$G_k=S,R,C^k$),并通过每次幂乘后的 top-k 行裁剪将 $|P|\times|P|$ 的稠密化控制在可计算规模。所有中间分数与特征均缓存于validation_runs/下,并依确定性切分种子(seed=202)组织,保证实验可复现。