freesolo-flash-dev 1.0.83__tar.gz → 1.0.85__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/catalog.py +4 -2
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/__init__.py +4 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/adapter.py +31 -3
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/backend_common.py +67 -12
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_train.py +9 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/lifecycle.py +16 -7
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rl_train.py +45 -3
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/sft_train.py +7 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_allocator.py +46 -10
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_backend_common.py +137 -1
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_gpus_flag.py +7 -2
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_analytical.py +14 -10
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_gpus.py +41 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_resident_sizing.py +28 -17
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd.py +8 -3
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_train.py +18 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_rl_train.py +160 -2
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_api.py +4 -4
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_gc_off.py +28 -5
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_train.py +17 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vram_architecture.py +12 -5
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_stack.py +32 -2
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/uv.lock +1 -1
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.env.example +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/README.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/TRAINING.md +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_eval.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo_plugin.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/multiturn_glue.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_plugin.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_structured.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/teacher_encoding.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_limits.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_validation.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/weight_cache_preload.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/db.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/projects.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/thinking.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_thinking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.85
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
|
@@ -466,16 +466,18 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
466
466
|
# vllm 0.19.1 derives the 1,097,728-byte gdn state page as 1072 fp8 attention
|
|
467
467
|
# tokens after the 16-token backend alignment.
|
|
468
468
|
mamba_block_size=1072,
|
|
469
|
-
# peft targets
|
|
470
|
-
#
|
|
469
|
+
# peft targets ordinary linears plus both fused routed-expert tensors on every layer.
|
|
470
|
+
# each routed tensor has 256 expert slices, all using the adapter's uniform serving rank.
|
|
471
471
|
lora_target_shapes=(
|
|
472
472
|
(512, 2048, 40),
|
|
473
|
+
(512, 2048, 10_240),
|
|
473
474
|
(1152, 1152, 27),
|
|
474
475
|
(1152, 3456, 27),
|
|
475
476
|
(1152, 4304, 27),
|
|
476
477
|
(2048, 1, 40),
|
|
477
478
|
(2048, 32, 60),
|
|
478
479
|
(2048, 512, 100),
|
|
480
|
+
(2048, 1024, 10_240),
|
|
479
481
|
(2048, 4096, 30),
|
|
480
482
|
(2048, 8192, 40),
|
|
481
483
|
(4096, 2048, 40),
|
|
@@ -22,10 +22,12 @@ from flash.engine.worker.adapter import (
|
|
|
22
22
|
_download_adapter,
|
|
23
23
|
_init_adapter_model,
|
|
24
24
|
_resolve_adapter_ref,
|
|
25
|
+
lora_target_parameters,
|
|
25
26
|
make_lora,
|
|
26
27
|
prepare_fresh_lora_base,
|
|
27
28
|
require_vllm_for_rollout_func,
|
|
28
29
|
stamp_adapter_provenance,
|
|
30
|
+
validate_lora_target_parameters,
|
|
29
31
|
)
|
|
30
32
|
from flash.engine.worker.backend_common import collect_ray_failure_logs
|
|
31
33
|
from flash.engine.worker.decoding import (
|
|
@@ -531,6 +533,7 @@ __all__ = [
|
|
|
531
533
|
"liger_on",
|
|
532
534
|
"load_mega_cache",
|
|
533
535
|
"load_tokenizer",
|
|
536
|
+
"lora_target_parameters",
|
|
534
537
|
"loraplus_optimizer_cls",
|
|
535
538
|
"main",
|
|
536
539
|
"make_checkpoint_upload_callback",
|
|
@@ -560,6 +563,7 @@ __all__ = [
|
|
|
560
563
|
"thinking_text",
|
|
561
564
|
"upload_debug_jsonl",
|
|
562
565
|
"upload_resume_checkpoint",
|
|
566
|
+
"validate_lora_target_parameters",
|
|
563
567
|
"wait_for_gpu",
|
|
564
568
|
"wandb_finish",
|
|
565
569
|
"wandb_report_to",
|
|
@@ -27,11 +27,35 @@ from flash.engine.worker.perf import optimal_attn_impl
|
|
|
27
27
|
|
|
28
28
|
_ADAPTER_DOWNLOAD_RETRIES = 4
|
|
29
29
|
_ADAPTER_DOWNLOAD_BACKOFF_S = 5.0
|
|
30
|
+
_QWEN35_EXPERT_TARGET_PARAMETERS = (
|
|
31
|
+
"mlp.experts.gate_up_proj",
|
|
32
|
+
"mlp.experts.down_proj",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def lora_target_parameters(model_id: str | None) -> list[str] | None:
|
|
37
|
+
"""return direct parameter targets required by the model's fused expert layout."""
|
|
38
|
+
if model_id == "Qwen/Qwen3.6-35B-A3B":
|
|
39
|
+
return list(_QWEN35_EXPERT_TARGET_PARAMETERS)
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def validate_lora_target_parameters(config: dict, model_id: str) -> None:
|
|
44
|
+
"""fail closed when a warm-start adapter omits required fused expert parameters."""
|
|
45
|
+
required = set(lora_target_parameters(model_id) or ())
|
|
46
|
+
if not required:
|
|
47
|
+
return
|
|
48
|
+
actual = set(config.get("target_parameters") or ())
|
|
49
|
+
missing = sorted(required - actual)
|
|
50
|
+
if missing:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"warm-start adapter for {model_id} omits required expert targets {missing}; "
|
|
53
|
+
"retrain the source adapter with the current Flash version"
|
|
54
|
+
)
|
|
30
55
|
|
|
31
56
|
|
|
32
57
|
def make_lora(model_id: str | None = None):
|
|
33
|
-
"""
|
|
34
|
-
projector / MTP linears are adapted too; on examples without images they simply get no gradient)."""
|
|
58
|
+
"""build the model's complete serve-compatible lora target set."""
|
|
35
59
|
from peft import LoraConfig
|
|
36
60
|
|
|
37
61
|
targets = "all-linear"
|
|
@@ -46,7 +70,9 @@ def make_lora(model_id: str | None = None):
|
|
|
46
70
|
"task_type": "CAUSAL_LM",
|
|
47
71
|
"revision": model_revision or None,
|
|
48
72
|
}
|
|
49
|
-
|
|
73
|
+
if target_parameters := lora_target_parameters(model_id):
|
|
74
|
+
kwargs["target_parameters"] = target_parameters
|
|
75
|
+
# pissa removed: it mutates the base, so its adapter corrupts serve + warm-start on the unmodified base.
|
|
50
76
|
kwargs["init_lora_weights"] = True
|
|
51
77
|
print(
|
|
52
78
|
"[lora] init_lora_weights=True (standard zero-B; PiSSA removed for serve/warm-start safety)"
|
|
@@ -160,6 +186,8 @@ def _init_adapter_model(model_id: str):
|
|
|
160
186
|
"refusing to silently start from the base model. Verify the source run and access, "
|
|
161
187
|
"or omit init_from_adapter to train a fresh LoRA."
|
|
162
188
|
)
|
|
189
|
+
with open(os.path.join(adir, "adapter_config.json"), encoding="utf-8") as config_file:
|
|
190
|
+
validate_lora_target_parameters(json.load(config_file), model_id)
|
|
163
191
|
print("[init-adapter] continuing the prepared source LoRA")
|
|
164
192
|
_attn = optimal_attn_impl()
|
|
165
193
|
attn_kw = {"attn_implementation": _attn} if _attn else {}
|
{freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/backend_common.py
RENAMED
|
@@ -808,6 +808,10 @@ _CHILD_TAIL_LINE_CHARS = 300
|
|
|
808
808
|
# how many retained lines ride along on a pre-first-step heartbeat. narrower than what is retained:
|
|
809
809
|
# this payload is uploaded every tick, so it stays small enough not to bloat the snapshot.
|
|
810
810
|
STALL_TAIL_LINES = 15
|
|
811
|
+
_RETRIABLE_VERL_CHILD_SIGNATURES = (
|
|
812
|
+
"cudaErrorDevicesUnavailable",
|
|
813
|
+
"CUDA-capable device(s) is/are busy or unavailable",
|
|
814
|
+
)
|
|
811
815
|
|
|
812
816
|
|
|
813
817
|
class ChildOutputTail:
|
|
@@ -826,13 +830,34 @@ class ChildOutputTail:
|
|
|
826
830
|
def __init__(self, limit: int = CHILD_TAIL_LINES) -> None:
|
|
827
831
|
self._lines: collections.deque[str] = collections.deque(maxlen=limit)
|
|
828
832
|
self._written = 0
|
|
833
|
+
self._retriable_infra_signature: str | None = None
|
|
834
|
+
self._cuda_oom_evidence: str | None = None
|
|
829
835
|
|
|
830
836
|
def record(self, line: str) -> None:
|
|
837
|
+
if self._retriable_infra_signature is None:
|
|
838
|
+
self._retriable_infra_signature = next(
|
|
839
|
+
(signature for signature in _RETRIABLE_VERL_CHILD_SIGNATURES if signature in line),
|
|
840
|
+
None,
|
|
841
|
+
)
|
|
842
|
+
if self._cuda_oom_evidence is None:
|
|
843
|
+
from flash.engine.worker.perf.lifecycle import cuda_oom_message_evidence
|
|
844
|
+
|
|
845
|
+
self._cuda_oom_evidence = cuda_oom_message_evidence(line)
|
|
831
846
|
text = line.rstrip("\n")
|
|
832
847
|
if text:
|
|
833
848
|
self._lines.append(text[:_CHILD_TAIL_LINE_CHARS])
|
|
834
849
|
self._written += 1
|
|
835
850
|
|
|
851
|
+
@property
|
|
852
|
+
def retriable_infra_signature(self) -> str | None:
|
|
853
|
+
"""the first stable retriable-infrastructure signature observed in child output."""
|
|
854
|
+
return self._retriable_infra_signature
|
|
855
|
+
|
|
856
|
+
@property
|
|
857
|
+
def cuda_oom_evidence(self) -> str | None:
|
|
858
|
+
"""the first authoritative cuda oom message evidence observed in child output."""
|
|
859
|
+
return self._cuda_oom_evidence
|
|
860
|
+
|
|
836
861
|
@property
|
|
837
862
|
def written(self) -> int:
|
|
838
863
|
"""how many non-empty lines the child has produced, ever.
|
|
@@ -851,6 +876,25 @@ class ChildOutputTail:
|
|
|
851
876
|
return lines
|
|
852
877
|
|
|
853
878
|
|
|
879
|
+
def raise_for_classified_verl_exit(return_code: int, tail: ChildOutputTail) -> None:
|
|
880
|
+
"""raise a classified failure when a nonzero verl child reported authoritative evidence."""
|
|
881
|
+
if return_code == 0:
|
|
882
|
+
return
|
|
883
|
+
oom_evidence = tail.cuda_oom_evidence
|
|
884
|
+
if oom_evidence is not None:
|
|
885
|
+
raise RuntimeError(
|
|
886
|
+
f"verl subprocess exited with status {return_code} after reporting {oom_evidence}"
|
|
887
|
+
)
|
|
888
|
+
signature = tail.retriable_infra_signature
|
|
889
|
+
if signature is None:
|
|
890
|
+
return
|
|
891
|
+
from flash.engine.worker.perf.lifecycle import RetriableInfraError
|
|
892
|
+
|
|
893
|
+
raise RetriableInfraError(
|
|
894
|
+
f"verl subprocess exited with status {return_code} after reporting {signature}"
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
|
|
854
898
|
class ChildTailStaleness:
|
|
855
899
|
"""tracks how long a child has been silent, across the ticks that sample its tail.
|
|
856
900
|
|
|
@@ -1073,6 +1117,7 @@ def run_verl_training(
|
|
|
1073
1117
|
device memory that nothing will release.
|
|
1074
1118
|
"""
|
|
1075
1119
|
step_re = re.compile(step_pattern)
|
|
1120
|
+
child_tail = tail if tail is not None else ChildOutputTail()
|
|
1076
1121
|
# before the child exists, so any grandchild it orphans reparents here and can actually be
|
|
1077
1122
|
# reaped. this process is not pid 1 -- the runpod handler is -- so without it every wait below
|
|
1078
1123
|
# answers ChildProcessError for a zombie nobody will collect.
|
|
@@ -1086,13 +1131,14 @@ def run_verl_training(
|
|
|
1086
1131
|
bufsize=1,
|
|
1087
1132
|
start_new_session=True,
|
|
1088
1133
|
)
|
|
1134
|
+
# start_new_session makes the leader pid the stable group id even after that leader is reaped.
|
|
1135
|
+
process_group_id = proc.pid
|
|
1089
1136
|
last_hb = 0.0
|
|
1090
1137
|
try:
|
|
1091
1138
|
assert proc.stdout is not None
|
|
1092
1139
|
for line in proc.stdout:
|
|
1093
1140
|
print(line, end="", flush=True)
|
|
1094
|
-
|
|
1095
|
-
tail.record(line)
|
|
1141
|
+
child_tail.record(line)
|
|
1096
1142
|
if on_line is not None:
|
|
1097
1143
|
on_line(line)
|
|
1098
1144
|
m = step_re.search(line)
|
|
@@ -1104,7 +1150,7 @@ def run_verl_training(
|
|
|
1104
1150
|
heartbeat()
|
|
1105
1151
|
last_hb = now
|
|
1106
1152
|
except BaseException:
|
|
1107
|
-
kill_process_group(proc)
|
|
1153
|
+
kill_process_group(proc, process_group_id=process_group_id)
|
|
1108
1154
|
raise
|
|
1109
1155
|
finally:
|
|
1110
1156
|
if proc.poll() is None:
|
|
@@ -1114,7 +1160,13 @@ def run_verl_training(
|
|
|
1114
1160
|
# caller of this -- runs on exceptions alone: a worker whose later jobs all succeed would
|
|
1115
1161
|
# hold that zombie for its whole life, as pid 1 with nothing else to reap it (codex[bot]).
|
|
1116
1162
|
reap_stragglers()
|
|
1117
|
-
|
|
1163
|
+
return_code = int(proc.returncode)
|
|
1164
|
+
try:
|
|
1165
|
+
raise_for_classified_verl_exit(return_code, child_tail)
|
|
1166
|
+
except BaseException:
|
|
1167
|
+
kill_process_group(proc, process_group_id=process_group_id)
|
|
1168
|
+
raise
|
|
1169
|
+
return return_code
|
|
1118
1170
|
|
|
1119
1171
|
|
|
1120
1172
|
_TEARDOWN_GRACE_S = 10.0
|
|
@@ -1373,13 +1425,14 @@ def _process_group_members(pgid: int) -> list[int] | None:
|
|
|
1373
1425
|
return members
|
|
1374
1426
|
|
|
1375
1427
|
|
|
1376
|
-
def kill_process_group(proc: subprocess.Popen) -> None:
|
|
1428
|
+
def kill_process_group(proc: subprocess.Popen, *, process_group_id: int | None = None) -> None:
|
|
1377
1429
|
"""signal the child's whole process group, escalating to SIGKILL if anything survives.
|
|
1378
1430
|
|
|
1379
1431
|
signalling the group rather than the pid is what reaches vllm's EngineCore grandchild; a survivor
|
|
1380
1432
|
holds its cuda context and strands the gpu for every later run. the escalation is driven off the
|
|
1381
1433
|
group, not off the direct child: the usual shape of this failure is the trainer dying on the term
|
|
1382
1434
|
while the EngineCore ignores it, so waiting only on the child returns before the survivor is gone.
|
|
1435
|
+
a captured ``process_group_id`` keeps the group addressable after the direct child is reaped.
|
|
1383
1436
|
"""
|
|
1384
1437
|
# grpo drives its own subprocess and calls this directly, never through `run_verl_training`, so
|
|
1385
1438
|
# the adoption is claimed here too rather than only at the other entry point. idempotent.
|
|
@@ -1388,13 +1441,15 @@ def kill_process_group(proc: subprocess.Popen) -> None:
|
|
|
1388
1441
|
# entry rather than on exit because that is when such a process has had the longest to die, and
|
|
1389
1442
|
# it runs before the early returns below so no path through this function skips it.
|
|
1390
1443
|
reap_stragglers()
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1444
|
+
pgid = process_group_id
|
|
1445
|
+
if pgid is None:
|
|
1446
|
+
try:
|
|
1447
|
+
pgid = os.getpgid(proc.pid)
|
|
1448
|
+
except OSError:
|
|
1449
|
+
# already reaped, so there is no group id left to address the survivors by.
|
|
1450
|
+
with contextlib.suppress(subprocess.TimeoutExpired):
|
|
1451
|
+
proc.wait(timeout=_TEARDOWN_GRACE_S)
|
|
1452
|
+
return
|
|
1398
1453
|
|
|
1399
1454
|
with contextlib.suppress(ProcessLookupError, PermissionError, OSError):
|
|
1400
1455
|
os.killpg(pgid, signal.SIGTERM)
|
|
@@ -1553,6 +1553,14 @@ def build_opd_overrides(config: dict) -> list[str]:
|
|
|
1553
1553
|
f"actor_rollout_ref.model.lora_rank={_hydra_val(config['lora_rank'])}",
|
|
1554
1554
|
f"actor_rollout_ref.model.lora_alpha={_hydra_val(config['lora_alpha'])}",
|
|
1555
1555
|
f"actor_rollout_ref.model.target_modules={_hydra_val(config['target_modules'])}",
|
|
1556
|
+
*(
|
|
1557
|
+
[
|
|
1558
|
+
"++actor_rollout_ref.model.target_parameters="
|
|
1559
|
+
+ _hydra_val(config["target_parameters"])
|
|
1560
|
+
]
|
|
1561
|
+
if config.get("target_parameters")
|
|
1562
|
+
else []
|
|
1563
|
+
),
|
|
1556
1564
|
f"actor_rollout_ref.model.lora_adapter_path={_hydra_val(config.get('lora_adapter_path'))}",
|
|
1557
1565
|
"actor_rollout_ref.actor.strategy=fsdp",
|
|
1558
1566
|
"actor_rollout_ref.actor.use_kl_loss=false",
|
|
@@ -2498,6 +2506,7 @@ def run_opd_train(spec=None) -> None:
|
|
|
2498
2506
|
"lora_rank": lora_rank,
|
|
2499
2507
|
"lora_alpha": lora_alpha,
|
|
2500
2508
|
"target_modules": target_modules,
|
|
2509
|
+
"target_parameters": _w.lora_target_parameters(model_id),
|
|
2501
2510
|
"lora_adapter_path": warmstart_adapter,
|
|
2502
2511
|
"learning_rate": knobs.learning_rate,
|
|
2503
2512
|
"local_dir": local_dir,
|
{freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/lifecycle.py
RENAMED
|
@@ -6,6 +6,10 @@ import contextlib
|
|
|
6
6
|
import re
|
|
7
7
|
|
|
8
8
|
RETRIABLE_INFRA_MARKER = "RETRIABLE_INFRA_GPU"
|
|
9
|
+
_CUDA_OOM_PREFLIGHT_RE = re.compile(
|
|
10
|
+
r"free memory on device\s+cuda:\d+.*less than desired gpu memory utilization"
|
|
11
|
+
)
|
|
12
|
+
_CUDA_OOM_CACHE_BLOCKS = "no available memory for the cache blocks"
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
class RetriableInfraError(RuntimeError):
|
|
@@ -30,6 +34,17 @@ def cuda_oom_count() -> int:
|
|
|
30
34
|
return 0
|
|
31
35
|
|
|
32
36
|
|
|
37
|
+
def cuda_oom_message_evidence(message: str) -> str | None:
|
|
38
|
+
"""the authoritative text evidence for a deterministic cuda oom, if present."""
|
|
39
|
+
normalized = message.lower()
|
|
40
|
+
preflight = _CUDA_OOM_PREFLIGHT_RE.search(normalized)
|
|
41
|
+
if preflight is not None:
|
|
42
|
+
return preflight.group(0)
|
|
43
|
+
if _CUDA_OOM_CACHE_BLOCKS in normalized:
|
|
44
|
+
return _CUDA_OOM_CACHE_BLOCKS
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
33
48
|
def is_cuda_oom(exc: BaseException | None) -> bool:
|
|
34
49
|
"""Whether a failure was a CUDA OOM.
|
|
35
50
|
|
|
@@ -46,13 +61,7 @@ def is_cuda_oom(exc: BaseException | None) -> bool:
|
|
|
46
61
|
return True
|
|
47
62
|
except Exception:
|
|
48
63
|
pass
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
re.search(
|
|
52
|
-
r"free memory on device\s+cuda:\d+.*less than desired gpu memory utilization", msg
|
|
53
|
-
)
|
|
54
|
-
or "no available memory for the cache blocks" in msg
|
|
55
|
-
):
|
|
64
|
+
if cuda_oom_message_evidence(str(exc)) is not None:
|
|
56
65
|
return True
|
|
57
66
|
return cuda_oom_count() > 0
|
|
58
67
|
|
|
@@ -49,6 +49,7 @@ from flash.engine.worker._pkg import W as _w
|
|
|
49
49
|
from flash.engine.worker.backend_common import (
|
|
50
50
|
VERL_REQUIREMENT,
|
|
51
51
|
BoundedThreadingHTTPServer,
|
|
52
|
+
ChildOutputTail,
|
|
52
53
|
adopt_orphaned_descendants,
|
|
53
54
|
agent_loop_workers,
|
|
54
55
|
append_step_metrics,
|
|
@@ -60,6 +61,7 @@ from flash.engine.worker.backend_common import (
|
|
|
60
61
|
parse_verl_metric,
|
|
61
62
|
parse_verl_step_metrics,
|
|
62
63
|
parse_wandb_link,
|
|
64
|
+
raise_for_classified_verl_exit,
|
|
63
65
|
ray_num_cpus,
|
|
64
66
|
reap_stragglers,
|
|
65
67
|
render_wandb_link_shim,
|
|
@@ -356,6 +358,11 @@ def build_verl_overrides(cfg: dict) -> list[str]:
|
|
|
356
358
|
f"actor_rollout_ref.model.lora_rank={cfg['lora_rank']}",
|
|
357
359
|
f"actor_rollout_ref.model.lora_alpha={cfg['lora_alpha']}",
|
|
358
360
|
f"actor_rollout_ref.model.target_modules={cfg['target_modules']}",
|
|
361
|
+
*(
|
|
362
|
+
["++actor_rollout_ref.model.target_parameters=" + _hydra_val(cfg["target_parameters"])]
|
|
363
|
+
if cfg.get("target_parameters")
|
|
364
|
+
else []
|
|
365
|
+
),
|
|
359
366
|
# memory: match the retired trl path's gradient checkpointing.
|
|
360
367
|
"actor_rollout_ref.model.enable_gradient_checkpointing=True",
|
|
361
368
|
# 32k contexts: fused linear-CE computes logprobs/entropy from hidden states + lm_head in
|
|
@@ -564,6 +571,7 @@ def _build_verl_training_cfg(
|
|
|
564
571
|
"lora_rank": inp["lora_rank"],
|
|
565
572
|
"lora_alpha": inp["lora_alpha"],
|
|
566
573
|
"target_modules": "all-linear",
|
|
574
|
+
"target_parameters": _w.lora_target_parameters(model_id),
|
|
567
575
|
"multimodal": bool(inp.get("multimodal")),
|
|
568
576
|
"lr": inp["lr"],
|
|
569
577
|
"group_size": inp["group_size"],
|
|
@@ -2756,6 +2764,7 @@ def _resolve_grpo_inputs():
|
|
|
2756
2764
|
)
|
|
2757
2765
|
with open(os.path.join(warmstart_adapter, "adapter_config.json")) as f:
|
|
2758
2766
|
_src_cfg = json.load(f)
|
|
2767
|
+
_w.validate_lora_target_parameters(_src_cfg, model_id)
|
|
2759
2768
|
# a patterned adapter trains some modules at higher rank than the base `r`; verl allocates
|
|
2760
2769
|
# one uniform rank, so it must cover the MAXIMUM prepared rank or the load truncates.
|
|
2761
2770
|
_ranks = [int(_src_cfg.get("r", lora_rank))]
|
|
@@ -3022,6 +3031,38 @@ def _resolve_grpo_inputs():
|
|
|
3022
3031
|
}
|
|
3023
3032
|
|
|
3024
3033
|
|
|
3034
|
+
class _GrpoSubprocessStream:
|
|
3035
|
+
"""one grpo child stream and the evidence latched from that same stream."""
|
|
3036
|
+
|
|
3037
|
+
def __init__(self, proc) -> None:
|
|
3038
|
+
self._proc = proc
|
|
3039
|
+
# the caller uses start_new_session, so the leader pid remains the group's stable identity.
|
|
3040
|
+
self._process_group_id = proc.pid
|
|
3041
|
+
self._tail = ChildOutputTail()
|
|
3042
|
+
self._terminated = False
|
|
3043
|
+
|
|
3044
|
+
def __iter__(self):
|
|
3045
|
+
assert self._proc.stdout is not None
|
|
3046
|
+
for line in self._proc.stdout:
|
|
3047
|
+
self._tail.record(line)
|
|
3048
|
+
yield line
|
|
3049
|
+
|
|
3050
|
+
def terminate(self) -> None:
|
|
3051
|
+
if self._terminated:
|
|
3052
|
+
return
|
|
3053
|
+
kill_process_group(self._proc, process_group_id=self._process_group_id)
|
|
3054
|
+
self._terminated = True
|
|
3055
|
+
|
|
3056
|
+
def wait_and_classify(self) -> int:
|
|
3057
|
+
return_code = int(self._proc.wait())
|
|
3058
|
+
try:
|
|
3059
|
+
raise_for_classified_verl_exit(return_code, self._tail)
|
|
3060
|
+
except BaseException:
|
|
3061
|
+
self.terminate()
|
|
3062
|
+
raise
|
|
3063
|
+
return return_code
|
|
3064
|
+
|
|
3065
|
+
|
|
3025
3066
|
def run_rl_train():
|
|
3026
3067
|
"""grpo training on verl, output-compatible with run_rl. see module docstring for scope."""
|
|
3027
3068
|
t_start = time.time()
|
|
@@ -3408,8 +3449,9 @@ def run_rl_train():
|
|
|
3408
3449
|
env=env_for_verl,
|
|
3409
3450
|
start_new_session=True,
|
|
3410
3451
|
)
|
|
3452
|
+
child_stream = _GrpoSubprocessStream(proc)
|
|
3411
3453
|
try:
|
|
3412
|
-
for line in
|
|
3454
|
+
for line in child_stream:
|
|
3413
3455
|
print(f"[verl] {line}", end="", flush=True)
|
|
3414
3456
|
link = parse_wandb_link(line)
|
|
3415
3457
|
if link is not None:
|
|
@@ -3483,14 +3525,14 @@ def run_rl_train():
|
|
|
3483
3525
|
adv_min = parse_verl_metric(line, "critic/advantages/min")
|
|
3484
3526
|
if adv_max is not None and adv_min is not None:
|
|
3485
3527
|
adv_spread_history.append(adv_max - adv_min)
|
|
3486
|
-
rc =
|
|
3528
|
+
rc = child_stream.wait_and_classify()
|
|
3487
3529
|
except BaseException:
|
|
3488
3530
|
# the stream loop died (upload error, cancel, oom in the parent): a still-running
|
|
3489
3531
|
# verl child would keep burning the gpu unattended, so kill its whole process group.
|
|
3490
3532
|
# this escalates to SIGKILL after the grace period, which a bare SIGTERM does not: a
|
|
3491
3533
|
# vllm EngineCore that ignores the term keeps its cuda context and strands the gpu
|
|
3492
3534
|
# for every later job on a reusable worker.
|
|
3493
|
-
|
|
3535
|
+
child_stream.terminate()
|
|
3494
3536
|
raise
|
|
3495
3537
|
if rc != 0:
|
|
3496
3538
|
raise RuntimeError(
|
|
@@ -166,6 +166,11 @@ def build_sft_overrides(cfg: dict) -> list[str]:
|
|
|
166
166
|
f"model.lora_rank={_hydra_val(cfg['lora_rank'])}",
|
|
167
167
|
f"model.lora_alpha={_hydra_val(cfg['lora_alpha'])}",
|
|
168
168
|
f"model.target_modules={_hydra_val(cfg['target_modules'])}",
|
|
169
|
+
*(
|
|
170
|
+
[f"++model.target_parameters={_hydra_val(cfg['target_parameters'])}"]
|
|
171
|
+
if cfg.get("target_parameters")
|
|
172
|
+
else []
|
|
173
|
+
),
|
|
169
174
|
f"model.lora_adapter_path={_hydra_val(cfg.get('lora_adapter_path'))}",
|
|
170
175
|
"model.use_remove_padding=true",
|
|
171
176
|
# 32k contexts: the fused linear-CE forward never materializes the [tokens, vocab] logits
|
|
@@ -762,6 +767,7 @@ def _warmstart_adapter_path(model_id: str, model_revision: str, expected_rank: i
|
|
|
762
767
|
f"SFT warm-start adapter rank {rank} does not match the prepared train.lora_rank "
|
|
763
768
|
f"{expected_rank}; rank changes are not supported"
|
|
764
769
|
)
|
|
770
|
+
_w.validate_lora_target_parameters(config, model_id)
|
|
765
771
|
base = str(config.get("base_model_name_or_path") or "").strip()
|
|
766
772
|
if base and base != model_id:
|
|
767
773
|
raise ValueError("SFT warm-start adapter base model does not match the target model")
|
|
@@ -1270,6 +1276,7 @@ def run_sft_train(spec=None) -> None:
|
|
|
1270
1276
|
"lora_rank": lora_rank,
|
|
1271
1277
|
"lora_alpha": lora_alpha,
|
|
1272
1278
|
"target_modules": target_modules,
|
|
1279
|
+
"target_parameters": _w.lora_target_parameters(model_id),
|
|
1273
1280
|
"lora_adapter_path": warmstart_adapter,
|
|
1274
1281
|
"ulysses_sp_size": gpu_count,
|
|
1275
1282
|
"lr": learning_rate,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "freesolo-flash-dev"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.85"
|
|
4
4
|
description = "Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
# RunPod Flash supports Python 3.11-3.12 (not 3.13 yet).
|
|
@@ -127,7 +127,7 @@ artifacts = ["flash/py.typed"]
|
|
|
127
127
|
# auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
|
|
128
128
|
# PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
|
|
129
129
|
# dev-channel release = bump this (and [project].version) and merge to `dev`.
|
|
130
|
-
version = "1.0.
|
|
130
|
+
version = "1.0.85"
|
|
131
131
|
|
|
132
132
|
[tool.pytest.ini_options]
|
|
133
133
|
pythonpath = ["."]
|
|
@@ -1073,7 +1073,7 @@ def test_catalog_model_algorithm_gpu_matrix_routes_to_fitting_cards(monkeypatch)
|
|
|
1073
1073
|
from flash.catalog import ALGORITHMS, MODELS
|
|
1074
1074
|
from flash.cost import RunConfig, estimate_cost
|
|
1075
1075
|
from flash.providers import allocator
|
|
1076
|
-
from flash.providers.base import get_gpu_info, provisional_gpu
|
|
1076
|
+
from flash.providers.base import GPU_INFO, combined_vram_gb, get_gpu_info, provisional_gpu
|
|
1077
1077
|
|
|
1078
1078
|
monkeypatch.setattr(allocator, "available_providers", lambda: ("runpod",))
|
|
1079
1079
|
expected = {
|
|
@@ -1090,25 +1090,50 @@ def test_catalog_model_algorithm_gpu_matrix_routes_to_fitting_cards(monkeypatch)
|
|
|
1090
1090
|
continue
|
|
1091
1091
|
train = {}
|
|
1092
1092
|
need = allocator.required_vram_gb(model_id, algo, train=train, thinking=False)
|
|
1093
|
+
# most cells fit one card. the 35B MoE trains 256 routed experts per fused tensor, so its
|
|
1094
|
+
# GRPO/OPD peaks exceed every single card and the route is only defined across two.
|
|
1095
|
+
cards = 2 if need > max(g.vram_gb for g in GPU_INFO.values() if g.validated) else 1
|
|
1093
1096
|
|
|
1094
|
-
preview_gpu = provisional_gpu(
|
|
1097
|
+
preview_gpu = provisional_gpu(
|
|
1098
|
+
model_id, algo, train=train, thinking=False, gpu_count=cards
|
|
1099
|
+
)
|
|
1095
1100
|
preview_info = get_gpu_info(preview_gpu)
|
|
1096
1101
|
assert preview_info.validated
|
|
1097
1102
|
assert preview_info.enum_member
|
|
1098
|
-
|
|
1103
|
+
# sharding is not free: combined_vram_gb applies the per-card overhead, so two cards hold
|
|
1104
|
+
# less than twice one card. sizing with a naive sum would overstate what the shape holds.
|
|
1105
|
+
assert combined_vram_gb(preview_info.vram_gb, cards) >= need, (
|
|
1106
|
+
model_id,
|
|
1107
|
+
algo,
|
|
1108
|
+
preview_gpu,
|
|
1109
|
+
need,
|
|
1110
|
+
)
|
|
1099
1111
|
|
|
1100
|
-
alloc = allocator.allocate(
|
|
1112
|
+
alloc = allocator.allocate(
|
|
1113
|
+
model_id, algo, train=train, thinking=False, max_gpu_count=cards
|
|
1114
|
+
)
|
|
1101
1115
|
alloc_info = get_gpu_info(alloc.gpu)
|
|
1102
1116
|
assert alloc.provider == "runpod"
|
|
1103
1117
|
assert alloc.min_vram_gb == need
|
|
1104
1118
|
assert alloc_info.validated
|
|
1105
1119
|
assert alloc_info.enum_member
|
|
1106
|
-
assert alloc_info.vram_gb >= need, (
|
|
1107
|
-
|
|
1120
|
+
assert combined_vram_gb(alloc_info.vram_gb, cards) >= need, (
|
|
1121
|
+
model_id,
|
|
1122
|
+
algo,
|
|
1123
|
+
alloc.gpu,
|
|
1124
|
+
need,
|
|
1125
|
+
)
|
|
1126
|
+
assert all(combined_vram_gb(c.vram_gb, cards) >= need for c in alloc.candidates)
|
|
1108
1127
|
|
|
1109
|
-
estimate = estimate_cost(
|
|
1110
|
-
|
|
1111
|
-
|
|
1128
|
+
estimate = estimate_cost(
|
|
1129
|
+
RunConfig(model_id, algo, 1, provider="runpod", gpu_count=cards)
|
|
1130
|
+
)
|
|
1131
|
+
assert estimate.gpu_vram_gb * estimate.gpu_count >= estimate.required_vram_gb, (
|
|
1132
|
+
model_id,
|
|
1133
|
+
algo,
|
|
1134
|
+
estimate.gpu,
|
|
1135
|
+
estimate.required_vram_gb,
|
|
1136
|
+
)
|
|
1112
1137
|
checked.add((model_id, algo))
|
|
1113
1138
|
|
|
1114
1139
|
assert checked == expected
|
|
@@ -1151,7 +1176,18 @@ def test_catalog_model_algorithm_config_gpu_matrix_enforces_pins(monkeypatch):
|
|
|
1151
1176
|
}
|
|
1152
1177
|
key = (model_id, algo, configured_gpu)
|
|
1153
1178
|
if get_gpu_info(configured_gpu).vram_gb < need:
|
|
1154
|
-
|
|
1179
|
+
# two distinct rejections, both correct: a pin that is merely too small names the
|
|
1180
|
+
# shortfall, while a run that outgrows EVERY validated class (35B GRPO/OPD, once
|
|
1181
|
+
# the routed experts train) fails earlier with no fitting class at all.
|
|
1182
|
+
biggest = max(g.vram_gb for g in GPU_INFO.values() if g.validated)
|
|
1183
|
+
# opd words its over-capacity error differently from the generic allocator one,
|
|
1184
|
+
# so match the shared "no ... validated GPU" shape rather than either wording.
|
|
1185
|
+
reason = (
|
|
1186
|
+
"requires at least"
|
|
1187
|
+
if need <= biggest
|
|
1188
|
+
else r"(no validated GPU class has|more than any single validated GPU)"
|
|
1189
|
+
)
|
|
1190
|
+
with pytest.raises(ConfigError, match=reason):
|
|
1155
1191
|
spec_from_dict(raw, run_id="matrix")
|
|
1156
1192
|
rejected.add(key)
|
|
1157
1193
|
continue
|