freesolo-flash-dev 1.0.6__tar.gz → 1.0.8__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.8/AB_PLAN.md +45 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/training_doc.py +10 -7
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cost/analytical.py +19 -8
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cost/facts.py +25 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cost/spec.py +8 -9
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cost/types.py +15 -2
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/diagnostics.py +11 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/vram.py +43 -50
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/gpu_setup.py +74 -3
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/heartbeat.py +93 -27
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/opd.py +150 -12
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/rl.py +110 -62
- freesolo_flash_dev-1.0.8/flash/engine/worker/rollout_samples.py +148 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/sft.py +122 -61
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/lora_rank.py +61 -15
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_poll.py +55 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/jobs.py +8 -5
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/train/endpoints.py +10 -3
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/api.py +8 -4
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/runner/__init__.py +38 -2
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/runner/lifecycle.py +7 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/schema/__init__.py +4 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/schema/fields.py +10 -1
- freesolo_flash_dev-1.0.8/flash/serve/preflight.py +121 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/routes/runs.py +3 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/routes/serving.py +26 -10
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/spec.py +34 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_allocator.py +123 -72
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_b200_rollout_opt.py +7 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_chalk_kernels.py +1 -6
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_estimate.py +17 -14
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_estimate.py +61 -6
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_hardware.py +19 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_flash_worker.py +9 -10
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_gpus.py +2 -3
- freesolo_flash_dev-1.0.8/tests/test_grpo_cudagraphs.py +101 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_grpo_params.py +76 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_jobs.py +90 -0
- freesolo_flash_dev-1.0.8/tests/test_multi_gpu_gate.py +83 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_opd.py +299 -60
- freesolo_flash_dev-1.0.8/tests/test_rollout_samples.py +606 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_api.py +253 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_envs_coverage.py +63 -2
- freesolo_flash_dev-1.0.8/tests/test_sft_chunked_nll.py +292 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_spec_and_validation.py +51 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_train_context_preflight.py +24 -1
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vast_api.py +12 -3
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_init_heartbeat.py +34 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/uv.lock +1 -1
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.claude/skills/verify/SKILL.md +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.env.example +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/README.md +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/grpo_multimodal.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/grpo_perturn_trainer.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/db.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_grpo_perturn.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_image_rollout.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_per_turn_reward.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_rollout_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_rollout_records.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_multiturn_rollout_request_policy.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_opd_full_state_resume.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_sft_activation_shaping.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_sft_tokenize_cache.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_single_turn_multimodal_grpo.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.6 → freesolo_flash_dev-1.0.8}/tests/test_worker_thinking.py +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# GRPO decode-only CUDA graph A/B plan
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
|
|
5
|
+
Measure whether decode-only CUDA graphs speed up the colocated GRPO rollout engine without changing training behavior. This plan does not authorize a paid run.
|
|
6
|
+
|
|
7
|
+
## Frozen comparison
|
|
8
|
+
|
|
9
|
+
- Control: `origin/dev` at `8fdfc8580b9058d8c40289d4fa1a2e6e3b7bced2`. On RTX 5090/sm120 with vLLM 0.19.1, this selects `enforce_eager=True`.
|
|
10
|
+
- Treatment: the committed head of `perf/grpo-cudagraphs`. On the same GPU and vLLM version, this selects `enforce_eager=False` with `mode=0` and `cudagraph_mode=FULL_DECODE_ONLY`.
|
|
11
|
+
- Hardware: two separate, matched RunPod RTX 5090 workers from the same GPU offer, image, region, CPU/RAM class, and storage configuration. Do not substitute unmatched cards between arms.
|
|
12
|
+
- Model: `Qwen/Qwen3.5-0.8B`, which fits within an RTX 4090-class memory budget.
|
|
13
|
+
- Environment: the real `entropy-R1` hub environment, pinned to one immutable `freesolo-co/environment-hub` commit before launch.
|
|
14
|
+
- Seed: 42 for both arms.
|
|
15
|
+
- Budget: 30 optimizer updates after a two-update exact-path smoke. Use the same prompts per step, group size, maximum context, maximum completion length, LoRA settings, optimizer settings, reward implementation, dataset order, and checkpoint schedule.
|
|
16
|
+
- Concurrency: launch both paid arms together only after both two-update smokes pass. Do not reuse a worker across arms.
|
|
17
|
+
|
|
18
|
+
## Preflight and token-parity gate
|
|
19
|
+
|
|
20
|
+
1. Resolve and record the exact Flash commit, environment-hub commit, model revision, container digest, vLLM version, CUDA/driver versions, and RunPod machine identifiers for each arm.
|
|
21
|
+
2. Run the same fixed prompt batch through both immutable rollout engines with greedy decoding and the same maximum token count.
|
|
22
|
+
3. Require identical token IDs, finish reasons, and decoded text for every fixed prompt. Any difference is a correctness failure and stops the A/B.
|
|
23
|
+
4. Run two GRPO updates per arm. Require successful graph capture or vLLM's eager fallback, finite loss/reward values, and no OOM before scaling to 30 updates.
|
|
24
|
+
|
|
25
|
+
## Metrics
|
|
26
|
+
|
|
27
|
+
Measure rollout work separately from training work where telemetry permits.
|
|
28
|
+
|
|
29
|
+
- Primary performance: generated rollout tokens per rollout-engine second, excluding engine startup, graph capture, checkpointing, reward evaluation, and optimizer time.
|
|
30
|
+
- Secondary performance: median rollout wall time per update and end-to-end median step wall time. Report graph-capture startup time separately rather than amortizing it away.
|
|
31
|
+
- Correctness: fixed-prompt rollout token parity, reward curve, training loss curve, completion length, finish-reason distribution, and invalid/empty completion rate.
|
|
32
|
+
- Safety: peak allocated and reserved GPU memory, OOM count, graph-capture failures, eager-fallback events, worker restarts, and failed updates.
|
|
33
|
+
|
|
34
|
+
## Decision thresholds
|
|
35
|
+
|
|
36
|
+
The expected direction is faster treatment decode with unchanged learning behavior.
|
|
37
|
+
|
|
38
|
+
- Performance works: treatment improves steady-state rollout tokens/second by at least 10% over control. A 10% to 40% improvement is the expected range. Confirm the direction with at least a 9% reduction in median rollout wall time over updates 3 through 30.
|
|
39
|
+
- End-to-end value: treatment reduces median total step wall time by at least 5%. Report a decode-only win below this threshold as technically real but operationally marginal.
|
|
40
|
+
- Reward parity: treatment reward AUC over the 30 matched updates must remain within 5% relative or 0.02 absolute of control, whichever tolerance is larger. There must be no sustained three-update reward regression larger than 0.05 absolute.
|
|
41
|
+
- Loss parity: treatment loss AUC must remain within 5% relative of control, with finite values at every update and no new divergence pattern.
|
|
42
|
+
- Rollout parity: the fixed greedy prompt batch must have exact token-ID parity. During stochastic training, completion length, finish-reason, and empty/invalid-rate differences must each remain within 5% relative or one sample, whichever is larger.
|
|
43
|
+
- Memory and reliability: no OOM, no worker restart, no failed update, and treatment peak reserved memory no more than 5% above control after graph capture.
|
|
44
|
+
|
|
45
|
+
The treatment passes only if all correctness and reliability gates pass and the primary performance threshold is met. If vLLM falls back to eager, report the fallback and classify the performance result as inconclusive rather than a decode-graph success.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
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
|
|
@@ -277,13 +277,16 @@ spending another GPU run:
|
|
|
277
277
|
- **Judge the trend, not a single number.** The proof of training is the curve:
|
|
278
278
|
loss falling (SFT) or `reward` rising over steps (GRPO). Record the base/early
|
|
279
279
|
value and the final value. A flat or noisy trend with no improvement is not success.
|
|
280
|
-
- **Read the model's outputs, not just the metrics.** A rising reward
|
|
281
|
-
reward-hacking or a degenerate output the
|
|
282
|
-
establish that the model got better.
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
280
|
+
- **Read the model's outputs, not just the metrics.** A rising reward (or falling loss)
|
|
281
|
+
can come from reward-hacking or a degenerate output the metric still credits — metrics
|
|
282
|
+
alone never establish that the model got better. For GRPO and OPD, `flash log` surfaces a
|
|
283
|
+
handful of full (untruncated) sample completions at the heartbeat cadence — GRPO shows
|
|
284
|
+
each completion's reward, OPD its distillation loss — with the first sample-bearing update
|
|
285
|
+
forced through, so you can catch skipped reasoning or a parroted prompt placeholder by
|
|
286
|
+
step 1-2. These are bounded diagnostics, not every rollout or a held-out
|
|
287
|
+
evaluation, so still **deploy the adapter and probe it**: `flash deploy <run-id>` then
|
|
288
|
+
`flash chat <run-id> -m "..."` on at least a few real inputs, including ones it should
|
|
289
|
+
get wrong.
|
|
287
290
|
|
|
288
291
|
```bash
|
|
289
292
|
flash status <run-id> # state + accrued cost
|
|
@@ -14,8 +14,8 @@ from flash.providers.allocator import required_vram_gb, vram_headroom
|
|
|
14
14
|
from .facts import (
|
|
15
15
|
active_params_b,
|
|
16
16
|
download_weight_gb,
|
|
17
|
+
effective_train_tflops,
|
|
17
18
|
gpu_hourly_usd,
|
|
18
|
-
gpu_tflops,
|
|
19
19
|
gpu_vram_gb,
|
|
20
20
|
model_quant,
|
|
21
21
|
pick_gpu,
|
|
@@ -150,7 +150,7 @@ def compile_seconds(config: RunConfig, gpu: str) -> float:
|
|
|
150
150
|
def seconds_per_step(config: RunConfig, gpu: str) -> float:
|
|
151
151
|
"""Steady-state wall time for one optimizer step on ``gpu``."""
|
|
152
152
|
n = config.normalized()
|
|
153
|
-
peak =
|
|
153
|
+
peak = effective_train_tflops(gpu) * 1e12 # FLOP/s (realized training throughput; see facts)
|
|
154
154
|
# An MoE's per-step wall scales with TOTAL params (routing + all-expert coordination + grouped
|
|
155
155
|
# GEMM under-utilization), not the tiny active-param FLOPs; dense models keep active (== total).
|
|
156
156
|
moe = _is_moe(n.model_id)
|
|
@@ -166,7 +166,9 @@ def seconds_per_step(config: RunConfig, gpu: str) -> float:
|
|
|
166
166
|
# sequence (see _opd_step_shape), not completion-only, or long-prompt opd is underquoted.
|
|
167
167
|
completions, seq_tokens = _opd_step_shape(n)
|
|
168
168
|
gen_s = (GRPO_GEN_FLOPS_PER_TOKEN_PER_PARAM * params * seq_tokens) / (peak * MFU_DECODE)
|
|
169
|
-
update_s = (OPD_UPDATE_FLOPS_PER_TOKEN_PER_PARAM * params * seq_tokens) / (
|
|
169
|
+
update_s = (OPD_UPDATE_FLOPS_PER_TOKEN_PER_PARAM * params * seq_tokens) / (
|
|
170
|
+
peak * update_mfu
|
|
171
|
+
)
|
|
170
172
|
teacher_lat = teacher_seconds_per_completion()
|
|
171
173
|
# run_opd's primary path scores a step's completions CONCURRENTLY over Fireworks with a fan-out
|
|
172
174
|
# cap of the step's OWN completion count (prompts_per_step * group_size, opd.py Phase 2), so
|
|
@@ -191,6 +193,7 @@ def seconds_per_step(config: RunConfig, gpu: str) -> float:
|
|
|
191
193
|
) # ceil: a partial wave still costs one latency
|
|
192
194
|
return overhead + gen_s + reward_s + update_s
|
|
193
195
|
|
|
196
|
+
|
|
194
197
|
def sft_seconds_for_tokens(config: RunConfig, gpu: str, train_tokens: float) -> float:
|
|
195
198
|
"""SFT steady-state wall time for an actual token count on ``gpu``."""
|
|
196
199
|
n = config.normalized()
|
|
@@ -198,7 +201,7 @@ def sft_seconds_for_tokens(config: RunConfig, gpu: str, train_tokens: float) ->
|
|
|
198
201
|
moe = _is_moe(n.model_id)
|
|
199
202
|
params = (total_params_b(n.model_id) if moe else active_params_b(n.model_id)) * 1e9
|
|
200
203
|
mfu = MFU_SFT_TRAIN_MOE if moe else MFU_SFT_TRAIN
|
|
201
|
-
peak =
|
|
204
|
+
peak = effective_train_tflops(gpu) * 1e12
|
|
202
205
|
flops = SFT_FLOPS_PER_TOKEN_PER_PARAM * params * train_tokens
|
|
203
206
|
return flops / (peak * mfu)
|
|
204
207
|
|
|
@@ -276,7 +279,11 @@ def _notes(
|
|
|
276
279
|
def estimate_cost(config: RunConfig, *, wall_cap_s: float = DEFAULT_WALL_CAP_S) -> CostEstimate:
|
|
277
280
|
"""Deterministic pre-flight cost calculation."""
|
|
278
281
|
# Billing cap: mirror the runner's max(60, max_wall_seconds) floor so a sub-60s cap isn't underpriced.
|
|
279
|
-
cap_s =
|
|
282
|
+
cap_s = (
|
|
283
|
+
max(60.0, float(config.max_wall_seconds))
|
|
284
|
+
if config.max_wall_seconds is not None
|
|
285
|
+
else wall_cap_s
|
|
286
|
+
)
|
|
280
287
|
# Vast market duration filter: price against offers that outlast the run, using the SAME semantics
|
|
281
288
|
# ``usable_offers`` applies at LAUNCH (not the 60s-floored billing cap_s) — a non-positive wall means
|
|
282
289
|
# NO filter, a positive one is floored at 60s by usable_offers itself:
|
|
@@ -331,7 +338,9 @@ def estimate_cost(config: RunConfig, *, wall_cap_s: float = DEFAULT_WALL_CAP_S)
|
|
|
331
338
|
compile_s = compile_seconds(config, gpu)
|
|
332
339
|
raw_train = compile_s + config.steps * sps + required_save_s
|
|
333
340
|
if not config.is_grpo and config.train_tokens is not None:
|
|
334
|
-
raw_train =
|
|
341
|
+
raw_train = (
|
|
342
|
+
compile_s + sft_seconds_for_tokens(config, gpu, config.train_tokens) + required_save_s
|
|
343
|
+
)
|
|
335
344
|
sps = raw_train / config.steps
|
|
336
345
|
|
|
337
346
|
# The cap is on total elapsed wall; setup is reported but not billed, so only training
|
|
@@ -367,9 +376,11 @@ def estimate_cost(config: RunConfig, *, wall_cap_s: float = DEFAULT_WALL_CAP_S)
|
|
|
367
376
|
train_seconds=train,
|
|
368
377
|
wall_clock_seconds=wall,
|
|
369
378
|
wall_capped=wall_capped,
|
|
379
|
+
gpu_count=config.gpu_count,
|
|
370
380
|
# total_usd is the customer gpu charge. the platform-owned teacher spend is itemized
|
|
371
|
-
# only as a diagnostic and is not passed through to the customer.
|
|
372
|
-
|
|
381
|
+
# only as a diagnostic and is not passed through to the customer. an n-card job occupies
|
|
382
|
+
# n cards for the billed training wall, so the charge scales linearly with gpu_count.
|
|
383
|
+
total_usd=train / 3600.0 * hourly * config.gpu_count,
|
|
373
384
|
teacher_api_usd=teacher_api_usd,
|
|
374
385
|
notes=_notes(config, raw_train, wall_capped, cap_s),
|
|
375
386
|
)
|
|
@@ -30,6 +30,31 @@ def gpu_tflops(name: str) -> float:
|
|
|
30
30
|
return GPU_COMPUTE_TFLOPS.get(name, _DEFAULT_TFLOPS)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
# realized TRAINING throughput sits well below peak when a class's training kernels don't reach it.
|
|
34
|
+
# b200 (sm100) has no arch-tuned training kernels yet and falls back to the same portable paths as
|
|
35
|
+
# h200 (sm90), so its 2.25 pflops dense-bf16 peak does not materialize for training -- realized
|
|
36
|
+
# throughput is h200-class (and frequently lower for rl/grpo). cap b200 at h200 so the analytical
|
|
37
|
+
# cost model does not rank it as faster/cheaper than h200 on peak flops alone (it is not, and is
|
|
38
|
+
# often slower). this is a conservative floor: it never prices b200 above h200-equivalent training
|
|
39
|
+
# time, so it cannot over-charge, and it removes the "b200 looks cheapest" inversion at the source.
|
|
40
|
+
# refine per-workload once real b200 training samples exist. the vram/serving paths keep the true
|
|
41
|
+
# peak via gpu_tflops; only the training-time model uses this.
|
|
42
|
+
_TRAIN_TFLOPS_CAP: dict[str, float] = {
|
|
43
|
+
"B200": 990.0, # h200-class realized training throughput, not the 2250 dense-bf16 peak
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def effective_train_tflops(name: str) -> float:
|
|
48
|
+
"""Realized bf16 TRAINING throughput for the analytical cost model.
|
|
49
|
+
|
|
50
|
+
Equal to ``gpu_tflops`` (peak) except where a class's training kernels fall short of peak: b200
|
|
51
|
+
training falls back to portable kernels, so it is capped at h200-class throughput rather than
|
|
52
|
+
its raw 2.25 pflops peak."""
|
|
53
|
+
peak = gpu_tflops(name)
|
|
54
|
+
cap = _TRAIN_TFLOPS_CAP.get(name)
|
|
55
|
+
return min(peak, cap) if cap is not None else peak
|
|
56
|
+
|
|
57
|
+
|
|
33
58
|
def gpu_hourly_usd(
|
|
34
59
|
name: str,
|
|
35
60
|
provider: str | None = None,
|
|
@@ -88,19 +88,17 @@ def _on_policy_prompts_per_step(spec, examples: int) -> int:
|
|
|
88
88
|
def _sft_realized_batch(spec) -> int:
|
|
89
89
|
from flash.catalog import resolve_vocab_size
|
|
90
90
|
from flash.engine.recipe import RECIPE
|
|
91
|
-
from flash.engine.vram import
|
|
91
|
+
from flash.engine.vram import sft_chunked_nll_enabled, sft_realized_batch
|
|
92
92
|
|
|
93
93
|
t = spec.train
|
|
94
94
|
requested_batch = int(t.batch_size) if t.batch_size is not None else RECIPE.sft.effective_batch
|
|
95
95
|
sft_seq = _sft_seq_len(spec)
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
resolve_params_b(spec.model, revision=spec.model_revision), sft_seq
|
|
103
|
-
)
|
|
96
|
+
# mirror the worker's validated chunked-nll model set so pricing uses the same realized batch.
|
|
97
|
+
# every allowlisted model is a gdn hybrid; at packable context lengths the worker may force
|
|
98
|
+
# per-device=1, so price the requested batch rather than the larger chunked-nll rounded batch.
|
|
99
|
+
sft_fused = sft_chunked_nll_enabled(spec.model)
|
|
100
|
+
if sft_fused and sft_seq <= 16_384:
|
|
101
|
+
return requested_batch
|
|
104
102
|
return sft_realized_batch(
|
|
105
103
|
requested_batch,
|
|
106
104
|
seq_len=sft_seq,
|
|
@@ -167,6 +165,7 @@ def runconfig_from_spec(spec) -> RunConfig:
|
|
|
167
165
|
exact_type=g.exact_type,
|
|
168
166
|
model_revision=spec.model_revision,
|
|
169
167
|
disk_gb=float(getattr(g, "disk_gb", 0.0) or 0.0),
|
|
168
|
+
gpu_count=g.count,
|
|
170
169
|
max_wall_seconds=g.max_wall_seconds,
|
|
171
170
|
environment=spec.environment.id or None,
|
|
172
171
|
save_at_steps=t.save_at_steps,
|
|
@@ -46,6 +46,9 @@ class RunConfig:
|
|
|
46
46
|
# Spec gpu.disk_gb, carried so an exact-auto quote allocates at the run's real disk floor (parity
|
|
47
47
|
# with the launch allocate call), keeping the persisted quote aligned with the pinned hardware.
|
|
48
48
|
disk_gb: float = 0.0
|
|
49
|
+
# Spec gpu.count: cards the job occupies. total cost scales linearly with it (n cards for the
|
|
50
|
+
# billed training wall); 1 = the historical single-gpu quote.
|
|
51
|
+
gpu_count: int = 1
|
|
49
52
|
|
|
50
53
|
def __post_init__(self) -> None:
|
|
51
54
|
object.__setattr__(self, "method", normalize_algorithm(self.method))
|
|
@@ -71,6 +74,14 @@ class RunConfig:
|
|
|
71
74
|
object.__setattr__(self, "model_revision", self.model_revision.strip())
|
|
72
75
|
if self.steps < 1:
|
|
73
76
|
raise ValueError(f"steps must be >= 1, got {self.steps}")
|
|
77
|
+
if isinstance(self.gpu_count, bool) or not isinstance(self.gpu_count, int):
|
|
78
|
+
raise TypeError("gpu_count must be an integer")
|
|
79
|
+
if self.gpu_count < 1:
|
|
80
|
+
raise ValueError(f"gpu_count must be >= 1, got {self.gpu_count}")
|
|
81
|
+
# upper bound mirrors GpuSpec's 1..8 so a direct RunConfig(gpu_count=...) cannot price a
|
|
82
|
+
# count the spec layer would reject.
|
|
83
|
+
if self.gpu_count > 8:
|
|
84
|
+
raise ValueError(f"gpu_count must be <= 8, got {self.gpu_count}")
|
|
74
85
|
# Reject 0/negative positive-only knobs (bogus quote). max_wall_seconds is NOT here: the
|
|
75
86
|
# runner floors it to max(60, ...) and estimate_cost mirrors that, so a non-positive cap
|
|
76
87
|
# is accepted (floored to 60s), not rejected.
|
|
@@ -173,6 +184,8 @@ class CostEstimate:
|
|
|
173
184
|
wall_clock_seconds: float
|
|
174
185
|
wall_capped: bool
|
|
175
186
|
total_usd: float
|
|
187
|
+
# cards the job occupies; total_usd already reflects n-card billing. 1 = single-gpu quote.
|
|
188
|
+
gpu_count: int = 1
|
|
176
189
|
# opd only: external fireworks teacher token spend (0.0 for sft/grpo). billed by fireworks
|
|
177
190
|
# to the platform-managed teacher key (users don't supply one), tracked separately from the
|
|
178
191
|
# platform-billed gpu charge, so it is not part of total_usd and is shown as its own itemized
|
|
@@ -192,9 +205,9 @@ class CostEstimate:
|
|
|
192
205
|
"""Multi-line itemized breakdown for CLI output."""
|
|
193
206
|
lines = [
|
|
194
207
|
f"Run : {self.model_id} [{self.method.upper()}, {self.steps} steps]",
|
|
195
|
-
f"GPU : {self.gpu} "
|
|
208
|
+
f"GPU : {f'{self.gpu_count}x ' if self.gpu_count > 1 else ''}{self.gpu} "
|
|
196
209
|
f"({self.gpu_vram_gb} GB; run needs >= {self.required_vram_gb} GB) "
|
|
197
|
-
f"@ ${self.gpu_hourly_usd:.2f}/hr",
|
|
210
|
+
f"@ ${self.gpu_hourly_usd:.2f}/hr{' per card' if self.gpu_count > 1 else ''}",
|
|
198
211
|
f"Setup : {self.setup_seconds / 60:.1f} min (cold start: boot + deps + model load"
|
|
199
212
|
+ (" + vLLM init" if self.method == "grpo" else "")
|
|
200
213
|
+ "; not billed)",
|
|
@@ -39,3 +39,14 @@ def sanitize_diagnostic(value: Any, *, limit: int = 2000) -> str:
|
|
|
39
39
|
text = _BEARER_RE.sub("Bearer <redacted>", text)
|
|
40
40
|
text = _SECRET_KEY_RE.sub(lambda match: f"{match.group(1)}{match.group(2)}<redacted>", text)
|
|
41
41
|
return text[: max(0, int(limit))]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def neutralize_control_chars(value: Any) -> str:
|
|
45
|
+
"""Escape terminal control characters while preserving newlines as separators."""
|
|
46
|
+
text = str(value)
|
|
47
|
+
return "".join(
|
|
48
|
+
char
|
|
49
|
+
if char == "\n" or 0x20 <= ord(char) < 0x7F or ord(char) >= 0xA0
|
|
50
|
+
else f"\\x{ord(char):02x}"
|
|
51
|
+
for char in text
|
|
52
|
+
)
|
|
@@ -27,6 +27,8 @@ _BYTES_PER_PARAM = {
|
|
|
27
27
|
_BASE_OVERHEAD_GB = 4.0
|
|
28
28
|
_ACT_COEF = 0.12
|
|
29
29
|
_SFT_PER_DEVICE_BS_DEFAULT = 4
|
|
30
|
+
OPD_CE_CHUNK_SIZE = 64
|
|
31
|
+
_OPD_CE_PEAK_BYTES_PER_LOGIT = 16
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
def _sft_per_device_bs() -> int:
|
|
@@ -112,7 +114,7 @@ def opd_rollout_concurrency(prompts_per_step: int = 1, group_size: int = 1) -> i
|
|
|
112
114
|
|
|
113
115
|
|
|
114
116
|
def opd_loss_microbatch(params_b: float, prompts_per_step: int = 1, group_size: int = 1) -> int:
|
|
115
|
-
"""Loss microbatch size used by OPD's
|
|
117
|
+
"""Loss microbatch size used by OPD's GKD backward.
|
|
116
118
|
|
|
117
119
|
Keep this in lockstep with worker.opd._opd_loss_microbatch_size without importing the worker from
|
|
118
120
|
the sizing path. Small/medium catalog models run up to four loss samples per forward; 35B-class
|
|
@@ -226,17 +228,27 @@ _VOCAB_DEFAULT = 248_320
|
|
|
226
228
|
_LOGITS_BUDGET_GB = 6.0
|
|
227
229
|
# 16 B/elem: fp32 logits+grad + bf16 logits+grad + CE temp. 8 B/elem under-counts (live OOM confirmed).
|
|
228
230
|
_SFT_LOGITS_BYTES_PER_ELEM = 16.0
|
|
229
|
-
|
|
230
|
-
#
|
|
231
|
+
_SFT_CHUNKED_NLL_TOKENS = 256
|
|
232
|
+
# shared thresholds for the independent liger and worker memory gates.
|
|
231
233
|
_LIGER_MIN_PARAMS_B = 3.0
|
|
232
234
|
_LIGER_LONG_CTX_TOKENS = 2048
|
|
233
235
|
|
|
236
|
+
# trl 1.6 chunked_nll is validated against these model families. other models keep plain nll
|
|
237
|
+
# until their output-head and backbone traversal are covered by the same parity tests.
|
|
238
|
+
_SFT_CHUNKED_NLL_MODELS = frozenset(
|
|
239
|
+
{
|
|
240
|
+
"Qwen/Qwen3.5-0.8B",
|
|
241
|
+
"Qwen/Qwen3.5-2B",
|
|
242
|
+
"Qwen/Qwen3.5-4B",
|
|
243
|
+
"Qwen/Qwen3.5-9B",
|
|
244
|
+
"Qwen/Qwen3.6-35B-A3B",
|
|
245
|
+
}
|
|
246
|
+
)
|
|
234
247
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return (params_b or 0.0) >= _LIGER_MIN_PARAMS_B
|
|
248
|
+
|
|
249
|
+
def sft_chunked_nll_enabled(model_id: str) -> bool:
|
|
250
|
+
"""whether the sft worker uses trl's dense-logit-free chunked nll path."""
|
|
251
|
+
return model_id in _SFT_CHUNKED_NLL_MODELS
|
|
240
252
|
|
|
241
253
|
|
|
242
254
|
def sft_logits_per_device_cap(seq_len: int, vocab: int) -> int:
|
|
@@ -370,44 +382,27 @@ def estimate_vram_gb(
|
|
|
370
382
|
rollout = weights + max(
|
|
371
383
|
_KV_CAP, _resident_kv_gb(eff_b, seq_len, rollout_concurrency, fp8_kv=fp8_kv)
|
|
372
384
|
)
|
|
373
|
-
# opd
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
377
|
-
# sized for an under-capacity card and OOM.
|
|
378
|
-
#
|
|
379
|
-
# Mirror opd_rollout_seq_len / run_opd's completion resolution: explicit max_tokens, else the
|
|
380
|
-
# OPD recipe default (thinking uses the longer max_completion_len_thinking). A GRPO-style
|
|
381
|
-
# min(seq_len, 1024) fallback would UNDER-budget a thinking opd job (1536-token completions).
|
|
385
|
+
# text opd projects only completion-prediction hidden states and computes exact full-vocabulary
|
|
386
|
+
# ce in checkpointed chunks. image samples still use the dense full-sequence logits path and are
|
|
387
|
+
# processed one at a time. allocation does not know the dataset modality, so reserve the larger
|
|
388
|
+
# of one text ce chunk and one dense image loss forward/backward peak.
|
|
382
389
|
completion = opd_completion_len(max_tokens, thinking)
|
|
383
|
-
# run_opd backprops a small loss microbatch. Budget that actual dense-logit microbatch, not
|
|
384
|
-
# the full rollout/teacher batch and not a single sequence.
|
|
385
390
|
loss_mb = opd_loss_microbatch(params_b, batch_size, group_size)
|
|
386
391
|
activations = loss_mb * _ACT_COEF * (seq_len / 1024.0) * width
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
# - backward: fp32 gradient of those completion rows [completion, vocab]
|
|
392
|
-
# (completion * 4)
|
|
393
|
-
# bf16 gradient scattered back into the full logits [seq, vocab] to reach lm_head
|
|
394
|
-
# (seq * 2)
|
|
395
|
-
# All four coexist at the backward peak. The old formula counted only the two FORWARD buffers,
|
|
396
|
-
# so a long-completion / large-vocab (248k) opd job under-budgeted the loss backward by
|
|
397
|
-
# ~(completion*4 + seq*2)*vocab bytes and could route to a GPU that OOMs in OPD loss backward
|
|
398
|
-
# (codex[bot]). Mirror the SFT dense-logit sizing by budgeting the backward buffers too.
|
|
399
|
-
logits_fwd = loss_mb * (seq_len * 2 + completion * 4) * vocab
|
|
400
|
-
logits_bwd = loss_mb * (seq_len * 2 + completion * 4) * vocab
|
|
401
|
-
logits = (logits_fwd + logits_bwd) / 1e9
|
|
392
|
+
ce_rows = min(OPD_CE_CHUNK_SIZE, loss_mb * completion)
|
|
393
|
+
chunked_logits = ce_rows * vocab * _OPD_CE_PEAK_BYTES_PER_LOGIT / 1e9
|
|
394
|
+
dense_image_logits = (seq_len * 4 + completion * 8) * vocab / 1e9
|
|
395
|
+
logits = max(chunked_logits, dense_image_logits)
|
|
402
396
|
return base + rollout + activations + logits
|
|
403
|
-
#
|
|
404
|
-
#
|
|
405
|
-
# comparisons; the default must mirror the worker.
|
|
397
|
+
# direct callers default to the conservative plain-nll estimate. model_required_vram_gb passes
|
|
398
|
+
# the worker's validated chunked-nll decision explicitly when it knows the model identity.
|
|
406
399
|
fused = False if sft_fused_ce is None else bool(sft_fused_ce)
|
|
407
400
|
pd = sft_per_device(batch_size, seq_len=seq_len, vocab=vocab, fused=fused)
|
|
408
401
|
activations = _ACT_COEF * pd * (seq_len / 1024.0) * width
|
|
409
|
-
#
|
|
410
|
-
|
|
402
|
+
# plain nll retains every sequence position. chunked nll retains at most one 256-token vocab
|
|
403
|
+
# projection at a time, independent of micro-batch and context once the chunk is full.
|
|
404
|
+
projected_tokens = min(pd * seq_len, _SFT_CHUNKED_NLL_TOKENS) if fused else pd * seq_len
|
|
405
|
+
logits = projected_tokens * vocab * _SFT_LOGITS_BYTES_PER_ELEM / 1e9
|
|
411
406
|
return base + activations + logits
|
|
412
407
|
|
|
413
408
|
|
|
@@ -481,10 +476,10 @@ def sft_gc_off_peak_gb(
|
|
|
481
476
|
lora_rank: int = 32,
|
|
482
477
|
quant: str = "bf16",
|
|
483
478
|
) -> float:
|
|
484
|
-
"""Estimated peak VRAM (GB) for a
|
|
485
|
-
resident weights + optimizer/base + the no-recompute activations held across ALL ``num_layers``.
|
|
486
|
-
|
|
487
|
-
|
|
479
|
+
"""Estimated peak VRAM (GB) for a dense-logit-free LoRA SFT step with gradient checkpointing OFF:
|
|
480
|
+
the resident weights + optimizer/base + the no-recompute activations held across ALL ``num_layers``.
|
|
481
|
+
Chunked or fused CE is assumed, so there is no ``[B, T, vocab]`` logits term (the thing that made
|
|
482
|
+
GC-off impossible at a 248k vocab). Unknown architecture dims -> ``inf`` (caller keeps GC on).
|
|
488
483
|
|
|
489
484
|
MoE: the activation backbone scales with the model's real ``hidden`` x ``num_layers`` (geometry),
|
|
490
485
|
NOT params_b -- the ~3B-active expert FFN is already folded into ``_GC_OFF_ACT_K``. ``weights``
|
|
@@ -513,7 +508,7 @@ def sft_grad_checkpoint_can_disable(
|
|
|
513
508
|
quant: str = "bf16",
|
|
514
509
|
margin_gb: float = 18.0,
|
|
515
510
|
) -> bool:
|
|
516
|
-
"""True when a
|
|
511
|
+
"""True when a dense-logit-free LoRA SFT step fits a ``card_vram_gb`` card WITHOUT gradient checkpointing,
|
|
517
512
|
so GC -- a ~+33% recompute tax on every step -- can be turned off for the speed win.
|
|
518
513
|
|
|
519
514
|
Conservative by construction: an unknown card / unknown architecture dims, or a peak that doesn't
|
|
@@ -732,12 +727,10 @@ def model_required_vram_gb(
|
|
|
732
727
|
vllm_concurrency = (
|
|
733
728
|
opd_rollout_concurrency(batch_size, group_size) if is_opd else group_size
|
|
734
729
|
)
|
|
735
|
-
#
|
|
736
|
-
#
|
|
737
|
-
#
|
|
738
|
-
|
|
739
|
-
# routes to consumer cards and OOMs on the first backward.
|
|
740
|
-
sft_fused_ce = None if is_grpo else False
|
|
730
|
+
# trl chunked_nll removes ignored positions before the lm head and projects valid tokens in
|
|
731
|
+
# bounded chunks. size validated qwen sft jobs without a dense [batch, seq, vocab] term; models
|
|
732
|
+
# outside that validated set keep the conservative plain-nll estimate and micro-batch cap.
|
|
733
|
+
sft_fused_ce = None if is_grpo else sft_chunked_nll_enabled(model_id)
|
|
741
734
|
if info is not None:
|
|
742
735
|
params_b = info.params_b
|
|
743
736
|
if model_revision:
|
|
@@ -109,11 +109,56 @@ def finalize_alloc_conf_for_sleep() -> None:
|
|
|
109
109
|
print("[alloc] auto-conf skipped:", e)
|
|
110
110
|
|
|
111
111
|
|
|
112
|
+
def _is_cudagraph_capture_failure(exc: BaseException) -> bool:
|
|
113
|
+
markers = (
|
|
114
|
+
"capture_model",
|
|
115
|
+
"cuda graph",
|
|
116
|
+
"cudagraph",
|
|
117
|
+
"graph capture",
|
|
118
|
+
)
|
|
119
|
+
current: BaseException | None = exc
|
|
120
|
+
seen: set[int] = set()
|
|
121
|
+
while current is not None and id(current) not in seen:
|
|
122
|
+
seen.add(id(current))
|
|
123
|
+
if any(marker in f"{type(current).__name__}: {current}".lower() for marker in markers):
|
|
124
|
+
return True
|
|
125
|
+
traceback = current.__traceback__
|
|
126
|
+
while traceback is not None:
|
|
127
|
+
frame = traceback.tb_frame
|
|
128
|
+
location = f"{frame.f_code.co_filename}:{frame.f_code.co_name}".lower()
|
|
129
|
+
if any(marker in location for marker in markers):
|
|
130
|
+
return True
|
|
131
|
+
traceback = traceback.tb_next
|
|
132
|
+
current = current.__cause__ or current.__context__
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _release_failed_cudagraph_capture(exc: BaseException) -> None:
|
|
137
|
+
current: BaseException | None = exc
|
|
138
|
+
seen: set[int] = set()
|
|
139
|
+
while current is not None and id(current) not in seen:
|
|
140
|
+
seen.add(id(current))
|
|
141
|
+
next_exc = current.__cause__ or current.__context__
|
|
142
|
+
current.__traceback__ = None
|
|
143
|
+
current = next_exc
|
|
144
|
+
try:
|
|
145
|
+
import gc
|
|
146
|
+
|
|
147
|
+
gc.collect()
|
|
148
|
+
import torch
|
|
149
|
+
|
|
150
|
+
if torch.cuda.is_available():
|
|
151
|
+
torch.cuda.empty_cache()
|
|
152
|
+
except Exception as cleanup_exc:
|
|
153
|
+
print(f"[rl][warn] cuda graph fallback cleanup failed: {cleanup_exc}")
|
|
154
|
+
|
|
155
|
+
|
|
112
156
|
def patch_trl_colocate_llm_kwargs(
|
|
113
157
|
*,
|
|
114
158
|
kv_cache_dtype: str | None = None,
|
|
115
159
|
max_num_batched_tokens: int | None = None,
|
|
116
160
|
enforce_eager: bool | None = None,
|
|
161
|
+
compilation_config: dict | None = None,
|
|
117
162
|
attention_backend: str | None = None,
|
|
118
163
|
mm_encoder_attn_backend: str | None = None,
|
|
119
164
|
reasoning_parser: str | None = None,
|
|
@@ -144,6 +189,8 @@ def patch_trl_colocate_llm_kwargs(
|
|
|
144
189
|
* ``enforce_eager=True``: run the rollout engine in pure eager mode (no torch.compile, no CUDA-graph
|
|
145
190
|
capture) — the SUPPORTED replacement for the removed ``VLLM_TORCH_COMPILE_LEVEL=0`` env. Dodges
|
|
146
191
|
the vLLM 0.19.1 aot_compile (Ampere sm86) + Triton slot-mapping (graph-capture) crashes off B200.
|
|
192
|
+
* ``compilation_config``: select a narrower vLLM compilation profile, such as decode-only CUDA
|
|
193
|
+
graphs with torch.compile/AOT disabled.
|
|
147
194
|
* ``attention_backend="FLASHINFER"|"TRITON_ATTN"``: pin a PTX-independent decoder attention backend
|
|
148
195
|
(consumer-Blackwell sm120) — the SUPPORTED replacement for the removed ``VLLM_ATTENTION_BACKEND``
|
|
149
196
|
env. ``EngineArgs`` coerces the bare member name through ``AttentionConfig.validate_backend_before``.
|
|
@@ -171,6 +218,8 @@ def patch_trl_colocate_llm_kwargs(
|
|
|
171
218
|
new_overrides["max_num_batched_tokens"] = int(max_num_batched_tokens)
|
|
172
219
|
if enforce_eager is not None:
|
|
173
220
|
new_overrides["enforce_eager"] = bool(enforce_eager)
|
|
221
|
+
if compilation_config is not None:
|
|
222
|
+
new_overrides["compilation_config"] = dict(compilation_config)
|
|
174
223
|
if attention_backend is not None:
|
|
175
224
|
new_overrides["attention_backend"] = attention_backend
|
|
176
225
|
if mm_encoder_attn_backend is not None:
|
|
@@ -194,7 +243,9 @@ def patch_trl_colocate_llm_kwargs(
|
|
|
194
243
|
_vg._flash_llm_overrides = overrides
|
|
195
244
|
overrides.update(new_overrides)
|
|
196
245
|
if getattr(_vg, "_flash_llm_kwargs_patched", False):
|
|
197
|
-
print(
|
|
246
|
+
print(
|
|
247
|
+
f"[rl] colocate vLLM LLM kwargs extended (wrapper already installed): {new_overrides}"
|
|
248
|
+
)
|
|
198
249
|
return True
|
|
199
250
|
# TRL binds the module-global ``LLM`` only under ``if is_vllm_available():`` (it's the symbol the
|
|
200
251
|
# colocate ``self.llm = LLM(...)`` references). If vLLM isn't importable here there is nothing to
|
|
@@ -205,11 +256,31 @@ def patch_trl_colocate_llm_kwargs(
|
|
|
205
256
|
return False
|
|
206
257
|
|
|
207
258
|
def _patched_LLM(*args, **kwargs):
|
|
208
|
-
#
|
|
259
|
+
# override trl's hardcoded/absent values with ours (the kwargs trl/env can't set). read the
|
|
209
260
|
# accumulated dict live so kwargs registered by later calls are applied too.
|
|
210
261
|
kwargs.update(_vg._flash_llm_overrides)
|
|
211
262
|
print(f"[rl] colocate vLLM LLM(...) kwargs override applied: {_vg._flash_llm_overrides}")
|
|
212
|
-
|
|
263
|
+
compilation = kwargs.get("compilation_config") or {}
|
|
264
|
+
decode_graphs = (
|
|
265
|
+
not kwargs.get("enforce_eager", False)
|
|
266
|
+
and compilation.get("cudagraph_mode") == "FULL_DECODE_ONLY"
|
|
267
|
+
)
|
|
268
|
+
try:
|
|
269
|
+
return _orig_LLM(*args, **kwargs)
|
|
270
|
+
except Exception as capture_exc:
|
|
271
|
+
if not decode_graphs or not _is_cudagraph_capture_failure(capture_exc):
|
|
272
|
+
raise
|
|
273
|
+
_release_failed_cudagraph_capture(capture_exc)
|
|
274
|
+
eager_kwargs = dict(kwargs)
|
|
275
|
+
eager_kwargs["enforce_eager"] = True
|
|
276
|
+
eager_kwargs.pop("compilation_config", None)
|
|
277
|
+
_vg._flash_llm_overrides["enforce_eager"] = True
|
|
278
|
+
_vg._flash_llm_overrides.pop("compilation_config", None)
|
|
279
|
+
print(
|
|
280
|
+
f"[rl][warn] decode-only cuda graph capture failed ({capture_exc}); "
|
|
281
|
+
"retrying colocate vLLM initialization once in eager mode"
|
|
282
|
+
)
|
|
283
|
+
return _orig_LLM(*args, **eager_kwargs)
|
|
213
284
|
|
|
214
285
|
_vg.LLM = _patched_LLM
|
|
215
286
|
_vg._flash_llm_kwargs_patched = True
|