What This Skill Does
Replace single-component trajectory encoding and loss functions with three complementary modifications: position-invariant grid-anchor encoding (eliminates location bias), spatiotemporal consistency regularizers for VAE (enforces motion realism), and on-policy boundary-anchored flow refinement (reduces long-horizon drift).
Component 1: Grid-Anchor Offset Encoding
Old component: Absolute pixel coordinates for trajectory points, which entangle motion representation with global position.
def encode_trajectory_absolute(trajectory):
return trajectory
New component: Offset from fixed grid anchors removes location-dependent statistics.
def encode_trajectory_grid_anchor(trajectory, grid_size=8):
"""
Express each point as offset from its grid cell anchor.
Removes location-driven variance that confuses motion learning.
"""
T, P, _ = trajectory.shape
offsets = torch.zeros_like(trajectory)
for p in range(P):
point_xy = trajectory[:, p]
grid_cell = (point_xy / grid_size).long()
grid_anchor = grid_cell * grid_size
offsets[:, p] = point_xy - grid_anchor.float()
return offsets
Impact: Reduces coordinate variance driven by location from ~90% to ~10%, making motion patterns consistent and learnable across image regions.
Component 2: Spatiotemporal Consistency Regularizers for VAE
Old component: Standard VAE with only pointwise reconstruction loss L_recon, ignoring temporal and spatial coherence.
class StandardVAE(nn.Module):
def forward(self, trajectory):
z = self.encode(trajectory)
recon = self.decode(z)
loss = F.mse_loss(recon, trajectory)
return recon, loss
New component: Augment with temporal velocity matching and multi-scale spatial neighbor consistency.
class TrajLoomVAE(nn.Module):
def __init__(self, encoder, decoder, lambda_temporal=0.1, lambda_spatial=0.05):
super().__init__()
self.encoder = encoder
self.decoder = decoder
self.lambda_temporal = lambda_temporal
self.lambda_spatial = lambda_spatial
def forward(self, trajectory):
z = self.encode(trajectory)
recon = self.decode(z)
loss_recon = F.mse_loss(recon, trajectory)
vel_target = trajectory[1:] - trajectory[:-1]
vel_recon = recon[1:] - recon[:-1]
loss_temporal = F.mse_loss(vel_recon, vel_target)
loss_spatial = 0
for scale in [1, 2, 4]:
for p in range(trajectory.shape[1] - scale):
neighbor_dist_target = torch.norm(
trajectory[:, p] - trajectory[:, p + scale],
dim=-1
)
neighbor_dist_recon = torch.norm(
recon[:, p] - recon[:, p + scale],
dim=-1
)
loss_spatial += F.mse_loss(neighbor_dist_recon, neighbor_dist_target)
total_loss = (
loss_recon +
.lambda_temporal * loss_temporal +
.lambda_spatial * loss_spatial
)
recon, total_loss
Impact on 81-frame prediction:
- Without regularizers: VEPE = 29.35–63.09 pixels (large jitter)
- With TrajLoom-VAE: VEPE = 1.59–2.04 pixels (30–40× improvement)
Component 3: Boundary-Anchored On-Policy Flow Fine-Tuning
Old component: Rectified flow trained on interpolated states, creating train-test mismatch during ODE sampling.
class StandardFlow(nn.Module):
def forward(self, z, t):
return self.velocity_net(z, t)
New component: Anchor boundary conditions and fine-tune on self-visited ODE states.
class TrajLoomFlow(nn.Module):
def __init__(self, velocity_net):
super().__init__()
self.velocity_net = velocity_net
def forward(self, z_0, num_steps=100):
"""Standard ODE solution with boundary hints."""
z = z_0.clone()
dt = 1.0 / num_steps
for step in range(num_steps):
t = step / num_steps
vel = self.velocity_net(z, t)
z = z + vel * dt
return z
def on_policy_finetune(self, z_0_batch, target_z_1_batch, K=5):
"""
Fine-tune on actual ODE trajectories (not interpolations).
K-step rollout: solve ODE, compute loss, backprop.
"""
optimizer = torch.optim.Adam(self.velocity_net.parameters(), lr=1e-4)
for _ in range(K):
z_trajectory = self.forward(z_0_batch, num_steps=50)
loss_endpoint = F.mse_loss(z_trajectory, target_z_1_batch)
vel_pred = (z_trajectory[1:] - z_trajectory[:-1]) / (1/50)
vel_smooth = torch.norm(vel_pred[:] - vel_pred[:-])
loss_smooth = vel_smooth.mean()
loss = loss_endpoint + * loss_smooth
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss.item()
Boundary hint mechanism:
- Anchor z₀ (last history token) and z₁ (target future state)
- ODE solver is constrained to respect endpoints, reducing divergence
Impact on 81-frame flow-based generation:
- FVMD (flow velocity magnitude distance): 4872 → 1338 (2.5–3.6× reduction)
- FlowTV (temporal variance): substantially reduced
- DivCurlE (spatial discontinuities): eliminated
Performance Summary
| Component | Metric | Before | After | Improvement |
|---|
| Offset Encoding | Location variance explained | 90% | 10% | 80pp reduction |
| TrajLoom-VAE | VEPE (81 frames) | 29.35–63.09 px | 1.59–2.04 px | 30–40× |
| Flow + Boundary | FVMD | 4872 | 1338 | 2.5–3.6× |
When to Use
- Predicting extended trajectories (≥81 frames)
- Tasks where temporal coherence matters (autonomous driving, video prediction)
- When training data is limited (VAE regularizers prevent overfitting to jittery patterns)
- Applications sensitive to local motion smoothness (motion capture, character animation)
- Generative models where perceptual quality of generated trajectories is critical
When NOT to Use
- Short-horizon prediction (<10 frames): overhead not justified
- Sparse trajectories: grid-anchor encoding assumes dense point clouds
- Tasks where absolute global coordinates are semantically meaningful
- Real-time applications with strict latency budgets (flow fine-tuning adds compute)
Implementation Checklist
1. Replace coordinate encoding:
trajectory_encoded = encode_trajectory_grid_anchor(
trajectory,
grid_size=8
)
2. Augment VAE loss:
vae = TrajLoomVAE(
encoder=your_encoder,
decoder=your_decoder,
lambda_temporal=0.1,
lambda_spatial=0.05
)
3. Optional: fine-tune flow model on-policy:
flow_model.on_policy_finetune(
z_0_batch=observed_latents,
target_z_1_batch=future_latents,
K=5
)
4. Verification:
- Measure VEPE (endpoint error) on 81-frame prediction
- Check temporal smoothness: velocity should vary slowly
- Ablate: remove each component to confirm individual contributions
5. Hyperparameter tuning:
- Grid size: 8 works for 256×256 images; scale proportionally
- Lambda values: start with (0.1, 0.05); increase if jitter persists
- Flow steps: 50-100 steps balances speed vs. quality
- Boundary anchor weight: increase if ODE diverges at horizon
6. Known issues:
- Grid anchors may create boundary artifacts at image edges; use padding
- Spatial consistency loss is expensive for large point clouds (>1000 points)
- Flow fine-tuning requires second-order gradients; use lower-precision training if memory-limited
- Extrapolation beyond training horizon: consistency guarantees degrade
Related Work
Builds on rectified flows (Flow Matching, Liphardt et al.) and VAE regularization (β-VAE, annealed loss). Grid-anchor encoding parallels local coordinate systems in computer graphics and relates to positional normalization in transformers. Boundary-anchored fine-tuning generalizes active learning on ODE solvers.