Advanced Training Options
XGBoost Memory Modes
By default, all edge embeddings are collected in CPU RAM before XGBoost training. For large datasets this can exceed available memory. The following modes progressively reduce memory pressure.
Choosing batch_size for batched modes:
A good starting point is batch_size: 65536 (≈ 64 MB for 256-dim embeddings) and double it until you reach the memory limit.
Config example — batched external memory:
How Edge Embeddings Are Generated Before XGBoost Trains
Understanding when to use memmap and extmem requires knowing how the GNN produces the embedding matrix that XGBoost trains on.
memmap: false (default) — in-RAM accumulation:
The GNN processes training edges in mini-batches. After each batch’s forward pass, the resulting edge embedding tensor is appended to a list held in CPU RAM. When all batches complete, the list is concatenated into a single tensor and handed to XGBoost. No disk I/O occurs. This is fastest but requires enough system RAM to hold the full embedding matrix at once (all training edges × embedding dimension × 4 bytes).
memmap: true — incremental disk write (requires batched: true):
Each mini-batch’s embeddings are written immediately to a disk-backed memory-mapped file (edge_emb_train_rank0.mmap) as the GNN produces them. XGBoost then reads from this file in batches — either using QuantileDMatrix (all data in disk file, but processed batch-by-batch) or using ExtMemQuantileDMatrix when extmem: true is also set (XGBoost manages its own disk cache too). Peak RAM during training equals approximately one batch of embeddings rather than the full training set.
The .mmap file is temporary — it is deleted automatically after XGBoost finishes training.
Use memmap: true (requires batched: true) in RAM-constrained environments when system RAM cannot comfortably hold all training edge embeddings at once. extmem: true is a separate flag that enables XGBoost’s own ExtMemQuantileDMatrix disk cache; the two options are independent and can be combined.
Resuming Interrupted Training
Set checkpoint_dir in your config to warm-start GNN weights from a previous run. The GNN saves a single checkpoint (model_final.pt) to output_dir after all epochs complete. If training is interrupted before finishing, no partial checkpoint is available and training will restart from the beginning unless a previous run’s model_final.pt already exists in output_dir or checkpoint_dir.
To retrain only the XGBoost step using the saved GNN embedding (without re-running GNN training):
Monitoring Training Progress
Real-Time Console Output
All log messages from rank 0 appear on stdout. Key lines to watch:
Log Files
Each run writes a timestamped log file: output_dir/training_YYYYMMDD_HHMMSS.log
Metrics File
After training completes, output_dir/metrics.json contains the full evaluation report:
When prior_test is configured, the file gains six additional top-level fields:
threshold_best_prod is the F1-optimal threshold evaluated on a class-ratio-simulated validation set (see Class Imbalance and Calibration). Use this value — not best_threshold — as the production decision threshold when your live fraud rate differs significantly from the training fraud rate.
Metric glossary:
Class Imbalance and Calibration
Production fraud rates (0.01%–0.2%) are typically 50–500× lower than training fraud rates (10–20%). If left unaddressed this gap produces overconfident probability scores and a misaligned decision threshold. Three parameters work together to close it:
scale_pos_weight — Training Balance
Upweights the fraud class during XGBoost training to compensate for imbalance in the training data. The default null computes it automatically as (1 − fraud_rate) / fraud_rate from the training labels. Override only if you want a custom ratio — for example to trade off precision vs. recall:
base_score — XGBoost’s Initial Prediction
Sets XGBoost’s intercept before any trees are built. The default 0.5 is calibrated for balanced datasets. Set it to your training fraud rate so the trees only need to learn the residual signal:
This reduces the number of trees needed for convergence and improves probability calibration on the training distribution.
prior_test — Production Threshold Calibration
When your evaluation environment (OOT test set, live production) has a much lower fraud rate than training, set prior_test to calibrate scores for that environment. The pipeline downsamples validation-set positives so their rate matches prior_test, then finds the F1-optimal threshold on that simulated distribution — only the threshold is recalibrated. AUC is unaffected.
This is essential for meaningful precision/recall at production thresholds — without it, the decision threshold is calibrated on a 10%-fraud validation set and will be misaligned when the model is deployed against 0.03% production traffic, resulting in far too many false positives or false negatives depending on where the threshold falls.
Combined Example — Large Imbalance Gap
Hyperparameter Tuning Guidance
When starting with a new dataset, tune parameters in this order — earlier parameters have larger impact and adjusting them makes later parameters more stable.
Step 1 — Validate basic learning:
Set epochs: 1, num_boost_round: 50. The goal is to confirm the pipeline runs end to end and produces a non-random PR-AUC (> 0.5). If AUC stays at 0.5, check data quality: label distribution, feature normalisation, index correctness.
Step 2 — Tune GNN epochs and learning rate:
Increase epochs until validation AUC plateaus. If AUC drops after plateau, you are overfitting — stop earlier. Learning rates between 0.001 and 0.01 work well for most datasets.
Step 3 — Tune XGBoost num_boost_round and learning_rate:
A smaller learning rate (0.01–0.05) with more rounds (500–1000) usually outperforms a large rate with fewer rounds. Set log_period: 5 to see per-round progress clearly. Important: when using a slow learning rate, increase early_stopping_rounds proportionally (e.g. early_stopping_rounds: 200) — at LR=0.01 the per-round improvement is very small and the default patience of 50 rounds may trigger early stopping before the model converges.
Step 4 — Tune XGBoost regularisation for overfitting:
If training PR-AUC is much higher than validation PR-AUC, increase min_child_weight (try 5, 10, 20), set gamma to 0.1–1.0, and reduce subsample to 0.7–0.8.
Step 5 — Try a deeper GNN or different encoder:
Once the baseline is stable, experiment with num_gnn_layers: 3 (and a corresponding third value in num_neighbors), or switch to encoder: gat.
Saving Node Embeddings for Hybrid Inference (EP Only)
Setting gnn.save_node_embeddings: true enables a third inference mode — hybrid inference — that pre-computes GNN node embeddings at training time and uses fast memmap lookup at inference time for any node that was in the training graph.
What Happens at the End of Training
After the main GNN+XGBoost training loop completes, two additional phases run automatically:
Phase A — Fine-tuning (optional): If final_fit_epochs > 0, the saved model_final.pt is reloaded and trained for final_fit_epochs more epochs on the combined train+val+test edge set, using learning_rate × final_fit_lr_scale as the LR. This improves embedding quality by exposing the model to the full labeled dataset before export.
Phase B — Stage 9: Node embedding export: A full GNN forward pass runs over all nodes of each type (both source and destination node types). Per-rank shard files are written:
train_gnn_xgb.py before Stage 9 (node embedding export). Because node_embeddings/ does not yet exist when Stage 8 runs, the auto-merge inside triton_export.py is always skipped during a fresh training run. The merge into embeddings.mmap and features.mmap happens lazily at first client startup (load_mmaps() in client_saved_emb.py / client_production.py calls merge_all() automatically when only rank shard .pt files are present). If you need the merged files before starting a client (for example, when copying artifacts to a serving machine), run python infer/merge_embeddings.py --emb_dir <output>/node_embeddings manually. After the merge, the rank shard .pt files are no longer needed at inference time.Inference Routing
At inference time, each edge is routed based on whether its src and dst node IDs fall within the training graph:
The per-path metrics in client_saved_emb.py output tell you what fraction of your inference traffic is hitting each path and the quality of each path independently.
When to Use Saved Node Embeddings
Use save_node_embeddings: true when:
- You need low-latency inference for most edges
- Your inference traffic is dominated by nodes seen during training (the known path)
- You want to decouple the GNN from the serving critical path
Use the standard client.py (no saved embeddings) when:
- You want the simplest possible serving setup
- Most inference nodes are novel (cold-start rate > 50%)
- Latency requirements allow the full GNN inference time