Geospatial Trajectory Foundation Model
A 132 M-parameter Transformer pretrained on 1.68 M public taxi GPS trajectories (Porto + Beijing) using two self-supervised objectives:
- Masked Trajectory Modeling (MTM) — bidirectional, for trajectory representations
- Autoregressive (AR) next-location prediction — causal, for anomaly scoring via perplexity
GPS coordinates are tokenized into H3 hexagonal-grid cells at resolution 9 (~0.1 km²). After pretraining, the AR head assigns a calibrated perplexity score to any trajectory — detours, unusual routes, and driver fraud surface as high-perplexity sequences.
Architecture
| Parameter | Value |
|---|---|
| Layers | 12 Transformer blocks |
| d_model | 768 |
| Attention heads | 12 |
| Vocab size | 30,004 (30k spatial H3 sub-hashes + PAD/BOS/EOS/MASK) |
| Max sequence length | 512 tokens |
| Parameters | 132.8 M |
| Attention | Flash Attention (is_causal=True) |
Embeddings: spatial H3 token + log-spaced Δt bucket + minute-of-day + day-of-week. The MTM and AR heads share the same weight-tied projection matrix.
Training
| Metric | Value |
|---|---|
| Training steps | 300,000 |
| AR perplexity: initial → final | 34,754 → 2.1 |
| Final combined loss | 0.963 |
| Hardware | 1 × NVIDIA H100-SXM 80 GB (preemptible) |
| Wall time | ~12 h 43 min |
| Cost | ~$28 |
Usage
Download backbone.py and config.json from this repo alongside the checkpoint, then:
import json
import sys
import torch
sys.path.insert(0, ".") # backbone.py must be in the working directory
from backbone import TrajectoryBackbone
with open("config.json") as f:
cfg = json.load(f)["tokenizer"]
model = TrajectoryBackbone(
vocab_size=cfg["vocab_size"],
d_model=cfg["d_model"],
n_layers=cfg["n_layers"],
n_heads=cfg["n_heads"],
max_seq_len=cfg["max_seq_len"],
)
ckpt = torch.load("ckpt_final.pt", map_location="cpu", weights_only=True)
model.load_state_dict(ckpt["model"])
model.eval()
- Downloads last month
- 8
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support