skyfull-policy-aosta-rescue-v1
Rescue drone trajectory policy trained on real Aosta Valley terrain. Part of Skyfull โ physical intelligence over geo-scale terrain.
Architecture
Tiny MLP policy. No vision encoder. No transformer. No diffusion. Just coordinate geometry learned end-to-end.
| Type | MLP (multi-layer perceptron) |
| Input | 3 floats: victim_dlon, victim_dlat, victim_elev |
| Output | 120 floats: trajectory (40 steps ร lon, lat, alt_m) |
| Hidden | 256 units ร 3 layers |
| Activation | SiLU |
| Parameters | 163,448 |
| Checkpoint size | 642 KB |
| Inference time | < 2 ms on CPU |
Also includes terrain_aosta.pt โ the TerrainNet implicit neural terrain
(4k params, 37 KB) encoding the Aosta Valley DEM as a queryable function.
Training
| Dataset | Ethgar/skyfull-aosta-rescue-v1 |
| Episodes | 10,000 |
| Train/val split | 90 / 10 |
| Epochs | 200 |
| Optimizer | Adam, lr=3e-3, cosine annealing |
| Batch size | 512 |
| Hardware | MacBook Air M2 (MPS) |
| Training time | < 90 seconds |
Performance
| Metric | Value |
|---|---|
| Endpoint error (mean) | 16 m |
| Endpoint error (median) | 14 m |
| Endpoint error (p90) | 27 m |
| Terrain violations | 0 / 1,000 (val set) |
Quick start
import torch, numpy as np
from huggingface_hub import hf_hub_download
# Load policy
ckpt = torch.load(hf_hub_download("Ethgar/skyfull-policy-aosta-rescue-v1", "policy_v1.pt"), weights_only=False)
norm = ckpt['norm']
# Define model (copy SkyfullPolicy or pip install skyfull when available)
import torch.nn as nn
class SkyfullPolicy(nn.Module):
def __init__(self, hidden=256, depth=3, in_dim=3, out_dim=120):
super().__init__()
layers = [nn.Linear(in_dim, hidden), nn.SiLU()]
for _ in range(depth - 1):
layers += [nn.Linear(hidden, hidden), nn.SiLU()]
layers.append(nn.Linear(hidden, out_dim))
self.net = nn.Sequential(*layers)
def forward(self, x): return self.net(x)
model = SkyfullPolicy(hidden=ckpt['hidden'], depth=ckpt['depth'])
model.load_state_dict(ckpt['state_dict'])
model.eval()
# Predict trajectory to a victim (lon, lat, elev)
CITY_BASE = (7.0673, 45.7402)
victim = (7.14, 45.82, 2100.0) # lon, lat, elev_m
x_raw = np.array([victim[0] - CITY_BASE[0],
victim[1] - CITY_BASE[1],
victim[2]], dtype=np.float32)
x_norm = (x_raw - norm['x_mean']) / norm['x_std']
with torch.no_grad():
y_norm = model(torch.from_numpy(x_norm).unsqueeze(0)).numpy()[0]
traj = y_norm.reshape(40, 3) * norm['y_std'] + norm['y_mean']
print(traj.shape) # (40, 3) โ lon, lat, alt_m per waypoint
Tile coverage
Morgex / Arpy col, Valle d'Aosta, Italy. lat [45.73, 45.85] ยท lon [7.0, 7.22]
The model is specialised to this tile. For other regions, retrain on a new terrain tile using the Skyfull pipeline (terrain.py โ dataset.py โ train.py).
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐ Ask for provider support