freesolo-flash-dev 0.2.46__tar.gz → 0.2.47__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.47}/PKG-INFO +2 -2
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/commands.py +2 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/training_doc.py +5 -5
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cost/analytical.py +6 -10
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cost/facts.py +4 -7
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cost/spec.py +0 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cost/types.py +2 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/recipe.py +2 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/opd.py +10 -11
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/schema/__init__.py +2 -17
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/spec.py +0 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/pyproject.toml +3 -3
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_analytical.py +16 -25
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_opd.py +7 -10
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/uv.lock +1 -1
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.dockerignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.env.example +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.gitignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/Dockerfile +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/LICENSE +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/README.md +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/_channel.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/_logging.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/catalog.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/client/config.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/client/http.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/train/deps.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/py.typed +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/app.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/db.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/conftest.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_export.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_version.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_vl_warmstart_recombine.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/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.47
|
|
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
|
|
@@ -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
|
)
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -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]
|
|
@@ -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
|
|
|
@@ -27,9 +27,8 @@ class RunConfig:
|
|
|
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
|
|
@@ -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.
|
|
@@ -54,11 +54,6 @@ from flash.engine.worker.perf import (
|
|
|
54
54
|
from flash.engine.worker.teacher import TeacherError
|
|
55
55
|
from flash.engine.worker.tokenizer_align import groupwise_alignment, groupwise_coverage
|
|
56
56
|
|
|
57
|
-
# Upper bound on teacher-scoring HTTP calls fired concurrently within one optimizer step. Generation
|
|
58
|
-
# (GPU) and the gkd loss forward/backward stay serial on the main thread; only the (dominant) teacher
|
|
59
|
-
# Fireworks round-trips for a step's samples are overlapped, so this caps the fan-out into the API.
|
|
60
|
-
_TEACHER_SCORE_MAX_WORKERS = 8 # bound concurrent GLM/Fireworks scoring calls per step
|
|
61
|
-
|
|
62
57
|
|
|
63
58
|
@dataclass(frozen=True)
|
|
64
59
|
class OpdKnobs:
|
|
@@ -108,7 +103,7 @@ def _resolve_opd_knobs() -> OpdKnobs:
|
|
|
108
103
|
"publishes an untrained adapter. Omit the field to use the default, or set a positive value."
|
|
109
104
|
)
|
|
110
105
|
return OpdKnobs(
|
|
111
|
-
teacher_model=
|
|
106
|
+
teacher_model=d.teacher_model,
|
|
112
107
|
teacher_base_url=d.teacher_base_url,
|
|
113
108
|
steps=int(opt("steps", 0) or d.num_steps),
|
|
114
109
|
learning_rate=float(opt("learning_rate", 0) or d.learning_rate),
|
|
@@ -668,16 +663,20 @@ def run_opd():
|
|
|
668
663
|
# Feed the stall clock during the (serial, up-to-~900s-each) generations;
|
|
669
664
|
# nseq is still 0 here since no loss has landed yet this step.
|
|
670
665
|
_opd_progress(opt_steps, nseq)
|
|
671
|
-
# Phase 2 (concurrent, NETWORK only): fire the teacher scoring calls for
|
|
672
|
-
# rollout at once
|
|
673
|
-
#
|
|
674
|
-
#
|
|
666
|
+
# Phase 2 (concurrent, NETWORK only): fire the teacher scoring calls for EVERY scorable
|
|
667
|
+
# rollout at once — the fan-out cap is the step's own completion count
|
|
668
|
+
# (prompts_per_step * group_size), so every sample in a step is scored in parallel (one
|
|
669
|
+
# round-trip of wall time) and the concurrency self-scales when group_size is raised
|
|
670
|
+
# (no queueing 8-at-a-time). The teacher endpoint's own rate limit is the real ceiling;
|
|
671
|
+
# 429s retry inside _score_one. _score_one touches only the stateless teacher HTTP client
|
|
672
|
+
# + Python strings (no torch/model/shared mutable state), so the round-trips overlap
|
|
673
|
+
# safely; truncated/empty/U+FFFD rollouts are never scored.
|
|
675
674
|
scorable = [i for i, p in enumerate(pending) if not (p.gen.skip or p.gen.truncated)]
|
|
676
675
|
_opd_progress(opt_steps, nseq) # refresh entering the (bounded) network phase
|
|
677
676
|
if scorable:
|
|
678
677
|
permanent_err = None
|
|
679
678
|
with ThreadPoolExecutor(
|
|
680
|
-
max_workers=min(len(scorable),
|
|
679
|
+
max_workers=min(len(scorable), knobs.prompts_per_step * knobs.group_size)
|
|
681
680
|
) as pool:
|
|
682
681
|
fut_to_idx = {
|
|
683
682
|
pool.submit(
|
|
@@ -21,7 +21,6 @@ from flash.schema.fields import (
|
|
|
21
21
|
_train_float,
|
|
22
22
|
_train_int,
|
|
23
23
|
_train_stops,
|
|
24
|
-
_train_str,
|
|
25
24
|
_wandb_spec,
|
|
26
25
|
_worker_env,
|
|
27
26
|
)
|
|
@@ -210,8 +209,6 @@ _TRAIN_KEYS = frozenset(
|
|
|
210
209
|
"stop_sequences",
|
|
211
210
|
"max_steps",
|
|
212
211
|
"max_examples",
|
|
213
|
-
# on-policy distillation (algorithm="opd")
|
|
214
|
-
"teacher_model",
|
|
215
212
|
}
|
|
216
213
|
)
|
|
217
214
|
|
|
@@ -222,7 +219,7 @@ def spec_from_dict(raw: dict[str, Any], run_id: str | None = None) -> JobSpec:
|
|
|
222
219
|
hint = ""
|
|
223
220
|
if {"grpo", "sft", "opd"} & set(unknown):
|
|
224
221
|
hint = (
|
|
225
|
-
" — GRPO/SFT/opd knobs (group_size, batch_size, max_tokens,
|
|
222
|
+
" — GRPO/SFT/opd knobs (group_size, batch_size, max_tokens, …) "
|
|
226
223
|
"belong under [train], not a [grpo]/[sft]/[opd] table"
|
|
227
224
|
)
|
|
228
225
|
raise ConfigError(
|
|
@@ -358,7 +355,6 @@ def spec_from_dict(raw: dict[str, Any], run_id: str | None = None) -> JobSpec:
|
|
|
358
355
|
# minimum=0: explicit 0 means "no cap" per TrainSpec contract
|
|
359
356
|
max_steps=_train_int(train_raw, "max_steps", minimum=0),
|
|
360
357
|
max_examples=_train_int(train_raw, "max_examples", minimum=0),
|
|
361
|
-
teacher_model=_train_str(train_raw, "teacher_model"),
|
|
362
358
|
),
|
|
363
359
|
gpu=GpuSpec(type=gpu_type),
|
|
364
360
|
run_id=run_id or "local", # server-assigned at create_run; never user-set
|
|
@@ -389,24 +385,13 @@ def _validate_grpo(spec: JobSpec) -> None:
|
|
|
389
385
|
|
|
390
386
|
|
|
391
387
|
def _validate_opd(spec: JobSpec) -> None:
|
|
392
|
-
"""OPD contract: step-driven (positive steps)
|
|
388
|
+
"""OPD contract: step-driven (positive steps) with a usable prompt budget.
|
|
393
389
|
|
|
394
390
|
The teacher key (FIREWORKS_API_KEY) is a platform-owned credential the control plane injects into
|
|
395
391
|
the worker env (build_worker_env), like HF_TOKEN — never a user-declared secret."""
|
|
396
392
|
if spec.train.steps is not None and spec.train.steps <= 0:
|
|
397
393
|
# OPD is step-driven (on-policy sampling), like GRPO — not epoch-driven.
|
|
398
394
|
raise ConfigError("train.steps must be positive for opd")
|
|
399
|
-
if spec.train.teacher_model:
|
|
400
|
-
# Reject an unpriced teacher override at parse time: falling back to the default rate would
|
|
401
|
-
# make both the submit-time quote and the final charge wrong for a differently-priced model.
|
|
402
|
-
from flash.cost.facts import TEACHER_USD_PER_1M
|
|
403
|
-
|
|
404
|
-
if spec.train.teacher_model not in TEACHER_USD_PER_1M:
|
|
405
|
-
raise ConfigError(
|
|
406
|
-
f"[train] teacher_model {spec.train.teacher_model!r} has no pricing entry, so its "
|
|
407
|
-
f"cost quote and charge would silently use the default rate. Use a priced teacher "
|
|
408
|
-
f"({', '.join(sorted(TEACHER_USD_PER_1M))}) or add an entry in flash/cost/facts.py."
|
|
409
|
-
)
|
|
410
395
|
if spec.train.max_length:
|
|
411
396
|
# Mirror run_opd's prompt-budget guard at PARSE time: a max_length that leaves no room for
|
|
412
397
|
# any prompt after the completion budget is rejected here, BEFORE a paid worker is
|
|
@@ -124,8 +124,6 @@ class TrainSpec:
|
|
|
124
124
|
advantage_clip: float | None = None
|
|
125
125
|
thinking_length_penalty_coef: float | None = None
|
|
126
126
|
stop_sequences: tuple[str, ...] = ()
|
|
127
|
-
# On-policy distillation (algorithm="opd"). None/"" => worker resolves the recipe default.
|
|
128
|
-
teacher_model: str = ""
|
|
129
127
|
|
|
130
128
|
|
|
131
129
|
@dataclass(frozen=True)
|
|
@@ -212,7 +210,6 @@ class JobSpec:
|
|
|
212
210
|
advantage_clip=_opt_float(train.get("advantage_clip")),
|
|
213
211
|
thinking_length_penalty_coef=_opt_float(train.get("thinking_length_penalty_coef")),
|
|
214
212
|
stop_sequences=_str_tuple(train.get("stop_sequences")),
|
|
215
|
-
teacher_model=str(train.get("teacher_model") or ""),
|
|
216
213
|
),
|
|
217
214
|
gpu=GpuSpec(
|
|
218
215
|
type=gpu.get("type", DEFAULT_GPU),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "freesolo-flash-dev"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "Flash — managed LoRA post-training (SFT/GRPO) for Freesolo environments, driven by the `flash` CLI"
|
|
3
|
+
version = "0.2.47"
|
|
4
|
+
description = "Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
# RunPod Flash supports Python 3.11-3.12 (not 3.13 yet).
|
|
7
7
|
requires-python = ">=3.11,<3.13"
|
|
@@ -106,7 +106,7 @@ artifacts = ["flash/py.typed"]
|
|
|
106
106
|
# auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
|
|
107
107
|
# PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
|
|
108
108
|
# dev-channel release = bump this (and [project].version) and merge to `dev`.
|
|
109
|
-
version = "0.2.
|
|
109
|
+
version = "0.2.47"
|
|
110
110
|
|
|
111
111
|
[tool.pytest.ini_options]
|
|
112
112
|
pythonpath = ["."]
|
|
@@ -272,33 +272,24 @@ def test_nonpositive_run_knobs_rejected(knob, bad):
|
|
|
272
272
|
RunConfig(MID, "grpo", 100, **{knob: bad})
|
|
273
273
|
|
|
274
274
|
|
|
275
|
-
def
|
|
276
|
-
# Teacher scoring
|
|
277
|
-
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
|
|
282
|
-
from flash.cost.analytical import TEACHER_CONCURRENCY, seconds_per_step
|
|
275
|
+
def test_opd_teacher_scoring_is_one_parallel_wave():
|
|
276
|
+
# Teacher scoring fans a step's completions across prompts_per_step*group_size concurrent Fireworks
|
|
277
|
+
# calls (opd.py Phase 2), so EVERY completion in a step is scored in one parallel wave -- the
|
|
278
|
+
# teacher wall is a single latency regardless of completion count, NOT the serial (completions x
|
|
279
|
+
# latency) sum. Hold seq_tokens (hence gen_s/update_s) constant while doubling the completion count;
|
|
280
|
+
# since scoring is now fully parallel the teacher term is unchanged, so the per-step delta is 0.
|
|
281
|
+
from flash.cost.analytical import seconds_per_step
|
|
283
282
|
from flash.cost.facts import teacher_seconds_per_completion
|
|
284
283
|
|
|
285
284
|
gpu = "RTX 5090"
|
|
286
285
|
teacher_lat = teacher_seconds_per_completion()
|
|
287
|
-
assert teacher_lat > 0 # else the
|
|
288
|
-
|
|
289
|
-
#
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
delta = seconds_per_step(
|
|
293
|
-
assert delta == pytest.approx(
|
|
294
|
-
"
|
|
286
|
+
assert teacher_lat > 0 # else the isolation below is vacuous
|
|
287
|
+
# completions x seq_len is identical (8*2048 == 16*1024), so gen_s/update_s match and only the
|
|
288
|
+
# completion count (hence any wave scaling) differs.
|
|
289
|
+
few = RunConfig(MID, "opd", 10, batch_size=8, group_size=1, seq_len=2048)
|
|
290
|
+
many = RunConfig(MID, "opd", 10, batch_size=16, group_size=1, seq_len=1024)
|
|
291
|
+
delta = seconds_per_step(many, gpu) - seconds_per_step(few, gpu)
|
|
292
|
+
assert delta == pytest.approx(0.0, abs=1e-6), (
|
|
293
|
+
"full-parallel teacher scoring bills one wave; doubling completions at equal total tokens "
|
|
294
|
+
"must not add teacher latency"
|
|
295
295
|
)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
def test_opd_teacher_concurrency_matches_worker_pool():
|
|
299
|
-
# The cost model's TEACHER_CONCURRENCY must track the worker's actual pool size, or quotes drift
|
|
300
|
-
# from real runs. Guard the two constants against silent divergence.
|
|
301
|
-
from flash.cost.analytical import TEACHER_CONCURRENCY
|
|
302
|
-
from flash.engine.worker.opd import _TEACHER_SCORE_MAX_WORKERS
|
|
303
|
-
|
|
304
|
-
assert TEACHER_CONCURRENCY == _TEACHER_SCORE_MAX_WORKERS
|
|
@@ -416,24 +416,23 @@ def test_opd_vram_sizing_uses_completion_budget_not_sft_default():
|
|
|
416
416
|
assert opd_rollout_seq_len(4096, 8192, False) == 4096 # explicit max_length pins the sequence
|
|
417
417
|
|
|
418
418
|
|
|
419
|
-
def
|
|
419
|
+
def test_opd_rejects_teacher_model_override():
|
|
420
420
|
from flash.schema import ConfigError, spec_from_dict
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
with pytest.raises(ConfigError, match="teacher_model"):
|
|
423
|
+
spec_from_dict(
|
|
424
424
|
{
|
|
425
425
|
"model": "Qwen/Qwen3.5-4B",
|
|
426
426
|
"algorithm": "opd",
|
|
427
427
|
"environment": {"id": "github:owner/repo@main:env/environment.py"},
|
|
428
|
-
"train": {
|
|
428
|
+
"train": {
|
|
429
|
+
"steps": 5,
|
|
430
|
+
"teacher_model": "accounts/fireworks/models/glm-5p2",
|
|
431
|
+
},
|
|
429
432
|
},
|
|
430
433
|
run_id="x",
|
|
431
434
|
)
|
|
432
435
|
|
|
433
|
-
_spec("accounts/fireworks/models/glm-5p2") # priced -> ok
|
|
434
|
-
with pytest.raises(ConfigError):
|
|
435
|
-
_spec("accounts/fireworks/models/mystery-9000") # unpriced override -> reject at parse
|
|
436
|
-
|
|
437
436
|
|
|
438
437
|
def test_opd_rejects_prompt_budget_at_parse_time_before_provisioning():
|
|
439
438
|
"""max_length <= max_tokens leaves no prompt budget; opd must reject it at spec-parse time
|
|
@@ -2607,7 +2606,6 @@ def test_opd_spec_json_round_trip():
|
|
|
2607
2606
|
"environment": {"id": "github:owner/repo@main:env/environment.py"},
|
|
2608
2607
|
"train": {
|
|
2609
2608
|
"steps": 25,
|
|
2610
|
-
"teacher_model": "accounts/fireworks/models/glm-5p1",
|
|
2611
2609
|
"hf_repo": "owner/runs",
|
|
2612
2610
|
},
|
|
2613
2611
|
},
|
|
@@ -2616,7 +2614,6 @@ def test_opd_spec_json_round_trip():
|
|
|
2616
2614
|
restored = JobSpec.from_json(spec.to_json())
|
|
2617
2615
|
assert restored == spec
|
|
2618
2616
|
assert restored.phase == "opd"
|
|
2619
|
-
assert restored.train.teacher_model == "accounts/fireworks/models/glm-5p1"
|
|
2620
2617
|
# The teacher key is platform-managed (control-plane-injected into the worker env, like
|
|
2621
2618
|
# HF_TOKEN) — NOT a user secret, so it is never added to environment.secrets.
|
|
2622
2619
|
assert "FIREWORKS_API_KEY" not in restored.environment.secrets
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/bake-kernel-cache.yml
RENAMED
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/main-source-guard.yml
RENAMED
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/notify-tests-repo.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/.github/workflows/version-parity.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/docker/Dockerfile.kernelcache.relayer
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/kernel_warmup.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/diagnostics.py
RENAMED
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/lifecycle.py
RENAMED
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/perf/loraplus.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-0.2.46 → freesolo_flash_dev-0.2.47}/flash/engine/worker/tokenizer_align.py
RENAMED
|
File without changes
|