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).

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support