|
| 1 | +--- |
| 2 | +name: deepctr-benchmark |
| 3 | +description: >- |
| 4 | + Run the DeepCTR model benchmark suite (benchmarks/) to validate and compare |
| 5 | + CTR models end-to-end on real or bundled data, producing a sorted leaderboard. |
| 6 | + Use when asked to benchmark, compare, validate, or measure DeepCTR models |
| 7 | + (single-task CTR, multitask, or sequence), or to re-run / extend the |
| 8 | + benchmark after a code change. |
| 9 | +--- |
| 10 | + |
| 11 | +# DeepCTR benchmark suite |
| 12 | + |
| 13 | +A self-contained harness (`benchmarks/`) that trains DeepCTR models and writes a |
| 14 | +ranked leaderboard. Three tracks: `single` (21 single-task CTR models, Criteo), |
| 15 | +`multitask` (SharedBottom/ESMM/MMOE/PLE, Census-Income), `sequence` |
| 16 | +(DIN/BST/DSIN, DIEN skipped on TF≥2.0). Full docs: `benchmarks/README.md`. |
| 17 | +Curated past results: `benchmarks/RESULTS.md`. |
| 18 | + |
| 19 | +## Always do these two things first |
| 20 | + |
| 21 | +1. **Force CPU** with `CUDA_VISIBLE_DEVICES=""`. The GPU on this host has a |
| 22 | + CUDA/PTX mismatch — every model fails with `CUDA_ERROR_UNSUPPORTED_PTX_VERSION` |
| 23 | + on GPU. The harness isolates each model, so on GPU you get an all-`failed` |
| 24 | + leaderboard rather than a crash; the fix is always CPU. |
| 25 | +2. **Use legacy Keras**: `TF_USE_LEGACY_KERAS=1` (DeepCTR targets the Keras 2 |
| 26 | + API; on TF≥2.16 that means `tf-keras`). The package sets this itself, but set |
| 27 | + it explicitly when invoking pytest. |
| 28 | + |
| 29 | +Run long sweeps in the background and poll the log — a full 21-model single-task |
| 30 | +sweep on real data is several minutes to ~30 min on CPU. |
| 31 | + |
| 32 | +## Data on this host |
| 33 | + |
| 34 | +Real data lives in `benchmarks/data/` (git-ignored). If absent, regenerate or |
| 35 | +re-download (see README; the built-in Criteo DAC URL is dead — anonymous HF |
| 36 | +mirrors rate-limit, so a `HF_TOKEN` is needed for `reczoo/Criteo_x1`). |
| 37 | + |
| 38 | +| File | Rows | Use | |
| 39 | +| ---- | ---- | --- | |
| 40 | +| `benchmarks/data/criteo_x1_500k.csv` | 500,000 | single-task, meaningful AUC | |
| 41 | +| `benchmarks/data/criteo_x1_200k.csv` | 200,000 | single-task, faster | |
| 42 | +| `benchmarks/data/census-income.data` (+ `.test`) | 199,523 (+99,762) | multitask, official split | |
| 43 | +| `examples/criteo_sample.txt` | 200 | smoke only — AUC is noise | |
| 44 | + |
| 45 | +## Commands |
| 46 | + |
| 47 | +```bash |
| 48 | +# Fast smoke test (1 epoch, 2 models/track, bundled data) — verify the harness |
| 49 | +CUDA_VISIBLE_DEVICES="" python -m benchmarks.benchmark --track all --quick |
| 50 | + |
| 51 | +# Single-task, real Criteo 500k — the headline comparison |
| 52 | +CUDA_VISIBLE_DEVICES="" python -m benchmarks.benchmark --track single \ |
| 53 | + --data-path benchmarks/data/criteo_x1_500k.csv \ |
| 54 | + --epochs 1 --batch-size 1024 --val-split 0 --seed 2020 |
| 55 | + |
| 56 | +# Multitask, real Census with its official train/test partition |
| 57 | +CUDA_VISIBLE_DEVICES="" python -m benchmarks.benchmark --track multitask \ |
| 58 | + --data-path benchmarks/data/census-income.data --epochs 3 --batch-size 1024 |
| 59 | + |
| 60 | +# Subset / exclude slow models; e.g. drop the interaction-heavy ones to save time |
| 61 | +# --models DeepFM,DCN,xDeepFM run only these |
| 62 | +# --exclude FiBiNET,ONN,DeepFEFM,FwFM,FGCNN ONN alone is 77M params / ~245s |
| 63 | +``` |
| 64 | + |
| 65 | +Leaderboards print to stdout and write `benchmarks/results/<track>_<dataset>.csv` |
| 66 | +and `.md`. To preserve a run, copy the numbers into `benchmarks/RESULTS.md` |
| 67 | +(the `results/` dir is git-ignored). |
| 68 | + |
| 69 | +## Train / test split — get this right |
| 70 | + |
| 71 | +- **Default = random split**, `--test-size 0.2`, fixed `--seed`. Correct for |
| 72 | + Criteo_x1 / DAC, which is anonymised and shuffled with no timestamp (so a |
| 73 | + random split is leakage-free and standard). |
| 74 | +- **`--temporal-split` (+ optional `--time-col COL`)**: chronological hold-out — |
| 75 | + the most recent `test_size` fraction becomes the test set, so no future row |
| 76 | + leaks into training. Sorts by `--time-col` when present, else trusts file |
| 77 | + order. Use only for time-ordered logs; the bundled Criteo has no timestamp. |
| 78 | +- **Census official split**: when `--data-path` is `census-income.data` and a |
| 79 | + sibling `census-income.test` exists, the loader uses that official partition |
| 80 | + automatically (encoders fit on the union). Don't reshuffle it. |
| 81 | +- **`--val-split`** carves validation from *train* but is **not wired to any |
| 82 | + early-stopping/checkpoint** — it does not influence training or model |
| 83 | + selection. For short fixed-epoch runs set `--val-split 0` so training uses the |
| 84 | + full train split; only keep it if you add an EarlyStopping callback. |
| 85 | + |
| 86 | +## Interpreting results |
| 87 | + |
| 88 | +- Reported AUC/LogLoss are on the held-out **test** set (never seen in `fit`). |
| 89 | +- Need enough data for a real ranking: on 200-row bundled data AUC ≈ 0.5 noise; |
| 90 | + on 200k–500k the deep interaction models (DeepFEFM/FiBiNET/DeepFM/xDeepFM) |
| 91 | + separate from simpler ones. More epochs raise absolute AUC but rarely flip the |
| 92 | + top group. |
| 93 | +- Always report the split and epoch count alongside the leaderboard — a ranking |
| 94 | + is only comparable within the same data/split/epochs. |
| 95 | + |
| 96 | +## Tests |
| 97 | + |
| 98 | +```bash |
| 99 | +CUDA_VISIBLE_DEVICES="" TF_USE_LEGACY_KERAS=1 python -m pytest tests/benchmark_test.py -q |
| 100 | +``` |
| 101 | + |
| 102 | +Covers each track on tiny data plus the split guarantees (temporal hold-out |
| 103 | +keeps the most-recent rows as test; Census uses the official `.test`). |
0 commit comments