feat(training): add SFT demo conversion pipeline#29
Merged
Conversation
Convert annotated demo JSON files to JSONL training data compatible with ms-swift for Qwen3-VL fine-tuning. Handles coordinate conversion from [0,1] to [0,1000] range, generates <think> blocks from observation and intent fields, and accumulates action history across steps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support --mapping flag for pre-computed screenshot mapping JSON that
maps task_id -> {step_index -> screenshot_path}. This correctly handles
the coalesced step-to-raw-capture mapping (where step indices skip due
to merging). Also adds --captures-dir with DB-based fallback and
DOUBLE_CLICK/RIGHT_CLICK parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add system role message to training conversations matching qwen3vl_agent.SYSTEM_PROMPT - Add "Output exactly one action" / thinking instruction to user message matching _build_prompt() output - Add coordinate range validation warning for values outside [0, 1] - Add input schema validation for required demo/step fields - Remove broken _resolve_screenshots_from_db() and _resolve_screenshots_direct() fallbacks that produced silently wrong mappings for coalesced demos - Remove --screenshot-dir CLI arg (unreliable for coalesced demos) - Keep --mapping (recommended) and capture API as screenshot resolution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align convert_demos output with internal SFT format (images + messages), add train_from_jsonl() loader, --jsonl flag to train.py, --bundle flag to convert_demos and Lambda Labs train command. Enables training on annotated demo data without Episode objects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add OpenAdaptCallback for training_log.json output + early stop on loss - Fix _load_standard_model to use BitsAndBytesConfig for 4-bit quantization - Use AutoModelForImageTextToText (supports Qwen3-VL) instead of Qwen2VL class - Switch demo config to 2B model for fast iteration on A10 - Hide Azure ML Jobs panel when cloud_provider is not azure - Fix Lambda setup: remove uv.sources before uv sync on remote Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace rsync with `git archive HEAD | ssh tar` in sync_local_code() to send only committed tracked files (~10MB vs ~1.8GB with binary artifacts). Fix callback class MRO: _OpenAdaptCallback must precede TrainerCallback so our on_log/on_train_begin override the no-op base implementations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract _run_sft_training() shared by train_with_trl() and train_from_jsonl(), eliminating ~80 lines of duplicated SFTConfig, SFTTrainer instantiation, and training loop code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add early_stop_min_delta and early_stop_plateau_patience to stop training when loss stops improving by at least min_delta for N consecutive steps. Works alongside the existing absolute threshold. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GPU hosting options covers 24 platforms ranked by value for open-source projects needing free/credited GPU compute for VLM fine-tuning. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detailed analysis of first fine-tuning run: 27.24 → 9.77 loss (64% reduction) over 50 steps on 20 annotated WAA demo samples. Includes per-epoch breakdown, compute efficiency metrics, and recommendations for future training runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove screenshot_mapping.json (has absolute local paths), add to .gitignore, add screenshot_mapping.example.json instead - Fix LoRA task_type: always use CAUSAL_LM (Qwen-VL is decoder-only, not encoder-decoder like T5/BART that needs SEQ_2_SEQ_LM) - Add 57 tests for convert_demos (action parsing, coordinate conversion, step conversion, validation, bundle creation) and training callback (log writing, threshold early stopping, plateau detection) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wire lr_scheduler_type, weight_decay, max_grad_norm, target_modules from YAML config through to SFTConfig (were silently ignored) - Fix command injection in lambda_labs.py via shlex.quote() - Fix callback writing loss=0 on non-loss log events (track _last_loss) - Fix WAIT() mapping to wait() instead of finished() in convert_demos - Fix CI: add --no-sources to uv sync for uv.sources compatibility - Add test for non-loss log event callback behavior - Update SYSTEM_PROMPT comment (remove stale cross-reference) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UV_NO_SOURCES=1 covers uv sync, uv run ruff, and uv run pytest. Integration tests require openadapt_evals which is not a dependency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add plot_training.py: generates loss curve, LR schedule, and combined plots from training_log.json using matplotlib - Copy training_log.json + plots into checkpoint directory after training so artifacts are self-contained and never lost - Add periodic rsync of training_log.json during Lambda training (every 5 min) so data survives instance interruption - Replace ASCII loss curve in training results doc with real PNG plots - Add reconstructed training_log.json from Qwen3-VL-2B demo run Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 tests covering: - Loss plot generation (with/without LR data) - Output directory creation and defaults - Empty data handling - Epoch boundary rendering - Real training log validation - Checkpoint co-location of log + plots Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
convert_demos.pyfor converting VLM-annotated demo JSON files into ms-swift SFT training format (JSONL)train_from_jsonl()to TRL trainer for training directly from JSONL bundles--jsonlflag totrain.pyfor JSONL-based training--bundleflag to Lambda Labs CLI for uploading training bundles_run_sft_training()min_delta+plateau_patience)git archivereplaces rsync (1.8GB → 10MB)Training Results (Qwen3-VL-2B)
First fine-tuning run completed on Lambda Labs A10 24GB:
checkpoints/qwen3vl2b_demo_lora/)Key observations:
docs/training_results_qwen3vl2b_demo.mdFiles Changed
openadapt_ml/training/convert_demos.pyopenadapt_ml/training/trl_trainer.pyopenadapt_ml/scripts/train.py--jsonlflag, plateau stopping configopenadapt_ml/cloud/lambda_labs.py--bundleupload, git archive syncconfigs/qwen3vl_demo.yamldocs/training_results_qwen3vl2b_demo.mddocs/gpu_hosting_options.mddocs/training_pipeline_gaps.mdTest plan
🤖 Generated with Claude Code