Skip to content

feat(pytorch): migrate training and inference to PyTorch (v1.27.1)#34

Open
Yasas1994 wants to merge 64 commits into
mainfrom
pytorch_migration
Open

feat(pytorch): migrate training and inference to PyTorch (v1.27.1)#34
Yasas1994 wants to merge 64 commits into
mainfrom
pytorch_migration

Conversation

@Yasas1994

Copy link
Copy Markdown
Owner

Summary

  • Migrated Jaeger's training and inference stack from TensorFlow to PyTorch.
  • Added PyTorch model/layer modules (src/jaeger/nnlib/pytorch/).
  • Added PyTorch data pipeline (src/jaeger/data/pytorch/) supporting numpy_full, numpy_raw, and csv formats.
  • Added PyTorch training engine, Trainer, callbacks, and distributed helper (src/jaeger/training/pytorch/).
  • Updated jaeger train and jaeger predict CLI commands to use PyTorch.
  • Removed legacy TensorFlow training/inference code.
  • Updated SLURM scripts and Singularity container for PyTorch/CUDA.
  • Bumped version to 1.27.1 and updated CHANGELOG/README.

Test Plan

  • pytest tests/unit/ tests/integration/ passes (218 tests)
  • ruff check src/ tests/ and ruff format --check src/ tests/ pass
  • Wheel builds successfully (python -m build --wheel)
  • Smoke tests for train/predict pass

Breaking Changes

  • Old TensorFlow SavedModel checkpoints are no longer loadable. Users must retrain with PyTorch.
  • Options --xla, --quantized, --onnx, --int8 in jaeger predict are no longer supported.

Yasas1994 added 30 commits June 14, 2026 19:03
Yasas1994 added 30 commits June 15, 2026 12:30
… memory guard

- Switch training and inference paths to PyTorch.
- Add Numba JIT kernels for nucleotide/translated encoding in optimize-data.
- Add memory guard to refuse one-hot conversions that exceed available RAM.
- Add nucleotide/translated/DVF training configs.
- Update CLI, builders, layers, models, callbacks, engine, and trainer.
…eline config

- Add NativeSequential and a registry for native torch.nn layers
  (conv1d, linear, dropout, pooling, activations, shape helpers).
- Add SiameseModel that runs two identical native-layer branches on
  Jaeger's 2-strand nucleotide input and averages the outputs.
- Extend Embedding with onehot_dim so padding is always an all-zero
  vector and N can be excluded from the one-hot channels.
- Update ModelBuilder to detect model_type: siamese / branch_layers.
- Add train_config/nn_config_500bp_dvf.yaml DVF-style baseline.
- Add unit tests for Embedding onehot_dim, SiameseModel shapes, and
  builder siamese integration.
- Move src/jaeger/data/pytorch/ to src/jaeger/dataops/pytorch/.
- Move corresponding tests from tests/unit/data/pytorch/ to
  tests/unit/dataops/pytorch/.
- Update all imports from jaeger.data.pytorch to jaeger.dataops.pytorch.
- Update AGENTS.md so data/ is described as bundled data/model artifacts
  and dataops/ includes the pytorch dataset loaders/builders.
…s refactor docs

- Add loss_window_size parameter to train_one_epoch, evaluate, and Trainer.
- Track a deque of recent batch losses and display the moving average in
  the Rich progress bar instead of the noisy single-batch loss.
- Add unit test verifying the progress bar shows the moving average.
- Commit the AGENTS.md and CHANGELOG.md updates that were missed in the
  previous dataops move refactor.
The DVF baseline config contains user-specific paths and is tuned per
experiment. Remove it from version control and add it to .gitignore so it
can be edited locally without showing up in git status.
Replace the per-batch and moving-average loss displays with the
running mean over all batches processed so far in the current epoch.
This gives a smoother, more stable progress indicator.
- Instrument train_one_epoch and evaluate with time.perf_counter() to
  measure data loading, forward+loss, backward, optimizer step, and
  metrics update.
- Add profile flag to Trainer and a --profile CLI flag for jaeger train.
- When profiling is enabled, the progress bar shows per-section timings
  and the returned history includes average timing keys (time_*_ms).
The train command decorators for --progress-bar, -v/--verbose, and the
def train(**kwargs): definition were accidentally removed, leaving the
docstring dangling under --meta and breaking the CLI.

- Restore --progress-bar and -v/--verbose decorators.
- Add --profile flag to expose per-section timing in the progress bar.
- All 262 tests pass.
…eps from config

The PyTorch trainer was ignoring classifier_train_steps,
classifier_validation_steps, reliability_train_steps, and
reliability_validation_steps from the YAML config and always iterated
through the entire dataloader each epoch.

- Add train_steps and validation_steps parameters to train_one_epoch and
  evaluate; negative values or None keep the legacy unlimited behavior.
- Plumb the same parameters through Trainer.fit, including progress-bar
  totals.
- Read the step counts from the config in commands/train.py and pass them
  to Trainer for both classifier and reliability branches.
- Add unit tests verifying step limiting, -1/unlimited behavior, and
  config-to-Trainer propagation.

267 tests pass; ruff clean.
The per-section timings shown with --profile measured only CPU-side
kernel-launch latency, not actual GPU execution time. Because CUDA ops are
asynchronous, the real forward/backward/optimizer work completed later at
implicit sync points (e.g. loss.item()), leaving most wall-clock time
unaccounted (e.g. validation reported ~2 ms of section time vs ~40 ms/batch
real average).

