Two-Tower model:
- Switch from BCE to BPR loss with per-user negative pairing
- Remove weight decay from embedding parameters (sparse gradient fix)
- Collapse linear architecture (hidden_dims=[]) — MLP with ReLU collapsed
all inputs to same hypersphere direction on sparse book data
- Add BPRDataset with per-user negative sampling to dataset.py
- All 3 models now produce non-zero Recall@10 (was 0.000 for Two-Tower)
Evaluation results (5k sampled users, leave-last-out):
- Naive: Recall@10=0.0046, NDCG@10=0.0022, MRR=0.0020
- LightGBM: Recall@10=0.0026, NDCG@10=0.0012, MRR=0.0010
- Two-Tower: Recall@10=0.0024, NDCG@10=0.0014, MRR=0.0012
API / inference:
- Filter untitled items (42% of catalog) from all recommendation paths
- Use numpy fancy indexing for exclusion (was O(n) loop)
- Expand LightGBM candidate pool to 500 (was 100)
Frontend redesign:
- Single model UX — always use Two-Tower, remove ModelSelector/CompareView
- New MetricsTable component with real evaluation numbers
- page…
feat: evaluation metrics, model evaluator, ablation experiment, error analysis