ARK-3 AdsRank · Three-Stage CTR Ranking Engine ARK-DS-001A

ARK-3 · ADSRANKThree-Stage Click-Through-Rate Ranking Engine

Two-tower retrieval  ▸  FAISS candidate recall  ▸  DeepFM fine-ranking  ▸  ONNX Runtime C++ serving. Trained on Criteo display-ad impressions.

DatasheetREV A

1Features

  • DeepFM ranker with learned field embeddings
    • Linear, factorisation-machine and deep MLP terms over one shared embedding table
    • Feature-interaction ablation: LR / FM / DNN / DeepFM under one training protocol
  • Ranker-distilled two-tower retrieval
    • Towers trained to imitate the ranker, not raw clicks
    • Click-trained, popularity and ranker-prior baselines included
  • FAISS IVF candidate recall, inner-product exact w.r.t. the tower score
  • ONNX export + C++ inference harness
    • Parity-checked against PyTorch
    • Thread-count sweep and reusable IoBinding buffers
  • Runs live in this page — evaluation board

2Applications

  • Display-advertising auctions (pCTR × bid)
  • Sponsored-search and feed candidate ranking
  • Offline funnel-budget studies: how many ranker calls a request actually needs
  • Teaching reference for retrieval ↔ ranking consistency

3Description

ARK-3 is a complete, reproducible ad-ranking stack built on a sample of the Criteo click logs. A DeepFM ranker models second-order and deep feature interactions over every embedded field. A two-tower model, trained to imitate that ranker, maps contexts and ads into one vector space so FAISS can shortlist candidates; DeepFM then re-scores only the shortlist.

The ranker is exported to ONNX and served from a C++ harness built on ONNX Runtime, where thread placement and buffer reuse are tuned against a fixed request shape: one context × a shortlist of candidates.

Device Information
PartPackageContents
ARK-3 rankerdeepfm.onnxDeepFM, field indices → click probability
ARK-3 retrievertwo_tower_distilled.ptquery + item towers, per-item bias
ARK-3 web (pruned)ranker_web.onnxranker pruned to the evaluation-board vocabulary
Simplified Schematic
ARK-3AdsRank · Three-Stage CTR Ranking EngineARK-DS-001A

Table of Contents

4Pin Configuration and Functions

Each Criteo field enters the ranker as one embedded "pin". Pins drawn in red belong to the ad side of the retrieval split; the rest describe the request context. Criteo does not disclose field semantics, so the split is inferred from the data (§5.3.3). Hover a pin.

Package (Field View)Top view · field inputs + pCTR output
Pin Functions
No.NameI/OSideDescription
loading…
ARK-3AdsRank · Three-Stage CTR Ranking EngineARK-DS-001A

5Detailed Description

5.1Overview

A request arrives with a context (the context pins). Stage one encodes it with the query tower; stage two asks a FAISS IVF index for the catalog items with the highest tower score; stage three runs DeepFM on exactly those pairs and returns the top ads by predicted click probability. An offline benchmark compares that output against an oracle that runs DeepFM on every catalog item, which shows how small the shortlist can be.

5.2Functional Block Diagram

5.3Feature Description

5.3.1 Field Encoding

Count features (I1–I13) are discretised: small values keep their own bucket, larger values map to ⌊ln²(x)⌋, the transform used by the winning Kaggle Criteo solutions. Categorical features (C1–C26) get a vocabulary fit on the training split only, with rare values sharing an out-of-vocabulary row and missing values their own row. Every field then indexes one shared embedding table; per-field offsets live inside the model so the exported graph consumes the raw int64[B, 39] tensor.

5.3.2 DeepFM Ranker

DeepFM (Guo et al., 2017) sums three terms that read the same field embeddings: a first-order linear term, the factorisation-machine pairwise term ½[(Σv)² − Σv²], and a deep MLP with batch norm and dropout. Training uses Adam, evaluates on validation several times per epoch, decays the learning rate whenever validation stops improving, and stops early. Embedding L2 is chosen per configuration on validation log loss, and the same protocol trains the LR, FM and DNN ablations.

5.3.3 Ad / Context Split

Retrieval needs an item side, but Criteo's fields are anonymous. Attributes of one entity are functionally dependent, so for every pair of categorical fields the pipeline computes the normalised conditional entropy U(J|K) = H(J|K)/H(J). High-cardinality fields that pin down several others are candidate ad keys. Each candidate catalog is then scored by the trained DeepFM, and the entity whose ranking depends most on the query is kept: , carrying . The catalog is the most frequent keys, each with its modal attributes.