- Add _maybe_synchronize() helper that calls torch.cuda.synchronize() only
  when profile=True and device.type == 'cuda'.
- Place sync boundaries around data, forward, backward, optimizer, and
  metrics sections in train_one_epoch and evaluate so each measured interval
  includes the real GPU work.
- Non-profiling runs and CPU runs are unaffected.
- Add unit tests for _maybe_synchronize behavior.

270 tests pass; ruff clean.
Training would silently write into an existing checkpoint directory,
potentially overwriting prior work. Users must now explicitly choose to
overwrite with --force or resume with --from_last_checkpoint.

- Add _has_checkpoints() and _guard_against_overwrite() helpers.
- Before classifier/reliability training, raise a ClickException if the
  checkpoint directory already contains .pt files and neither --force nor
  --from_last_checkpoint is set.
- --force continues to delete existing checkpoint directories first.
- --from_last_checkpoint continues to load the latest .pt checkpoint and
  train.
- Add tests for refusal, --force overwrite, and --from_last_checkpoint
  resume paths.

273 tests pass; ruff clean.
Loading a checkpoint on CPU then moving the model to CUDA left the
optimizer's param_groups pointing at stale CPU tensors and the optimizer
state on CPU. optimizer.step() then crashed with:
  Expected all tensors to be on the same device, but found at least two
  devices, cuda:0 and cpu!

- Move rep_model, jaeger_classifier, and reliability_head to the target
  device immediately after lazy-layer initialization and before building
  optimizers.
- Pass the target device into _load_checkpoint_if_requested() and use
  map_location=device so checkpoint tensors land directly on the target
  device.
- Add a unit test verifying resumed optimizer state is mapped to the
  requested device.

274 tests pass; ruff clean.
Replace the hardcoded adam/sgd/rmsprop map with a case-insensitive
lookup over torch.optim classes. This makes AdamW, NAdam, RAdam, and
any future PyTorch optimizer available via training.optimizer.

- Empty/missing optimizer names still default to Adam.
- Unknown names raise a ValueError listing available optimizers.
- Add unit tests for AdamW resolution, case-insensitivity, default,
  and unknown-name handling.
--from_last_checkpoint previously always started training from epoch 1,
ignoring the epoch stored in the checkpoint. This caused it to re-train
already-completed epochs or overwrite previous checkpoints.

- _load_checkpoint_if_requested() now returns the epoch stored in the
  checkpoint (default 0).
- Trainer accepts a start_epoch argument and trains from
  start_epoch + 1 through classifier_epochs.
- If start_epoch >= epochs, training is skipped and a message is logged.
- Add tests for resumed epoch ranges and skipping when no epochs remain.

281 tests pass; ruff clean.
Add two commonly requested PyTorch-style callbacks and wire them into the
config-based callback builder.

- ReduceLROnPlateau: lowers LR by factor after patience epochs of
  no improvement on monitor, down to min_lr.
- TerminateOnNaN: stops training when the monitored metric becomes NaN or Inf.
- Update _SUPPORTED_CALLBACKS and _build_callbacks in commands/train.py to
  instantiate them from YAML config entries.
- Add unit tests for both callbacks.

283 tests pass; ruff clean.
The Trainer was unconditionally writing checkpoint_epoch_{epoch}.pt files
in addition to the optional ModelCheckpoint callback. This produced
redundant checkpoint files and duplicated responsibilities.

- Remove Trainer.checkpoint_dir and Trainer._save_checkpoint().
- Remove checkpoint_dir argument from Trainer instantiation in
  commands/train.py.
- Rely on the ModelCheckpoint callback for all checkpoint saving.
- Fix ModelCheckpoint so save_best_only=False also saves the first epoch
  (previously it skipped the first epoch because best_value always
  improved from the initial value).
- Update tests to remove checkpoint_dir usage and add ModelCheckpoint to
  the default test config so resume/overwrite tests still work.

283 tests pass; ruff clean.
Add a config-driven JsonLogger callback for saving per-epoch metrics and
remove the Trainer's built-in history.json saving for consistency with the
ModelCheckpoint-only approach.

- JsonLogger writes a JSON array of epoch logs; append=True loads existing
  history and extends it (useful for resumed runs).
- Wire JsonLogger into commands/train.py _build_callbacks.
- Remove Trainer.history_path and Trainer._save_history().
- Update commands/train.py to stop passing history_path.
- Update tests and add JsonLogger-specific tests.

286 tests pass; ruff clean.
Replace hardcoded per-class precision/recall with a config-driven metric
builder supporting categorical_accuracy, binary_accuracy, precision, recall,
per_class_precision, per_class_recall, auc, and per_class_auc.

- Add metric classes: CategoricalAccuracy, BinaryAccuracy, Precision, Recall,
  AUC, AUCForClass.
- Update PrecisionForClass/RecallForClass to handle both one-hot and index
  labels via _as_class_indices().
- Add build_metrics() dispatcher that parses metrics_classifier and
  metrics_reliability config lists.
- ModelBuilder.get_metrics() now delegates to build_metrics().
- Add unit tests for new metrics and config-driven builder.

291 tests pass; ruff clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant