--- license: mit tags: - drone - rescue - trajectory-planning - alpine - geospatial - xyz-semantic - skyfull - pytorch library_name: pytorch --- # skyfull-policy-aosta-rescue-v1 Rescue drone trajectory policy trained on real Aosta Valley terrain. Part of [Skyfull](https://huggingface.co/datasets/Ethgar/skyfull-aosta-rescue-v1) — 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](https://huggingface.co/datasets/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 ```python 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).