5.3.4 Two-Tower Retrieval, Distilled from the Ranker

Both towers embed their fields and pass them through an MLP to unit-norm vectors. A click-trained tower (in-batch sampled softmax with logQ correction) learns what gets clicked, but the funnel must find what DeepFM will rank highest. The distilled tower therefore minimises KL(teacher ‖ student) between the softmax of DeepFM logits and of tower scores over slates of uniformly sampled items plus the student's own current top items (hard negatives). Each item also learns a scalar bias stored as an extra vector coordinate (the query appends a constant 1), so inner-product search in FAISS reproduces the tower score exactly.

5.3.5 FAISS Candidate Recall

Item vectors go into an IndexIVFFlat inverted-file index. The number of probed lists scales with the requested shortlist size, so larger budgets scan proportionally more of the catalog.

5.3.6 ONNX Export and C++ Harness

The ranker is exported with a dynamic batch dimension and the sigmoid in-graph, then verified against PyTorch on held-out rows. cpp/bench.cpp replays real fine-ranking requests through ONNX Runtime and reports latency percentiles for each serving configuration.

5.4Device Functional Modes

ModeSessionPer request
PyTorch eagernn.Module, torch.no_grad(), torch default threadstensor from NumPy, forward, copy out
ORT · PythonInferenceSession, defaultssess.run with a NumPy feed
ORT · C++ naivedefault SessionOptionsfresh input vector + tensor; Run() allocates the output
ORT · C++ tunedexplicit intra-op threads, inter-op 1, sequential executor, spin-wait, all graph optimisationsmemcpy into one pre-bound input buffer; output written into a pre-bound buffer via IoBinding
ARK-3AdsRank · Three-Stage CTR Ranking EngineARK-DS-001A

6Application and Implementation

6.1Typical Application — Evaluation Board

The board below is the real funnel running in your browser through onnxruntime-web: the trained query tower, the catalog item vectors, and the DeepFM ranker (embedding table pruned to the rows this board can address). Pick a held-out impression, pull context pins to missing, and compare the funnel's top-10 with the ranker scoring the entire catalog.

ARK-3 EVM · Live Funnelidle
CONTEXT HEADER — click a pin to force it to missing

Funnel top-10 (tower → shortlist → DeepFM)

    Exhaustive top-10 (DeepFM × catalog)

      Ads marked SHARED appear in both lists. In-browser shortlisting uses exact inner product over the item vectors; the offline pipeline uses the FAISS IVF index of §5.3.5.

      6.2Layout Guidelines

      ARK-3AdsRank · Three-Stage CTR Ranking EngineARK-DS-001A

      7Device and Documentation Support

      7.1Setup

      # Linux (tested on Ubuntu / WSL2), Python 3.12, C++17 compiler, CMake
      git clone https://github.com/DevFrancisA/AdsRank && cd AdsRank
      python -m venv .venv && . .venv/bin/activate
      pip install -r requirements.txt
      bash scripts/run_all.sh        # download → train → retrieve → export → bench → site assets
      python -m http.server -d docs  # open http://localhost:8000
      StageEntry pointProduces
      Datapython -m adsrank.dataencoded splits, vocabulary
      Ranker + ablationpython -m adsrank.train_rankertrained rankers
      Field splitpython -m adsrank.fields, python -m adsrank.split_probead / context split
      Retrievalpython -m adsrank.retrievaltowers, catalog, item vectors
      ONNX exportpython -m adsrank.exportdeepfm.onnx, request replay file
      Latency harnesspython -m adsrank.bench_py, scripts/bench_cpp.shlocal benchmark logs
      This sitepython -m adsrank.export_sitedocs/assets/*

      7.2Related Documentation

      8Mechanical, Packaging, and Orderable Information

      Package Option Addendum
      ArtifactFormatContents
      deepfm.onnxONNXDeepFM, int64[B, 39] → float32[B]; sigmoid in-graph
      two_tower_distilled.ptPyTorch state dictquery + item towers, per-item bias
      item_vectors.binfloat32 matrixscaled item vectors ⊕ bias, FAISS input
      ranker_web.onnxONNXDeepFM with embedding rows pruned to the evaluation-board vocabulary
      query_tower_web.onnxONNXquery tower, same pruning
      requests.binint64 replay filefine-ranking requests for the latency harness

      Trained weights are not committed — regenerate them with scripts/run_all.sh. The pruned web models in docs/assets/ are committed.