freesolo-flash-dev 0.2.46__tar.gz → 0.2.48__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-0.2.46 → freesolo_flash_dev-0.2.48}/PKG-INFO +2 -2
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/commands.py +5 -6
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/training_doc.py +14 -14
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cost/analytical.py +8 -12
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cost/facts.py +4 -7
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cost/spec.py +4 -7
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cost/types.py +7 -8
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/recipe.py +4 -5
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/vram.py +73 -20
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/grpo.py +2 -2
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/opd.py +237 -249
- freesolo_flash_dev-0.2.48/flash/engine/worker/opd_vllm.py +274 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/lifecycle.py +13 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/memory.py +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/rl.py +6 -5
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/lora_rank.py +8 -7
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/schema/__init__.py +21 -30
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/spec.py +4 -7
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/pyproject.toml +3 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_allocator.py +456 -61
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_b200_rollout_opt.py +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_backend_jobspec_contract.py +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_commands.py +4 -4
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_estimate.py +4 -4
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_analytical.py +43 -39
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_gpus.py +4 -4
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_grpo_params.py +51 -15
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_grpo_sleep_gate.py +4 -4
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_jobs.py +54 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_oom_escalate_gpu.py +10 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_opd.py +363 -75
- freesolo_flash_dev-0.2.48/tests/test_opd_vllm.py +184 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_open_model_policy.py +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_spec_and_validation.py +9 -5
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_train_context_preflight.py +19 -14
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/uv.lock +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.dockerignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.env.example +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/.gitignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/Dockerfile +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/LICENSE +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/README.md +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/_channel.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/_logging.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/catalog.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/client/config.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/client/http.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/train/deps.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/py.typed +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/app.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/db.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/conftest.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_export.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_version.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_vl_warmstart_recombine.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.48}/tests/test_worker_thinking.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Flash — managed LoRA post-training (SFT/GRPO) for Freesolo environments, driven by the `flash` CLI
|
|
3
|
+
Version: 0.2.48
|
|
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
|
|
7
7
|
Author: Freesolo
|
|
@@ -447,11 +447,11 @@ def cmd_env_setup(args) -> int:
|
|
|
447
447
|
'# secrets = ["SERPAPI_API_KEY"]\n\n'
|
|
448
448
|
)
|
|
449
449
|
# `thinking = true` opts the run into reasoning mode. Reasoning shares the generation budget with
|
|
450
|
-
# the answer, so GRPO also gets a raised
|
|
451
|
-
# off, keeping the default scaffold byte-for-byte identical.
|
|
450
|
+
# the answer, so GRPO also gets a raised completion budget. These strings are empty when reasoning
|
|
451
|
+
# is off, keeping the default scaffold byte-for-byte identical.
|
|
452
452
|
thinking_line = "thinking = true\n" if reasoning else ""
|
|
453
453
|
rl_reasoning_train = (
|
|
454
|
-
"
|
|
454
|
+
"max_completion_tokens = 2048 # reasoning shares this budget with the answer; raised so it isn't truncated\n"
|
|
455
455
|
if reasoning
|
|
456
456
|
else ""
|
|
457
457
|
)
|
|
@@ -504,16 +504,15 @@ def cmd_env_setup(args) -> int:
|
|
|
504
504
|
opd.write_text(
|
|
505
505
|
f"{opd_multiturn_note}"
|
|
506
506
|
'model = "Qwen/Qwen3.5-4B"\n'
|
|
507
|
-
'algorithm = "opd" # on-policy distillation from
|
|
507
|
+
'algorithm = "opd" # on-policy distillation from the managed GLM 5.2 teacher\n\n'
|
|
508
508
|
"# Environment: upload this project folder with\n"
|
|
509
509
|
"# `flash env push --name my-env .`, then paste the returned id below.\n"
|
|
510
|
-
"# The GLM teacher key
|
|
510
|
+
"# The GLM 5.2 teacher and key are platform-managed — nothing to set up or export.\n"
|
|
511
511
|
"[environment]\n"
|
|
512
512
|
'id = ""\n\n'
|
|
513
513
|
"[train]\n"
|
|
514
514
|
"steps = 100 # opd is step-driven (like GRPO)\n"
|
|
515
515
|
"lora_rank = 32\n"
|
|
516
|
-
'# teacher_model = "accounts/fireworks/models/glm-5p2" # Fireworks GLM teacher (default)\n'
|
|
517
516
|
"# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
|
|
518
517
|
"# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
|
|
519
518
|
)
|
|
@@ -201,15 +201,15 @@ spending another GPU run:
|
|
|
201
201
|
| --- | --- | --- |
|
|
202
202
|
| Environment id is blank or stale | `flash train --dry-run` fails, or the worker uses old reward/data | Run `flash env push --name my-env .` after every environment/data edit and paste the returned id into every config you submit. |
|
|
203
203
|
| Local-only env path in config | Config validation says there is no local path mode | Publish first, then use the returned slug in `[environment] id`. `flash train` only runs published env ids, not local paths. |
|
|
204
|
-
| Config knobs are in the wrong table | Validation rejects `[grpo]`, `[sft]`, or unknown `[train]` keys | Put `steps`, `epochs`, `group_size`, `
|
|
204
|
+
| Config knobs are in the wrong table | Validation rejects `[grpo]`, `[sft]`, or unknown `[train]` keys | Put `steps`, `epochs`, `group_size`, `max_completion_tokens`, `temperature`, `max_context_tokens`, LoRA, and other training knobs under `[train]`. |
|
|
205
205
|
| Trying to pin managed infrastructure | `gpu.type`, `train.hf_repo`, or `model_policy` changes do not do what you expected | Treat GPU choice, model policy, and the run artifact repo as managed. Tune the model, algorithm, environment, and `[train]` knobs instead. |
|
|
206
206
|
| Secrets are not available on the worker | Reward code works locally but remote logs show missing API keys or auth failures | List secret names under `[environment] secrets = [...]`, export those env vars locally before submit, or put them in local `.env` / `.env.local`. Never put secret values in `[worker_env]` or hard-code them in the config. |
|
|
207
207
|
| Wrong model / thinking setting | Config validation fails, or chat behavior does not match the run | Use `flash models`; set `thinking = true` only for supported models. Thinking is a training-time/run-level choice and serving preserves that parity, so `flash chat` does not expose an override flag. |
|
|
208
208
|
| Thinking reward grades the wrong text | Rewards accidentally score hidden reasoning, or ignore reasoning you meant to inspect | By default, score the answer text. In thinking mode the response object is still string-compatible, but also exposes `.completion`, `.thinking`, and `.raw` when a reward intentionally needs those fields. |
|
|
209
209
|
| All-zero or flat GRPO reward | `reward_mean` stays near 0 and outputs do not improve | Make the reward dense: give partial credit for parse/format/execution/correctness tiers, and log a separate clean `success` metric. Do not keep rerunning an all-zero reward. |
|
|
210
210
|
| Reward rises but behavior is worse | Short, templated, malformed, or reward-hacked outputs score well | Deploy the adapter and probe real examples. Add hard validity gates before judge calls, penalize degenerate shortcuts, and judge the outcome rather than the surface string. |
|
|
211
|
-
| Output is truncated | Correct-looking answers cut off mid-response or JSON is incomplete | Increase `
|
|
212
|
-
| Infrastructure, CUDA, OOM, vLLM, or kernel failure | Run errors before useful metrics, often during setup/model load | Treat this as infrastructure pressure, not proof the model is too large. Read `flash log <run-id>`, reduce footprint (`
|
|
211
|
+
| Output is truncated | Correct-looking answers cut off mid-response or JSON is incomplete | Increase `max_completion_tokens` for GRPO/OPD rollouts or `max_context_tokens` for total prompt+completion context only after seeing truncation. Oversizing them by default just burns memory/cost. |
|
|
212
|
+
| Infrastructure, CUDA, OOM, vLLM, or kernel failure | Run errors before useful metrics, often during setup/model load | Treat this as infrastructure pressure, not proof the model is too large. Read `flash log <run-id>`, reduce footprint (`max_context_tokens`, `max_completion_tokens`, `group_size`) if needed, and let Flash retry/allocate another fitting GPU class. |
|
|
213
213
|
| Run looks stuck after disconnecting | Terminal stopped streaming but the job may still be alive | Ctrl-C detaches. Use `flash log <run-id> --follow` to reattach, `flash log <run-id>` for the console/error output, or `flash cancel <run-id>` if you intentionally want to stop it. |
|
|
214
214
|
| Final checkpoint regresses | Last step is worse than an earlier checkpoint | Run `flash checkpoints <run-id>`, deploy a specific step with `flash deploy <run-id>/step-N`, and compare with held-out probes before exporting or relying on the final adapter. |
|
|
215
215
|
| Export fails before upload | CLI says no HuggingFace token | Pass `flash export --api-key hf_...`, or set `HF_TOKEN` in your shell, `.env`, or `.env.local`. Exports are private unless you pass `--public`. |
|
|
@@ -335,8 +335,8 @@ Pick SFT when you already have good answers and want the model to imitate them.
|
|
|
335
335
|
split the run never trains on, then **deploy the adapter and score it on that split**
|
|
336
336
|
(`flash deploy` + `flash chat`). If held-out quality stalls or drops while train loss
|
|
337
337
|
keeps falling, reduce `epochs` or add more data — not more passes.
|
|
338
|
-
- **Start `
|
|
339
|
-
`
|
|
338
|
+
- **Start `max_context_tokens` small and grow it on evidence.** Begin from the smallest
|
|
339
|
+
`max_context_tokens` that plausibly fits prompt + completion, and only raise it when you see
|
|
340
340
|
truncation (outputs cut off mid-thought, degraded loss). A bigger context just costs
|
|
341
341
|
more.
|
|
342
342
|
- **For Qwen3.5 thinking multi-turn SFT, put reasoning only in the final assistant
|
|
@@ -377,15 +377,16 @@ SFT is **epoch-driven** (`epochs`); GRPO is **step-driven** (`steps`).
|
|
|
377
377
|
## On-policy distillation (`algorithm = "opd"`)
|
|
378
378
|
|
|
379
379
|
Pick distillation when a much stronger **teacher** model can grade your student's work
|
|
380
|
-
token-by-token. The student samples on-policy (like GRPO),
|
|
380
|
+
token-by-token. The student samples on-policy (like GRPO), the managed GLM 5.2 teacher scores
|
|
381
381
|
each of *its own* completions, and a dense per-token loss teaches the student to match the teacher —
|
|
382
382
|
far more sample-efficient than reward-based RL and with no reward to design. It is **step-driven**
|
|
383
383
|
(`steps`) and produces a LoRA served exactly like SFT.
|
|
384
384
|
|
|
385
|
-
- **No teacher key to set up.** The
|
|
385
|
+
- **No teacher key or model override to set up.** The GLM 5.2 teacher and its Fireworks key are platform-managed: the
|
|
386
386
|
service supplies its own key to every opd run, so there is nothing to export or declare — an opd
|
|
387
|
-
run submits like any other.
|
|
388
|
-
in your shell is simply ignored.
|
|
387
|
+
run submits like any other. Bring-your-own teacher models and keys are not supported; a
|
|
388
|
+
`FIREWORKS_API_KEY` in your shell is simply ignored. The key is never stored in the spec or
|
|
389
|
+
needed at serving time.
|
|
389
390
|
- **The student (Qwen / MiniCPM / Kimi) and the teacher (GLM) have different tokenizers.** Flash
|
|
390
391
|
bridges the vocabulary mismatch with **groupwise reverse-KL** (the collinear-ai *spider* / Tinker
|
|
391
392
|
method): it aligns the two tokenizations by shared decoded-text spans and applies per-span reverse
|
|
@@ -396,7 +397,7 @@ far more sample-efficient than reward-based RL and with no reward to design. It
|
|
|
396
397
|
(driving `step_episode` / observations just like GRPO) and distils EVERY assistant turn against the
|
|
397
398
|
teacher, each conditioned on the transcript up to that turn — the episode's total reverse-KL over
|
|
398
399
|
the student's generated tokens is the sum of its per-turn reverse-KLs. Env/observation tokens are
|
|
399
|
-
never distilled (they're context, not the student's output). Set `[train]
|
|
400
|
+
never distilled (they're context, not the student's output). Set `[train] max_context_tokens` to bound the
|
|
400
401
|
transcript; the teacher must cover it (GLM-5.2's context far exceeds the default budget).
|
|
401
402
|
- **Judge it like SFT.** Distillation logs a falling per-token loss; a low loss alone is not proof.
|
|
402
403
|
Keep a held-out split, `flash deploy` the adapter, and score it — confirm the student actually
|
|
@@ -413,7 +414,6 @@ id = "your-org/my-env"
|
|
|
413
414
|
[train]
|
|
414
415
|
steps = 100
|
|
415
416
|
lora_rank = 32
|
|
416
|
-
# teacher_model = "accounts/fireworks/models/glm-5p2" # Fireworks GLM teacher (default)
|
|
417
417
|
# kl_penalty_coef = 1.0 # reverse-KL scale
|
|
418
418
|
```
|
|
419
419
|
|
|
@@ -427,7 +427,7 @@ in a sensible value, so only override with a reason.
|
|
|
427
427
|
| Knob | Convention |
|
|
428
428
|
| --- | --- |
|
|
429
429
|
| `group_size` | Completions sampled per prompt (default 8). More = more signal and more cost; drop to 4 to trim cost. The group needs *within-group variance* for an advantage to exist. |
|
|
430
|
-
| `
|
|
430
|
+
| `max_completion_tokens` | Completion budget per rollout. Size it to the expected output length — too small silently truncates good answers and poisons the reward; too large just costs more. |
|
|
431
431
|
| `temperature` | Rollout sampling temperature. Keep it near 1.0 for GRPO — too low collapses diversity (and the model can collapse within a few steps); raise it to widen exploration against uniform-reward groups. |
|
|
432
432
|
| `kl_penalty_coef` | Keeps the trained model from drifting too far from the base. Raise it to anchor against entropy collapse; lower it for more freedom to move. |
|
|
433
433
|
| `thinking_length_penalty_coef` | Per-reasoning-token reward deduction — curb overthinking, but watch it doesn't push the model into terse degeneracy. |
|
|
@@ -468,7 +468,7 @@ targeted fix rather than leaning on the reward gate to slowly select against it.
|
|
|
468
468
|
| --- | --- | --- |
|
|
469
469
|
| Repetition / looping collapse | the same phrase repeats until truncation | repetition or length penalty; lower `temperature` |
|
|
470
470
|
| Overthinking / verbose reasoning | reasoning eats the whole token budget | `thinking_length_penalty_coef`; tighten the prompt |
|
|
471
|
-
|
|
|
471
|
+
| Completion truncation | answers cut off mid-thought | raise `max_completion_tokens` / `max_context_tokens` |
|
|
472
472
|
| Unparsed / over-escaped output | reward can't read the answer | robust parser; return `0.0` on parse fail; format gate |
|
|
473
473
|
| Wrapper / markdown around structured output | prose around the JSON/answer | a format gate; `stop_sequences` |
|
|
474
474
|
| Uniform-reward groups | every rollout in a group scores the same → no gradient | shape the reward for partial credit; raise `temperature` |
|
|
@@ -513,7 +513,7 @@ on a beyond-noise improvement.
|
|
|
513
513
|
## Treat crashes as infra, not model size
|
|
514
514
|
|
|
515
515
|
> A CUDA / OOM / vLLM / kernel / infrastructure error is an **infrastructure** problem, not a
|
|
516
|
-
> sign the model is too big. Lower `
|
|
516
|
+
> sign the model is too big. Lower `max_context_tokens`, `max_completion_tokens`, or `group_size` to shrink
|
|
517
517
|
> the run's footprint and let the allocator retry onto the next fitting GPU class — do
|
|
518
518
|
> **not** switch to a smaller model to make a crash disappear. That silently destroys
|
|
519
519
|
> quality.
|
|
@@ -44,11 +44,6 @@ MFU_DECODE = 0.12 # batched vLLM rollout (decode is memory-bandwidth-bound)
|
|
|
44
44
|
# wall is ceil(completions / slots) waves x latency, not completions x latency.
|
|
45
45
|
REWARD_CONCURRENCY = 16.0
|
|
46
46
|
|
|
47
|
-
# Teacher scoring is CONCURRENT too: run_opd's primary path fans a step's completions across up to
|
|
48
|
-
# TEACHER_CONCURRENCY Fireworks calls (mirror of opd.py _TEACHER_SCORE_MAX_WORKERS), so the teacher
|
|
49
|
-
# wall is ceil(completions / slots) waves x latency, not completions x latency.
|
|
50
|
-
TEACHER_CONCURRENCY = 8.0
|
|
51
|
-
|
|
52
47
|
# Cold-start overhead (seconds): container boot + deps + model load (+ vLLM init for GRPO).
|
|
53
48
|
#
|
|
54
49
|
# Calibrated against a real fresh-worker run (0.8B SFT, RTX 3090 @ $0.239/hr) whose elapsed wall
|
|
@@ -78,11 +73,11 @@ def _fmt_duration(seconds: float) -> str:
|
|
|
78
73
|
|
|
79
74
|
def setup_seconds(config: RunConfig) -> float:
|
|
80
75
|
"""Cold-start wall time before the first optimizer step: container boot + deps + model load
|
|
81
|
-
(a fixed deserialize/placement/init base + a size-scaled download), plus vLLM init for
|
|
76
|
+
(a fixed deserialize/placement/init base + a size-scaled download), plus vLLM init for rollouts.
|
|
82
77
|
This elapsed setup time is reported but not included in customer-facing cost."""
|
|
83
78
|
model_load = MODEL_LOAD_BASE_S + download_weight_gb(config.model_id) / DOWNLOAD_RATE_GBPS
|
|
84
79
|
s = WORKER_BOOT_S + DEPS_INSTALL_S + model_load
|
|
85
|
-
if config.
|
|
80
|
+
if config.has_rollout:
|
|
86
81
|
s += VLLM_INIT_S
|
|
87
82
|
return s
|
|
88
83
|
|
|
@@ -112,11 +107,12 @@ def seconds_per_step(config: RunConfig, gpu: str) -> float:
|
|
|
112
107
|
gen_s = (GRPO_GEN_FLOPS_PER_TOKEN_PER_PARAM * params * seq_tokens) / (peak * MFU_DECODE)
|
|
113
108
|
update_s = (OPD_UPDATE_FLOPS_PER_TOKEN_PER_PARAM * params * seq_tokens) / (peak * MFU_TRAIN)
|
|
114
109
|
teacher_lat = teacher_seconds_per_completion()
|
|
115
|
-
# run_opd's primary path scores a step's completions CONCURRENTLY over Fireworks
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
|
|
110
|
+
# run_opd's primary path scores a step's completions CONCURRENTLY over Fireworks with a fan-out
|
|
111
|
+
# cap of the step's OWN completion count (prompts_per_step * group_size, opd.py Phase 2), so
|
|
112
|
+
# every completion in a step is scored in ONE parallel wave — the teacher wall is a single
|
|
113
|
+
# latency, NOT the full serial sum (that describes only the CPU-test fallback that can't
|
|
114
|
+
# batch-generate). The teacher endpoint's rate limit is the real ceiling on this fan-out.
|
|
115
|
+
teacher_s = teacher_lat if completions else 0.0
|
|
120
116
|
return gen_s + teacher_s + update_s
|
|
121
117
|
|
|
122
118
|
if not n.is_grpo:
|
|
@@ -166,10 +166,9 @@ def reward_seconds_per_completion(override: float | None = None) -> float:
|
|
|
166
166
|
# NO FIREWORKS_API_KEY. Source: https://fireworks.ai/models/fireworks/glm-5p2 lists
|
|
167
167
|
# $1.40 / $0.14 / $4.40 (input / cached input / output) per 1M. opd echo-scores completions
|
|
168
168
|
# (max_tokens=0), so only INPUT tokens are billed (the teacher never generates) — but the table keeps
|
|
169
|
-
# both so a mispriced entry is obvious.
|
|
169
|
+
# both so a mispriced entry is obvious.
|
|
170
170
|
TEACHER_USD_PER_1M: dict[str, tuple[float, float]] = {
|
|
171
171
|
"accounts/fireworks/models/glm-5p2": (1.40, 4.40),
|
|
172
|
-
"accounts/fireworks/models/glm-5p1": (1.40, 4.40),
|
|
173
172
|
}
|
|
174
173
|
# Fireworks echo-scoring round-trip per completion (wall time, concurrency-bound like reward grading).
|
|
175
174
|
AVG_TEACHER_SECONDS_PER_COMPLETION = 2.0
|
|
@@ -178,11 +177,9 @@ AVG_TEACHER_SECONDS_PER_COMPLETION = 2.0
|
|
|
178
177
|
def teacher_price_per_1m(teacher_model: str) -> tuple[float, float]:
|
|
179
178
|
"""(input, output) $/1M tokens for a teacher model.
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
unknown non-default teacher falls back to the default teacher's rate (spec-parse already rejects
|
|
185
|
-
an unpriced teacher_model, so this is only a defensive backstop)."""
|
|
180
|
+
OPD uses the recipe's fixed GLM 5.2 teacher. ``teacher_model`` is accepted only for internal
|
|
181
|
+
diagnostics/tests; user configs cannot override it. Unknown values fall back defensively to
|
|
182
|
+
the fixed teacher rate."""
|
|
186
183
|
from flash.engine.recipe import RECIPE
|
|
187
184
|
|
|
188
185
|
default = TEACHER_USD_PER_1M[RECIPE.opd.teacher_model]
|
|
@@ -24,8 +24,8 @@ def _sft_seq_len(spec) -> int:
|
|
|
24
24
|
|
|
25
25
|
t = spec.train
|
|
26
26
|
return (
|
|
27
|
-
int(t.
|
|
28
|
-
if t.
|
|
27
|
+
int(t.max_context_tokens)
|
|
28
|
+
if t.max_context_tokens is not None
|
|
29
29
|
else (RECIPE.sft.max_seq_len_thinking if spec.thinking else RECIPE.sft.max_seq_len)
|
|
30
30
|
)
|
|
31
31
|
|
|
@@ -101,8 +101,8 @@ def runconfig_from_spec(spec) -> RunConfig:
|
|
|
101
101
|
model_id=spec.model,
|
|
102
102
|
method=spec.algorithm,
|
|
103
103
|
steps=spec_steps(spec),
|
|
104
|
-
seq_len=t.
|
|
105
|
-
completion_len=t.
|
|
104
|
+
seq_len=t.max_context_tokens,
|
|
105
|
+
completion_len=t.max_completion_tokens if has_rollout else None,
|
|
106
106
|
batch_size=t.batch_size,
|
|
107
107
|
group_size=t.group_size if has_rollout else None,
|
|
108
108
|
lora_rank=t.lora_rank,
|
|
@@ -110,9 +110,6 @@ def runconfig_from_spec(spec) -> RunConfig:
|
|
|
110
110
|
provider="auto",
|
|
111
111
|
max_wall_seconds=g.max_wall_seconds,
|
|
112
112
|
environment=spec.environment.id or None,
|
|
113
|
-
# "" is the unset sentinel (RunConfig.teacher_model); facts.teacher_price_per_1m resolves it
|
|
114
|
-
# to the recipe default. Non-opd carries no teacher.
|
|
115
|
-
teacher_model=t.teacher_model if spec.algorithm == "opd" else "",
|
|
116
113
|
)
|
|
117
114
|
|
|
118
115
|
|
|
@@ -17,19 +17,18 @@ class RunConfig:
|
|
|
17
17
|
method: str # "sft" | "grpo" | "opd"
|
|
18
18
|
steps: int
|
|
19
19
|
|
|
20
|
-
# Engine context length (forwarded as [train].
|
|
20
|
+
# Engine context length (forwarded as [train].max_context_tokens, NOT prompt length). When unset the
|
|
21
21
|
# GRPO default mirrors the worker's max(1024, max_prompt_len + completion); see normalized().
|
|
22
22
|
seq_len: int | None = None
|
|
23
|
-
completion_len: int | None = None # GRPO only (
|
|
23
|
+
completion_len: int | None = None # GRPO/OPD only (max_completion_tokens)
|
|
24
24
|
batch_size: int | None = None # SFT effective batch / GRPO prompts_per_step
|
|
25
25
|
group_size: int | None = None # GRPO completions per prompt (G)
|
|
26
26
|
lora_rank: int | None = None
|
|
27
27
|
thinking: bool = False
|
|
28
28
|
# GRPO only: seconds to score one completion. None -> the single average grader latency.
|
|
29
29
|
reward_seconds_per_completion: float | None = None
|
|
30
|
-
# OPD only:
|
|
31
|
-
#
|
|
32
|
-
# teacher (RECIPE.opd.teacher_model) at the pricing boundary (facts.teacher_price_per_1m).
|
|
30
|
+
# OPD only: internal Fireworks teacher id for teacher-token diagnostics. User configs cannot
|
|
31
|
+
# override this; an empty value resolves to the recipe's fixed GLM 5.2 teacher.
|
|
33
32
|
teacher_model: str = ""
|
|
34
33
|
|
|
35
34
|
max_wall_seconds: int | None = None # wall cap (spec gpu.max_wall_seconds); None = 24h
|
|
@@ -83,7 +82,7 @@ class RunConfig:
|
|
|
83
82
|
comp = self.completion_len
|
|
84
83
|
if comp is None:
|
|
85
84
|
comp = rc.max_completion_len_thinking if self.thinking else rc.max_completion_len
|
|
86
|
-
# Explicit pin wins; else mirror the allocator's rollout sizing of an unset
|
|
85
|
+
# Explicit pin wins; else mirror the allocator's rollout sizing of an unset context:
|
|
87
86
|
# max(1024, max_prompt_len + completion), not bare max_prompt_len (which under-sizes).
|
|
88
87
|
seq = (
|
|
89
88
|
self.seq_len
|
|
@@ -117,9 +116,9 @@ class RunConfig:
|
|
|
117
116
|
if self.batch_size is not None:
|
|
118
117
|
knobs["batch_size"] = self.batch_size
|
|
119
118
|
if n.seq_len is not None:
|
|
120
|
-
knobs["
|
|
119
|
+
knobs["max_context_tokens"] = n.seq_len
|
|
121
120
|
if n.completion_len is not None:
|
|
122
|
-
knobs["
|
|
121
|
+
knobs["max_completion_tokens"] = n.completion_len
|
|
123
122
|
if n.group_size is not None:
|
|
124
123
|
knobs["group_size"] = n.group_size
|
|
125
124
|
return knobs
|
|
@@ -36,7 +36,7 @@ class RLConfig:
|
|
|
36
36
|
learning_rate: float = 1e-5
|
|
37
37
|
max_prompt_len: int = 2048
|
|
38
38
|
max_completion_len: int = 320
|
|
39
|
-
# 320 is too short for <think> blocks; overridable via [train].
|
|
39
|
+
# 320 is too short for <think> blocks; overridable via [train].max_completion_tokens.
|
|
40
40
|
max_completion_len_thinking: int = 1536
|
|
41
41
|
prompts_per_step: int = 64
|
|
42
42
|
group_size: int = 8
|
|
@@ -50,9 +50,8 @@ class OPDConfig:
|
|
|
50
50
|
"""On-policy distillation: student samples, a remote teacher scores its tokens, and a groupwise
|
|
51
51
|
reverse-KL loss (the collinear-ai spider / Tinker cross-tokenizer method) trains the student."""
|
|
52
52
|
|
|
53
|
-
# Fireworks-hosted teacher reached over the OpenAI-compatible API
|
|
54
|
-
#
|
|
55
|
-
# supervise the (much smaller) student.
|
|
53
|
+
# Fixed Fireworks-hosted GLM 5.2 teacher reached over the OpenAI-compatible API. This is
|
|
54
|
+
# platform-managed and intentionally not configurable from [train].
|
|
56
55
|
teacher_model: str = "accounts/fireworks/models/glm-5p2"
|
|
57
56
|
teacher_base_url: str = "https://api.fireworks.ai/inference/v1"
|
|
58
57
|
# OPD is step-driven like GRPO (on-policy sampling), not epoch-driven like SFT.
|
|
@@ -60,7 +59,7 @@ class OPDConfig:
|
|
|
60
59
|
learning_rate: float = 1e-5
|
|
61
60
|
max_prompt_len: int = 1024
|
|
62
61
|
max_completion_len: int = 512
|
|
63
|
-
# 512 is short for <think> traces; overridable via [train].
|
|
62
|
+
# 512 is short for <think> traces; overridable via [train].max_completion_tokens.
|
|
64
63
|
max_completion_len_thinking: int = 1536
|
|
65
64
|
prompts_per_step: int = 8
|
|
66
65
|
# Student samples per prompt. 1 is enough for a direct KD loss (no group-relative baseline
|
|
@@ -96,6 +96,20 @@ def opd_rollout_seq_len(
|
|
|
96
96
|
return int(max_length or max(1024, RECIPE.opd.max_prompt_len + completion))
|
|
97
97
|
|
|
98
98
|
|
|
99
|
+
def opd_rollout_concurrency(prompts_per_step: int = 1, group_size: int = 1) -> int:
|
|
100
|
+
"""Concurrent student generations in one OPD vLLM rollout batch."""
|
|
101
|
+
|
|
102
|
+
def _positive_int(value: object, default: int) -> int:
|
|
103
|
+
try:
|
|
104
|
+
if isinstance(value, bool):
|
|
105
|
+
return default
|
|
106
|
+
return max(1, int(value))
|
|
107
|
+
except (TypeError, ValueError):
|
|
108
|
+
return default
|
|
109
|
+
|
|
110
|
+
return _positive_int(prompts_per_step, 1) * _positive_int(group_size, 1)
|
|
111
|
+
|
|
112
|
+
|
|
99
113
|
def _resident_kv_gb(
|
|
100
114
|
params_b: float | None, vllm_max_len: int, num_generations: int = 8, fp8_kv: bool = False
|
|
101
115
|
) -> float:
|
|
@@ -188,6 +202,12 @@ def colocate_kv_util(
|
|
|
188
202
|
_TRAIN_COEF = 0.27
|
|
189
203
|
# Small-model colocated GRPO floor: 0.8B OOMs 20 GB; 2B OOMs 24 GB -> both need 32 GB tier.
|
|
190
204
|
_VLLM_COLOCATE_FLOOR_GB = 28.0
|
|
205
|
+
# OPD builds its resident vLLM engine after the HF/PEFT student is already loaded. A real
|
|
206
|
+
# Qwen3.5-2B OPD run with vLLM failed vLLM startup on a 32 GB RTX 5090 despite the raw equation
|
|
207
|
+
# estimating ~28 GB with headroom, because vLLM requires the requested executor budget to be free at
|
|
208
|
+
# init time. Keep 2B+ OPD off <=40 GB classes so the allocator picks an 80 GB-class card instead of a
|
|
209
|
+
# consumer GPU that passes the aggregate estimate but fails the vLLM free-memory preflight.
|
|
210
|
+
_OPD_VLLM_COLOCATE_FLOOR_GB = 41.0
|
|
191
211
|
_VOCAB_DEFAULT = 248_320
|
|
192
212
|
_LOGITS_BUDGET_GB = 6.0
|
|
193
213
|
# 16 B/elem: fp32 logits+grad + bf16 logits+grad + CE temp. 8 B/elem under-counts (live OOM confirmed).
|
|
@@ -328,6 +348,14 @@ def estimate_vram_gb(
|
|
|
328
348
|
train = activations + logits
|
|
329
349
|
return base + (max(rollout, train) if sleep_offload else rollout + train)
|
|
330
350
|
if is_opd:
|
|
351
|
+
# OPD always samples the student through a resident colocated vLLM engine, while the HF/PEFT
|
|
352
|
+
# trainer model stays resident for the GKD loss forward/backward. Budget the second bf16
|
|
353
|
+
# weight copy plus a viable KV pool through the training step. ``use_vllm`` is intentionally
|
|
354
|
+
# ignored for OPD; it only exists for legacy GRPO sizing callers.
|
|
355
|
+
rollout_concurrency = opd_rollout_concurrency(batch_size, group_size)
|
|
356
|
+
rollout = weights + max(
|
|
357
|
+
_KV_CAP, _resident_kv_gb(eff_b, seq_len, rollout_concurrency, fp8_kv=fp8_kv)
|
|
358
|
+
)
|
|
331
359
|
# opd's gkd loss forward materializes DENSE logits — there is NO fused cross-entropy: the
|
|
332
360
|
# student forward yields full-sequence bf16 logits [seq, vocab], then the completion rows are
|
|
333
361
|
# gathered in fp32 [completion, vocab] for the logsumexp. The SFT fused path budgets ZERO
|
|
@@ -357,8 +385,11 @@ def estimate_vram_gb(
|
|
|
357
385
|
logits_fwd = (seq_len * 2 + completion * 4) * vocab
|
|
358
386
|
logits_bwd = (seq_len * 2 + completion * 4) * vocab
|
|
359
387
|
logits = (logits_fwd + logits_bwd) / 1e9
|
|
360
|
-
return base + activations + logits
|
|
361
|
-
fused
|
|
388
|
+
return base + rollout + activations + logits
|
|
389
|
+
# Actual TRL SFT keeps fused CE disabled (see worker/sft.py), so dense logits materialize even
|
|
390
|
+
# for long-context / >=3B models. Callers can pass sft_fused_ce=True only for theoretical
|
|
391
|
+
# comparisons; the default must mirror the worker.
|
|
392
|
+
fused = False if sft_fused_ce is None else bool(sft_fused_ce)
|
|
362
393
|
pd = sft_per_device(batch_size, seq_len=seq_len, vocab=vocab, fused=fused)
|
|
363
394
|
activations = _ACT_COEF * pd * (seq_len / 1024.0) * width
|
|
364
395
|
# Don't clamp to budget: pd=1 is irreducible and the logits can exceed the budget at near-2048 ctx.
|
|
@@ -516,7 +547,7 @@ def model_required_vram_gb(
|
|
|
516
547
|
except (TypeError, ValueError):
|
|
517
548
|
return default
|
|
518
549
|
|
|
519
|
-
max_tokens = _pos_int(_g(train, "
|
|
550
|
+
max_tokens = _pos_int(_g(train, "max_completion_tokens"), None)
|
|
520
551
|
_algo = (algorithm or "").lower()
|
|
521
552
|
if _algo in ("grpo", "rl"):
|
|
522
553
|
_default_len = grpo_rollout_seq_len(0, max_tokens, thinking)
|
|
@@ -525,10 +556,18 @@ def model_required_vram_gb(
|
|
|
525
556
|
_default_len = opd_rollout_seq_len(0, max_tokens, thinking)
|
|
526
557
|
else:
|
|
527
558
|
_default_len = 1024
|
|
528
|
-
seq_len = _pos_int(_g(train, "
|
|
559
|
+
seq_len = _pos_int(_g(train, "max_context_tokens"), _default_len)
|
|
529
560
|
lora_rank = _pos_int(_g(train, "lora_rank"), 32)
|
|
530
|
-
|
|
531
|
-
|
|
561
|
+
if _algo == "opd":
|
|
562
|
+
from flash.engine.recipe import RECIPE
|
|
563
|
+
|
|
564
|
+
batch_size_default = int(RECIPE.opd.prompts_per_step)
|
|
565
|
+
group_size_default = int(RECIPE.opd.group_size)
|
|
566
|
+
else:
|
|
567
|
+
batch_size_default = _sft_per_device_bs()
|
|
568
|
+
group_size_default = 8
|
|
569
|
+
group_size = _pos_int(_g(train, "group_size"), group_size_default)
|
|
570
|
+
batch_size = _pos_int(_g(train, "batch_size"), batch_size_default)
|
|
532
571
|
|
|
533
572
|
def _need(
|
|
534
573
|
params_b: float,
|
|
@@ -557,17 +596,21 @@ def model_required_vram_gb(
|
|
|
557
596
|
return math.ceil(est * headroom)
|
|
558
597
|
|
|
559
598
|
from flash.catalog import MODELS, vocab_size_for
|
|
560
|
-
from flash.engine.chalk_kernels import chalk_supports_fused_ce_model
|
|
561
599
|
|
|
562
600
|
info = MODELS.get(model_id)
|
|
563
601
|
model_vocab = vocab_size_for(model_id)
|
|
564
|
-
is_grpo =
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
and chalk_supports_fused_ce_model(model_id)
|
|
602
|
+
is_grpo = _algo in ("grpo", "rl")
|
|
603
|
+
is_opd = _algo == "opd"
|
|
604
|
+
is_vllm_rollout = is_grpo or is_opd
|
|
605
|
+
vllm_concurrency = (
|
|
606
|
+
opd_rollout_concurrency(batch_size, group_size) if is_opd else group_size
|
|
570
607
|
)
|
|
608
|
+
# Worker parity: TRL SFT deliberately calls install_chalk_kernels(..., fused_ce=False), because
|
|
609
|
+
# SFTTrainer.compute_loss reads outputs.logits and crashes when fused CE returns logits=None. So
|
|
610
|
+
# every SFT run materializes dense logits, even for long context / >=3B models where the old
|
|
611
|
+
# allocator assumed a fused CE path. Size SFT with fused CE OFF up front or long-context Qwen SFT
|
|
612
|
+
# routes to consumer cards and OOMs on the first backward.
|
|
613
|
+
sft_fused_ce = None if is_grpo else False
|
|
571
614
|
if info is not None:
|
|
572
615
|
params_b = info.params_b # curated, authoritative (required field) — no string parsing
|
|
573
616
|
quant = getattr(info, "quant", "bf16") or "bf16"
|
|
@@ -620,29 +663,39 @@ def model_required_vram_gb(
|
|
|
620
663
|
else:
|
|
621
664
|
floor += grpo_seq_escalation_gb(active_b or params_b, seq_len)
|
|
622
665
|
need = max(need, floor)
|
|
623
|
-
if
|
|
666
|
+
if is_vllm_rollout and use_vllm:
|
|
624
667
|
floor_gb = 24 if (params_b or 0.0) <= 1.0 else int(_VLLM_COLOCATE_FLOOR_GB)
|
|
668
|
+
if is_opd and (params_b or 0.0) >= 2.0:
|
|
669
|
+
floor_gb = max(floor_gb, int(_OPD_VLLM_COLOCATE_FLOOR_GB))
|
|
625
670
|
need = max(need, floor_gb)
|
|
626
671
|
# vLLM KV-cache init preflight: the card must leave a viable cache-block pool
|
|
627
672
|
# under the colocate utilization cap, or the engine dies at init ("No available
|
|
628
673
|
# memory for the cache blocks") on a card the training-peak estimate accepted.
|
|
629
674
|
need = max(
|
|
630
675
|
need,
|
|
631
|
-
grpo_kv_floor_gb(
|
|
676
|
+
grpo_kv_floor_gb(
|
|
677
|
+
params_b or 4.0,
|
|
678
|
+
seq_len,
|
|
679
|
+
vllm_concurrency,
|
|
680
|
+
active_params_b=active_b,
|
|
681
|
+
),
|
|
632
682
|
)
|
|
633
683
|
return need
|
|
634
684
|
params_b = fetch_hf_params_b(model_id)
|
|
635
685
|
if params_b is None:
|
|
636
686
|
return 24
|
|
637
687
|
# Size the uncataloged (model_policy="allow") fallback with the ACTUAL algorithm, not a hardcoded
|
|
638
|
-
# "grpo".
|
|
639
|
-
#
|
|
640
|
-
#
|
|
641
|
-
# _need; do the same here (codex[bot]). The grpo-only escalations below stay gated on is_grpo.
|
|
688
|
+
# "grpo". The cataloged path above already threads `algorithm` through _need; do the same here so
|
|
689
|
+
# open-model OPD uses its own dense-logit + colocated-vLLM estimator. The grpo-only sequence
|
|
690
|
+
# escalation stays gated on is_grpo.
|
|
642
691
|
need = _need(params_b, algorithm, vocab=model_vocab)
|
|
643
692
|
if is_grpo:
|
|
644
693
|
need += grpo_seq_escalation_gb(params_b, seq_len)
|
|
645
|
-
|
|
694
|
+
if is_vllm_rollout:
|
|
695
|
+
floor_gb = 24 if params_b <= 1.0 else int(_VLLM_COLOCATE_FLOOR_GB)
|
|
696
|
+
if is_opd and params_b >= 2.0:
|
|
697
|
+
floor_gb = max(floor_gb, int(_OPD_VLLM_COLOCATE_FLOOR_GB))
|
|
698
|
+
need = max(need, floor_gb, grpo_kv_floor_gb(params_b, seq_len, vllm_concurrency))
|
|
646
699
|
return need
|
|
647
700
|
|
|
648
701
|
|
|
@@ -137,7 +137,7 @@ def grpo_overrides() -> dict:
|
|
|
137
137
|
cfg = {
|
|
138
138
|
"group_size": train.group_size,
|
|
139
139
|
"temperature": train.temperature,
|
|
140
|
-
"max_tokens": train.
|
|
140
|
+
"max_tokens": train.max_completion_tokens,
|
|
141
141
|
"kl_penalty_coef": train.kl_penalty_coef,
|
|
142
142
|
"advantage_clip": train.advantage_clip,
|
|
143
143
|
"thinking_length_penalty_coef": train.thinking_length_penalty_coef,
|
|
@@ -173,7 +173,7 @@ def resolve_grpo_sleep_mode() -> tuple[bool, int, float, bool]:
|
|
|
173
173
|
spec = _w.JOB_SPEC
|
|
174
174
|
train = spec.train if spec else None
|
|
175
175
|
model_id = spec.model if spec else ""
|
|
176
|
-
ctx = int(train.
|
|
176
|
+
ctx = int(train.max_context_tokens if train and train.max_context_tokens else 0)
|
|
177
177
|
gcfg = _w.grpo_overrides()
|
|
178
178
|
group_size = int(gcfg.get("group_size") or RECIPE.rl.group_size)
|
|
179
179
|
lora_rank = int(train.lora_rank) if train and train.lora_rank else 32
|