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
| File | Purpose |
|---|---|
gnn.pt |
Spider-GNN backbone state_dict (141 K params, ~579 KB) |
pca.pkl |
Pickled {"pca": sklearn.PCA(n=10), "scaler": StandardScaler} |
xgb.pkl |
Pickled dict[target_name, list[XGBRegressor]] β 9 seeds Γ 5 targets |
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).
| Target | RΒ² β | RMSE | Unit |
|---|---|---|---|
| RSSI | 0.759 | 6.43 | dBm |
| RSRP | 0.770 | 6.36 | dBm |
| RSRQ | 0.268 | 1.70 | dB |
| SNR | 0.146 | 6.06 | dB |
| CQI | 0.195 | 2.86 | step |
| Mean RΒ² | 0.421 | β | β |
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 (edge_index, edge_attr) 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.