Public research record for multi-source maritime trajectory forecasting and completion.
This repository records the current method, implementation, and experimental results of Traj-PathFormer, a patch-based trajectory forecasting model with time-conditioned future queries and local auxiliary-source completion.
- Author: Yongshuo Liu, Yuting Song
- Public record date: 2026-05-21
- License in the GitHub repository: MIT License
- Main research object: irregular ship trajectory forecasting with AIS, BDS, and radar observations
- Primary dataset used in the manuscript: Multi-Source Ship Trajectory Dataset (MSTD)
This README is intentionally detailed. It is written as a timestamped technical record of the model design, code organization, and current manuscript experiments.
Traj-PathFormer addresses trajectory prediction when historical maritime observations are irregular, locally incomplete, and available from heterogeneous sources. The method combines:
- A hierarchical patch encoder for irregular historical trajectories.
- Learnable time embeddings for both historical observations and future target intervals.
- Temporal-bias patch attention for local continuity and long-range context.
- A time-conditioned future query decoder that predicts future motion step by step.
- A local cross-attention completion branch that reconstructs missing target history from nearby auxiliary-source patches.
- Single-source and multi-source completion protocols for AIS, BDS, and radar.
The central idea is that future forecasting and missing-history completion should both be formulated as query-conditioned attention over trajectory patches, but with different context scopes:
- Forecasting attends over the global target-history memory.
- Completion attends over a local auxiliary-source memory near the missing target patch.
Given a historical trajectory sequence
X = {x_1, x_2, ..., x_L}, x_t in R^C
and a future interval sequence
delta = {delta_1, delta_2, ..., delta_H},
the model predicts normalized future motion increments
y_hat_norm = {y_hat_1_norm, ..., y_hat_H_norm}
and reconstructs future positions by cumulative integration. In velocity mode,
the physical displacement at step h is:
Delta p_hat_h = y_hat_h * delta_h
In displacement mode, the model directly predicts displacement increments.
The implementation supports:
- Single-target forecasting without auxiliary completion.
- Single-auxiliary completion, where one source completes another.
- Multi-auxiliary completion, where two auxiliary sources provide joint evidence.
- Empty-patch corruption, where all observations in selected patches are removed.
- Sparse-patch corruption, where only a few observations remain in selected patches.
The current manuscript experiments use the Multi-Source Ship Trajectory Dataset (MSTD) collected from Bohai Bay, Shandong Province.
Current curated dataset statistics:
| Item | Value |
|---|---|
| Complete trajectory groups | 2,107 |
| Complete three-source groups | 2,107 |
| Total observations | 566,045 |
| Sources | BDS, AIS, radar |
| Region | Bohai Bay, Shandong Province |
| Median BDS observations per sequence | 124 |
| Median AIS observations per sequence | 94 |
| Median radar observations per sequence | 54 |
| Median BDS sampling interval | about 1.98 min |
| Median AIS sampling interval | about 1.98 min |
| Median radar sampling interval | about 4.98 min |
The three sources describe related vessel motion but are not point-wise aligned. They differ in sampling density, local continuity, spatial noise, and source reliability. This motivates patch-level fusion instead of direct point-wise replacement.
The repository also contains preprocessing support for an independently processed BDS-AIS merged benchmark. In that benchmark, BDS and AIS trajectories are restricted to their shared temporal overlap, interpolated onto a fixed 76-step grid, and fused by equal-weight averaging. The first 64 steps are used as history and the last 12 steps as the prediction target.
The historical sequence is partitioned into N patches. Each patch contains up
to P observations:
L = N * P
Current common settings:
| Setting | Value |
|---|---|
Number of patches N |
8 |
| Single-trajectory patch length | 8 points |
| MSTD pair-completion max points per patch | 16 points |
| Future horizon | 12 steps |
| Hidden dimension | 128 |
| Attention heads | 4 |
| Patch duration in MSTD completion | 15 min |
For point-based pair completion, each point uses six physical features:
x, y, speed, course_sin, course_cos, dt
For single-trajectory baselines, a source_id channel is also supported:
x, y, speed, course_sin, course_cos, dt, source_id
The coordinate channels are represented in a local Cartesian frame relative to the last historical observation. Motion targets are normalized by training-set statistics and converted back to physical displacement for trajectory loss and evaluation.
Within each patch, the interval channel is embedded by a learnable time embedding. The point representation is:
z_{n,p} = concat(x_{n,p}, time_embed(dt_{n,p}))
The implementation uses IntraPatchPointGAT to model point interactions within
each patch, followed by masked aggregation. Empty points are masked out, and
patch validity is computed from the point mask.
Relevant implementation:
models/patch_forecaster.pytrain_pair_patch_cross_completion.py
Local patch tokens are contextualized with two components:
PatchGraphAttention, which adds an explicit temporal-distance bias.- A Transformer encoder over the patch sequence.
The temporal bias favors nearby historical patches while preserving global interaction:
b_ij = log(exp(-abs(i - j) * Delta_p / tau) + eps)
This design captures both local vessel-motion continuity and longer-range route context.
Forecasting is not performed by a single global regression head. Instead, Traj-PathFormer builds one query per future step.
The decoder first constructs a global anchor from:
- the last valid historical observation;
- the contextual token of the last valid patch.
For future step h, the query contains:
- the global historical anchor;
- a learnable embedding of
log(1 + delta_h); - a learnable future-step identity embedding.
The query attends to the historical patch memory through multi-head cross-attention. The step decoder then predicts the normalized future motion.
This is important for irregular trajectories because each future step may have a different target time interval.
Relevant implementation:
models/time_query_forecaster.pymodels/patch_forecaster.pytrain_ours_singletraj_noslide.pytrain_pair_patch_cross_completion.py
When target-source history is incomplete, the model completes the missing target patch in latent patch-token space before forecasting.
For a missing target patch, the model:
- Encodes the corrupted target stream.
- Encodes the auxiliary source stream.
- Contextualizes auxiliary patches with source-specific patch attention.
- Selects the nearest valid auxiliary patches by patch start time.
- Builds a completion query from:
- the masked target local token;
- target patch temporal features;
- patch index embedding;
- left local auxiliary context;
- right local auxiliary context;
- average auxiliary local summary.
- Uses local cross-attention over the selected auxiliary chunk.
- Applies a learned gate to mix the completed token and the original masked target token.
- Replaces only the masked target patch tokens.
The current implementation supervises latent patch completion with MSE between the completed target token and the fully observed target token. The completion loss is jointly optimized with motion, trajectory, and endpoint losses.
Relevant implementation:
PairPatchCrossCompletionModelintrain_pair_patch_cross_completion.pyevaluate_mstd_source_completion.pyevaluate_mstd_local_patch_length.pyevaluate_mstd_model_ablation.py
The experiments compare the following protocols:
| Protocol | Meaning |
|---|---|
| No Completion | Forecast directly from corrupted target history. |
| Linear Interpolation | Use target-source boundary/interpolated patch tokens only. No auxiliary source is used. |
| Direct Source Fill | Copy the nearest auxiliary-source patch into the missing target patch. |
| Single-Source Cross-Attn. | Complete target history from one auxiliary source through local cross-attention. |
| Multi-Source Cross-Attn. | Use two auxiliary sources jointly through cross-attention fusion. |
For terminal missing patches, target-source interpolation becomes boundary filling because no right-side target patch exists.
The forecasting loss combines:
L = lambda_motion * L_motion
+ lambda_traj * L_traj
+ lambda_final * L_final
where:
L_motionsupervises normalized per-step motion increments.L_trajsupervises reconstructed normalized future positions.L_finalsupervises the endpoint.
For completion models, the total loss adds latent patch completion:
L_all = L + lambda_completion * L_completion
Current default weights in the main experiments are:
lambda_motion = 1.0
lambda_traj = 1.0
lambda_final = 1.0
lambda_completion = 1.0
Core model files:
| File | Purpose |
|---|---|
models/patch_forecaster.py |
Patch encoder, temporal bias attention, losses, patch forecasting backbone. |
models/time_query_forecaster.py |
Time-conditioned future query forecaster. |
train_pair_patch_cross_completion.py |
Pairwise target/auxiliary cross-attention completion model. |
models/baseline_forecasters.py |
Runnable baseline forecasters used in comparisons. |
motion_dataset.py |
Single-trajectory dataset loader. |
pair_patch_data.py |
Pair patch construction, normalization, and cache utilities. |
trajectory_eval_utils.py |
Lat/lon conversion, trajectory metrics, DTW. |
Training and evaluation scripts:
| File | Purpose |
|---|---|
preprocess_motion_data.py |
Preprocess raw AIS JSONL into motion-target NPZ data. |
preprocess_newdata_bds_ais_merged.py |
Build the BDS-AIS merged no-sliding benchmark. |
train_ours_singletraj_noslide.py |
Train the single-target Traj-PathFormer forecaster. |
quick_singletraj_baseline_suite.py |
Train compact comparison baselines. |
evaluate_trajectory_metrics.py |
Evaluate Avg L2, Avg MSE, Avg DTW. |
evaluate_table2_pair_protocols.py |
Evaluate missing/sparse pair-completion protocols. |
evaluate_mstd_source_completion.py |
Evaluate source selection and multi-source completion on MSTD. |
evaluate_mstd_local_patch_length.py |
Evaluate local auxiliary patch length settings. |
run_mstd_local_patch_length_retrain.py |
Retrain local auxiliary patch length variants from 1 to 8. |
evaluate_mstd_model_ablation.py |
Evaluate architecture and completion ablations. |
plot_mstd_local_patch_length_predictions.py |
Generate the 1-to-8 local patch length prediction figure. |
run_missing_last2_multimodel_comparison.py |
Run recent-history missing-patch multi-model comparison. |
Manuscript files:
| File | Purpose |
|---|---|
paper/methodology_en.tex |
Current English methodology section. |
paper/experiments_en.tex |
Current English experiments section and tables. |
paper/figures/mstd_dataset_overview.* |
Dataset visualization. |
paper/figures/local_patch_length_predictions.* |
Prediction example for local auxiliary patch lengths 1 to 8. |
Unless otherwise stated:
- Train/validation/test split: 60% / 20% / 20% for MSTD source-completion experiments.
- Single-target no-sliding forecasting: each original trajectory group contributes at most one sample.
- Input history: 8 patches.
- Prediction horizon: 12 future steps.
- Metrics:
- Avg L2 distance;
- Avg MSE;
- Avg DTW.
- Lower is better for every reported metric.
This experiment evaluates single-target forecasting without historical corruption. It compares recurrent, patch-based, graph-based, irregular time-series, continuous-time, and neural-flow style baselines.
| Method | Avg L2 | Avg MSE | Avg DTW |
|---|---|---|---|
| Ours | 0.003260 | 0.00001875 | 0.032463 |
| AGDN | 0.004701 | 0.00003416 | 0.045685 |
| TLSTM | 0.004457 | 0.00003063 | 0.043179 |
| T-PatchGNN | 0.009282 | 0.00008465 | 0.107036 |
| DLinear | 0.004362 | 0.00002915 | 0.043687 |
| TimesNet | 0.004652 | 0.00002963 | 0.045639 |
| PatchTST | 0.005077 | 0.00003174 | 0.051094 |
| Crossformer | 0.004281 | 0.00002766 | 0.041038 |
| Graph WaveNet | 0.004603 | 0.00003175 | 0.045384 |
| MTGNN | 0.004723 | 0.00003397 | 0.046464 |
| StemGNN | 0.004445 | 0.00002788 | 0.045406 |
| CrossGNN | 0.004220 | 0.00002559 | 0.041731 |
| FourierGNN | 0.004438 | 0.00002473 | 0.044792 |
| GRU-D | 0.004419 | 0.00002861 | 0.042718 |
| SeFT | 0.007802 | 0.00007024 | 0.086307 |
| RainDrop | 0.005834 | 0.00004123 | 0.058391 |
| Warpformer | 0.004280 | 0.00002633 | 0.042219 |
| mTAND | 0.008375 | 0.00007512 | 0.092223 |
| Latent-ODE | 0.004294 | 0.00002745 | 0.041619 |
| CRU | 0.004482 | 0.00003031 | 0.043251 |
| Neural Flow | 0.004070 | 0.00002432 | 0.040065 |
On MSTD, Traj-PathFormer achieves the lowest Avg L2, Avg MSE, and Avg DTW among the compared methods.
| Method | Avg L2 | Avg MSE | Avg DTW |
|---|---|---|---|
| Ours | 0.013421 | 0.00108327 | 0.156698 |
| AGDN | 0.010762 | 0.00094231 | 0.126118 |
| TLSTM | 0.011759 | 0.00103357 | 0.138022 |
| T-PatchGNN | 0.016382 | 0.00101861 | 0.184140 |
| DLinear | 0.011100 | 0.00095051 | 0.129720 |
| TimesNet | 0.011268 | 0.00097475 | 0.131185 |
| PatchTST | 0.012609 | 0.00109108 | 0.147368 |
| Crossformer | 0.012275 | 0.00109618 | 0.144517 |
| Graph WaveNet | 0.011210 | 0.00094534 | 0.128694 |
| MTGNN | 0.011074 | 0.00095406 | 0.127711 |
| StemGNN | 0.011646 | 0.00093356 | 0.133614 |
| CrossGNN | 0.012016 | 0.00093541 | 0.138024 |
| FourierGNN | 0.011591 | 0.00093907 | 0.132043 |
| GRU-D | 0.012133 | 0.00104358 | 0.139772 |
| SeFT | 0.014300 | 0.00094474 | 0.161112 |
| RainDrop | 0.013321 | 0.00096788 | 0.150508 |
| Warpformer | 0.011461 | 0.00093680 | 0.132932 |
| mTAND | 0.012907 | 0.00101733 | 0.148480 |
| Latent-ODE | 0.011413 | 0.00101142 | 0.133851 |
| CRU | 0.011567 | 0.00101814 | 0.136204 |
| Neural Flow | 0.011535 | 0.00102779 | 0.135759 |
On the BDS-AIS merged benchmark, AGDN obtains the best Avg L2 and Avg DTW, while StemGNN obtains the best Avg MSE. This indicates that averaging multiple sources into one fused single trajectory changes the evaluation distribution and reduces the benefit of explicitly modeling source-specific auxiliary relationships.
This experiment evaluates forecasting when historical observations are
incomplete. Empty-patch corruption removes all observations in selected patches,
while sparse-patch corruption keeps only a few observations. The full trend is
reported as a line chart in paper/figures/missing_sparse_robustness.png.
Across empty and sparse corruption levels, cross-attention completion gives the
best or near-best Avg L2, Avg MSE, and Avg DTW.
This experiment removes the two historical patches immediately before the final observed patch. Baseline forecasters use the target source only. Traj-PathFormer is evaluated with both target-source linear interpolation and paired-source cross-attention completion.
| Method | Protocol | Avg L2 | Avg MSE | Avg DTW | Protocol | Avg L2 | Avg MSE | Avg DTW |
|---|---|---|---|---|---|---|---|---|
| AGDN | No Comp. | 0.013663 | 0.00022450 | 0.162183 | Linear Interp. | 0.012814 | 0.00020925 | 0.151432 |
| TLSTM | No Comp. | 0.013759 | 0.00022564 | 0.163125 | Linear Interp. | 0.013033 | 0.00021301 | 0.153574 |
| T-PatchGNN | No Comp. | 0.013897 | 0.00022516 | 0.164743 | Linear Interp. | 0.013303 | 0.00021297 | 0.156902 |
| DLinear | No Comp. | 0.013731 | 0.00022423 | 0.162820 | Linear Interp. | 0.012964 | 0.00021063 | 0.152658 |
| TimesNet | No Comp. | 0.013695 | 0.00022410 | 0.162583 | Linear Interp. | 0.012980 | 0.00021041 | 0.152975 |
| PatchTST | No Comp. | 0.013833 | 0.00022567 | 0.164345 | Linear Interp. | 0.012685 | 0.00020587 | 0.150017 |
| Crossformer | No Comp. | 0.013886 | 0.00022617 | 0.165056 | Linear Interp. | 0.012712 | 0.00020584 | 0.150408 |
| Graph WaveNet | No Comp. | 0.013770 | 0.00022425 | 0.163208 | Linear Interp. | 0.013050 | 0.00021113 | 0.153648 |
| MTGNN | No Comp. | 0.013769 | 0.00022487 | 0.163453 | Linear Interp. | 0.013054 | 0.00021187 | 0.153979 |
| StemGNN | No Comp. | 0.013767 | 0.00022519 | 0.163292 | Linear Interp. | 0.012954 | 0.00021215 | 0.152819 |
| CrossGNN | No Comp. | 0.013711 | 0.00022288 | 0.162655 | Linear Interp. | 0.012819 | 0.00020868 | 0.151478 |
| FourierGNN | No Comp. | 0.013816 | 0.00022541 | 0.163935 | Linear Interp. | 0.012996 | 0.00021265 | 0.153223 |
| GRU-D | No Comp. | 0.013769 | 0.00022420 | 0.163237 | Linear Interp. | 0.013058 | 0.00021169 | 0.153869 |
| SeFT | No Comp. | 0.013746 | 0.00022373 | 0.163190 | Linear Interp. | 0.012886 | 0.00020816 | 0.151930 |
| RainDrop | No Comp. | 0.013790 | 0.00022445 | 0.163211 | Linear Interp. | 0.013021 | 0.00021116 | 0.152928 |
| Warpformer | No Comp. | 0.013715 | 0.00022300 | 0.162832 | Linear Interp. | 0.012957 | 0.00020877 | 0.152918 |
| mTAND | No Comp. | 0.013689 | 0.00022254 | 0.162573 | Linear Interp. | 0.012877 | 0.00020822 | 0.152046 |
| Latent-ODE | No Comp. | 0.013747 | 0.00022436 | 0.162977 | Linear Interp. | 0.013001 | 0.00021186 | 0.153184 |
| CRU | No Comp. | 0.013762 | 0.00022473 | 0.162973 | Linear Interp. | 0.013008 | 0.00021219 | 0.153111 |
| Neural Flow | No Comp. | 0.013701 | 0.00022421 | 0.162741 | Linear Interp. | 0.012969 | 0.00021127 | 0.152975 |
| Ours | Linear Interp. | 0.003058 | 0.00001334 | 0.031027 | Cross-Attn. | 0.003026 | 0.00001336 | 0.031268 |
The proposed cross-attention completion gives the lowest Avg L2 among all target-only no-completion, target-source interpolation, and Traj-PathFormer interpolation variants.
Install dependencies:
pip install -r requirements.txtPreprocess single-stream trajectory data:
python preprocess_motion_data.py \
--input-jsonl data/raw/dual_ais_level2_shape_aggressiveC_pointclean_ema_recomputed_outlierdrop200.jsonl \
--output-dir data/singletraj_pair \
--source-mode traj_a \
--history-steps 64 \
--future-steps 12 \
--window-stride 1000000 \
--target-mode velocityTrain the single-target Traj-PathFormer forecaster:
python train_ours_singletraj_noslide.py \
--data-dir data/singletraj_pair \
--workdir workdir_ours_singletraj_noslide \
--device cuda:0 \
--epochs 60 \
--batch-size 64 \
--lr 3e-4 \
--amp \
--tf32Train the pairwise cross-attention completion model:
python train_pair_patch_cross_completion.py \
--input-jsonl data/raw/dual_ais_level2_shape_aggressiveC_pointclean_ema_recomputed_outlierdrop200.jsonl \
--workdir workdir_pair_cross_completion \
--cache-dir workdir_pair_cross_completion/data_cache_rawpair \
--anchor-key traj_a \
--sender-key traj_b \
--no-sliding-window \
--device cuda:0 \
--epochs 20 \
--batch-size 64 \
--lr 1e-4 \
--amp \
--tf32Evaluate pairwise missing/sparse completion protocols:
python evaluate_table2_pair_protocols.py \
--exp-dir workdir_pair_cross_completion/experiments/<experiment_name> \
--cache-dir workdir_pair_cross_completion/data_cache_rawpair \
--split test \
--device cuda:0 \
--batch-size 128Retrain local auxiliary patch lengths from 1 to 8:
python run_mstd_local_patch_length_retrain.py \
--gpus 0,1 \
--batch-size 32 \
--workdir /tmp/mstd_local_patch_length_retrain \
--resumeGenerate the local patch length prediction figure:
python plot_mstd_local_patch_length_predictions.py \
--workdir /tmp/mstd_local_patch_length_retrain \
--target AIS \
--aux BDS \
--sample-index 199 \
--device cpu \
--output-prefix paper/figures/local_patch_length_predictionsThe repository intentionally excludes large or transient artifacts:
- raw datasets;
- generated
.npzcaches; - model checkpoints;
- training logs;
workdir*experiment directories;- Python caches.
These are ignored by .gitignore and should be stored separately from the
public source-code record.
This repository contains the research code, manuscript method text, manuscript experiment text, and table-level results for the current Traj-PathFormer work. The README records the current technical contribution and experimental evidence as of 2026-05-21.
For formal academic use, please cite the repository commit or the corresponding paper once available.