uts-aiot-ibc-research/graph-xgb
graph-xgb — Indoor 5G Signal Prediction (Spider-GNN + XGBoost)
A two-stage hybrid model that predicts five indoor 5G RF parameters (RSSI, RSRP, RSRQ, SNR, CQI) from sparse outdoor + indoor walk-test measurements at a single multi-floor building.
The GNN backbone (Spider-GNN, BESC2025) learns a 128-D graph embedding over a spatial KNN graph of measurement points. PCA reduces it to 10 D, which is concatenated with 14 raw spatial features and fed to a per-target ensemble of 9 XGBoost regressors (one seed per estimator, predictions averaged at inference).
Files
Tag the model with revision="v8" when downloading (see Usage below).
Test-set performance (v8)
Evaluated on a held-out 58-node subset (single building, 613 nodes, 9 668 edges; train 268 / val 58 / test 58).
v8 is currently the best-on-mean configuration across v2–v9; v9 (cascaded ensemble) is competitive on CQI but loses on SNR.
Usage
import pickle
import torch
from huggingface_hub import hf_hub_download
REPO = "uts-aiot-ibc-research/graph-xgb"
REV = "v8"
gnn_pt = hf_hub_download(REPO, "gnn.pt", revision=REV)
pca_pkl = hf_hub_download(REPO, "pca.pkl", revision=REV)
xgb_pkl = hf_hub_download(REPO, "xgb.pkl", revision=REV)
# 1. Load GNN backbone (architecture: GATv2Conv ×2, hidden=32, heads=4, in_dim=14)
# See `apps/api/src/graph_xgb/registry/hf_loader.py` in the source repo
# (uts-aiot-ibc-research/spider-gnn) for the full `_SpiderGNN` definition.
state_dict = torch.load(gnn_pt, map_location="cpu", weights_only=True)
# 2. Load PCA + StandardScaler
with open(pca_pkl, "rb") as f:
bundle = pickle.load(f)
pca, scaler = bundle["pca"], bundle["scaler"]
# 3. Load 45 XGBoost regressors (5 targets × 9 seeds)
with open(xgb_pkl, "rb") as f:
ensemble = pickle.load(f) # dict[target, list[XGBRegressor]]
# Inference pipeline:
# emb = gnn.get_embedding(x, edge_index, edge_attr) # (N, 128)
# pca_emb = pca.transform(scaler.transform(emb)) # (N, 10)
# X = np.concatenate([pca_emb, x_spatial], axis=1) # (N, 24)
# for target in ["CQI", "RSSI", "RSRP", "SNR", "RSRQ"]:
# preds = np.mean([m.predict(X) for m in ensemble[target]], axis=0)For a turn-key FastAPI server + Next.js viz, see the source repository.
Architecture
Spider-GNN backbone (frozen after training)
└─ GATv2Conv(14 → 32×4=128, edge_dim=4)
GATv2Conv(128 → 128, edge_dim=4)
LayerNorm + GELU + Dropout(0.3)
shared_mlp → 128-D embedding
per-target heads (RSSI / RSRP / RSRQ / SNR / CQI)
↑ heads are trained but unused at inference;
only the shared 128-D embedding feeds the XGBoost stage.
XGBoost stage (per target, ensemble of 9 seeds)
└─ Input: 24 D = PCA(128 → 10) + 14 D raw spatial features
Output: averaged prediction in physical units
(CQI clipped and rounded to [0, 15])Training data
Dataset: 613 nodes (384 internal + 229 external context) from a single multi-floor indoor building campaign. Walk-test measurements combined from outdoor (calibrated) and indoor (relative) RF surveys. Not publicly redistributed.
Limitations
- Single-building generalisation — model is fit to one indoor venue's geometry and KNN graph structure; transferring to another building requires retraining on a new graph.
- Interference-bounded targets — SNR (0.146) and CQI (0.195) hit a ceiling because the input features do not include interference measurements; this is a data limitation, not an architectural one.
- Frozen-graph inference only — adding new survey points requires reconstructing the KNN graph (edgeindex, edgeattr) with the original scaler statistics.
Citation
@inproceedings{spidergnn2025,
title = {Spider-GNN: A Graph Neural Network for Indoor 5G Signal Prediction},
booktitle = {BESC 2025},
year = {2025},
note = {Code and model: https://huggingface.co/uts-aiot-ibc-research/graph-xgb}
}License
MIT — see source repository.
