freesolo-flash-dev 1.0.63__tar.gz → 1.0.65__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/rl_train.py +42 -11
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/sft_train.py +41 -1
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_rl_train.py +101 -3
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_sft_train.py +200 -3
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/uv.lock +1 -1
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.env.example +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/README.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/TRAINING.md +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/env_eval.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/colocation.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/grpo_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/grpo_plugin.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/multiturn_glue.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd_plugin.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd_structured.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/opd_validation.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/providers/weight_cache_preload.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/db.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/projects.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/flash/thinking.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_colocation.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/tests/test_worker_thinking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.65
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
|
@@ -105,6 +105,17 @@ _MULTI_TURN_SCORE_BATCH_SIZE = 64
|
|
|
105
105
|
_MULTI_TURN_SCORE_FLUSH_WAIT_S = 0.1
|
|
106
106
|
_MULTI_TURN_SCORE_SHUTDOWN_WAIT_S = 5.0
|
|
107
107
|
|
|
108
|
+
# the bridge's listen() backlog. verl opens one connection per episode and starts a whole step's
|
|
109
|
+
# episodes at once, so the accept queue sees the entire rollout batch -- prompts_per_step *
|
|
110
|
+
# group_size, 512 on the default 64x8 recipe -- connecting in a burst. socketserver's default of 5
|
|
111
|
+
# overflows there and the kernel RESETS the excess, which surfaces client-side as
|
|
112
|
+
# ConnectionResetError at getresponse() (the connect and send landed in the queue; the reset arrives
|
|
113
|
+
# when the queue is dropped). bridge_post deliberately does not retry, so that reset kills the run.
|
|
114
|
+
# the opd teacher bridge already carries this fix as _TEXT_TEACHER_REQUEST_BACKLOG; a fixed constant
|
|
115
|
+
# would only move the cliff, so size the queue from the burst the caller actually generates.
|
|
116
|
+
# linux caps the effective backlog at somaxconn (4096 here) and silently clamps beyond it.
|
|
117
|
+
_REWARD_BRIDGE_MIN_REQUEST_BACKLOG = 128
|
|
118
|
+
|
|
108
119
|
|
|
109
120
|
# --------------------------------------------------------------------------------------------
|
|
110
121
|
# pure helpers (no verl, no gpu, no network) -- unit tested directly.
|
|
@@ -1229,14 +1240,20 @@ def render_reentrant_checkpointing_shim(reentrant: bool, *, multimodal: bool = F
|
|
|
1229
1240
|
engines whose config may legitimately have checkpointing off, and enabling it there would turn
|
|
1230
1241
|
on a feature verl chose to leave off.
|
|
1231
1242
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1243
|
+
reentrant recompute drops the backward for a checkpointed block when none of that block's
|
|
1244
|
+
inputs require grad. that hits the LANGUAGE side on every lora run: lora freezes the
|
|
1245
|
+
embeddings, so the hidden states entering the first checkpointed decoder layer have
|
|
1246
|
+
``requires_grad=False`` and the whole segment -- containing every lora parameter -- receives no
|
|
1247
|
+
gradient, while the run reports success and bills (GRAD-001). ``enable_input_require_grads()``
|
|
1248
|
+
is what prevents it, and it is unconditional here because every flash rl run is lora.
|
|
1249
|
+
|
|
1250
|
+
on a MULTIMODAL run the same hook additionally restores VISION input gradients. the vision
|
|
1251
|
+
tower's patch embeddings are the same failure in a place the language-side call does not
|
|
1252
|
+
reach: the pixels are frozen inputs, so without a forward hook marking the patch-embed output
|
|
1253
|
+
as requiring grad the visual modules silently receive nothing while the language side trains
|
|
1254
|
+
normally (``tests/test_multimodal_input_grads.py``). the retired trl path installed that hook
|
|
1255
|
+
via a trainer callback; verl has no callback surface, so it rides this shim instead -- and only
|
|
1256
|
+
here, because non-reentrant recompute does not have the behaviour that makes it necessary
|
|
1240
1257
|
(codex[bot]).
|
|
1241
1258
|
"""
|
|
1242
1259
|
if not reentrant:
|
|
@@ -1290,6 +1307,13 @@ def _flash_reentrant_build_module(self):
|
|
|
1290
1307
|
# only when verl actually enabled checkpointing: calling gradient_checkpointing_enable on a
|
|
1291
1308
|
# model verl deliberately left uncheckpointed would turn it ON and change the memory profile.
|
|
1292
1309
|
if getattr(self.model_config, "enable_gradient_checkpointing", False):
|
|
1310
|
+
# the LANGUAGE-side counterpart of the vision hook below, and required for the same
|
|
1311
|
+
# reason (GRAD-001): lora freezes the embeddings, so nothing entering the first
|
|
1312
|
+
# checkpointed decoder layer requires grad and reentrant recompute drops the backward
|
|
1313
|
+
# for the whole segment -- where every lora parameter lives. the vision hook only ever
|
|
1314
|
+
# covered the patch embeddings on multimodal runs; text-only runs had no hook at all and
|
|
1315
|
+
# trained nothing while reporting success.
|
|
1316
|
+
module.enable_input_require_grads()
|
|
1293
1317
|
module.gradient_checkpointing_enable(gradient_checkpointing_kwargs={{"use_reentrant": True}}){vision_hook}
|
|
1294
1318
|
print("[rl-verl] reentrant gradient checkpointing is active", flush=True)
|
|
1295
1319
|
return module
|
|
@@ -2071,12 +2095,15 @@ def multi_turn_child_env(inp: dict, *, reward_url: str, thinking: bool) -> dict[
|
|
|
2071
2095
|
}
|
|
2072
2096
|
|
|
2073
2097
|
|
|
2074
|
-
def start_reward_server(
|
|
2098
|
+
def start_reward_server(
|
|
2099
|
+
score_by_index, *, example_count: int, multi_turn_bridge=None, rollout_batch: int = 0
|
|
2100
|
+
):
|
|
2075
2101
|
"""start a localhost http reward server. score_by_index(index, solution_str) -> float.
|
|
2076
2102
|
|
|
2077
2103
|
returns (server, base_url). the server runs in a daemon thread; call server.shutdown() when
|
|
2078
2104
|
done. single-turn scoring lives at ``<base_url>/score``; when ``multi_turn_bridge`` is given,
|
|
2079
|
-
its four episode routes are served alongside it from the same thread pool.
|
|
2105
|
+
its four episode routes are served alongside it from the same thread pool. ``rollout_batch`` is
|
|
2106
|
+
how many episodes verl starts at once (prompts_per_step * group_size) and sizes the accept queue.
|
|
2080
2107
|
"""
|
|
2081
2108
|
# serialize scoring so the flash env sees sequential calls: a flash env is a plain python object
|
|
2082
2109
|
# with no concurrency contract, and the retired trl path only ever called it from one thread.
|
|
@@ -2123,7 +2150,10 @@ def start_reward_server(score_by_index, *, example_count: int, multi_turn_bridge
|
|
|
2123
2150
|
self.end_headers()
|
|
2124
2151
|
self.wfile.write(body)
|
|
2125
2152
|
|
|
2126
|
-
|
|
2153
|
+
class _RewardBridgeHTTPServer(ThreadingHTTPServer):
|
|
2154
|
+
request_queue_size = max(_REWARD_BRIDGE_MIN_REQUEST_BACKLOG, int(rollout_batch))
|
|
2155
|
+
|
|
2156
|
+
server = _RewardBridgeHTTPServer(("127.0.0.1", 0), _Handler)
|
|
2127
2157
|
threading.Thread(target=server.serve_forever, daemon=True).start()
|
|
2128
2158
|
port = server.server_address[1]
|
|
2129
2159
|
return server, f"http://127.0.0.1:{port}"
|
|
@@ -3159,6 +3189,7 @@ def run_rl_train():
|
|
|
3159
3189
|
_score,
|
|
3160
3190
|
example_count=len(rollout_examples),
|
|
3161
3191
|
multi_turn_bridge=multi_turn_bridge,
|
|
3192
|
+
rollout_batch=int(inp["prompts_per_step"]) * int(inp["group_size"]),
|
|
3162
3193
|
)
|
|
3163
3194
|
# bound before the try so the finally can always ask whether it was started.
|
|
3164
3195
|
resume_uploader: _VerlResumeUploader | None = None
|
|
@@ -57,6 +57,10 @@ from flash.engine.worker.sft import (
|
|
|
57
57
|
_SFT_LORAPLUS_RATIO = 16.0
|
|
58
58
|
_LORAPLUS_READY_MARKER = "FLASH_LORAPLUS_READY"
|
|
59
59
|
_VERL_STEP_RE = re.compile(r"(?:^|\s)step:(\d+)(?:\s|$)")
|
|
60
|
+
# consecutive zero-grad-norm steps tolerated before the run is failed as untrainable (GRAD-001).
|
|
61
|
+
# 2 is enough to separate a one-off fully-masked batch from a severed backward graph, and keeps
|
|
62
|
+
# the wasted spend to a couple of steps rather than the whole run.
|
|
63
|
+
_MAX_ZERO_GRAD_STEPS = 2
|
|
60
64
|
|
|
61
65
|
_REQUIRED_OVERRIDE_KEYS = (
|
|
62
66
|
"train_files",
|
|
@@ -535,6 +539,15 @@ _flash_original_build_module = _FlashFSDPEngine._build_module
|
|
|
535
539
|
|
|
536
540
|
def _flash_build_reentrant_module(self):
|
|
537
541
|
module = _flash_original_build_module(self)
|
|
542
|
+
# REQUIRED before enabling reentrant checkpointing on a lora model, and the reason every
|
|
543
|
+
# verl sft run silently trained nothing (GRAD-001). lora freezes the embeddings, so the
|
|
544
|
+
# hidden states entering the first checkpointed decoder layer have requires_grad=False.
|
|
545
|
+
# reentrant checkpointing needs at least one input tensor requiring grad to attach the
|
|
546
|
+
# recomputed forward to the graph; with none it warns "None of the inputs have
|
|
547
|
+
# requires_grad=True. Gradients will be None" and returns no gradient for the whole
|
|
548
|
+
# segment -- which is where every lora parameter lives. result was grad_norm 0.0 on every
|
|
549
|
+
# step while the run reported done and billed. opd already does this; sft did not.
|
|
550
|
+
module.enable_input_require_grads()
|
|
538
551
|
module.gradient_checkpointing_enable(gradient_checkpointing_kwargs={"use_reentrant": True})
|
|
539
552
|
return module
|
|
540
553
|
|
|
@@ -1340,6 +1353,9 @@ def run_sft_train(spec=None) -> None:
|
|
|
1340
1353
|
]
|
|
1341
1354
|
|
|
1342
1355
|
progress = {"step": resume_step, "loss": None, "grad_norm": None, "lr": None}
|
|
1356
|
+
# consecutive steps seen with grad_norm == 0.0 at a nonzero lr. one step can legitimately be
|
|
1357
|
+
# zero (a fully-masked micro-batch), so require a short run of them before failing.
|
|
1358
|
+
zero_grad_steps: list[int] = []
|
|
1343
1359
|
loss_curve: list[float] = []
|
|
1344
1360
|
train_tokens = sft_completed_train_tokens(
|
|
1345
1361
|
total_tokens_per_epoch,
|
|
@@ -1379,6 +1395,21 @@ def run_sft_train(spec=None) -> None:
|
|
|
1379
1395
|
progress["loss"] = loss
|
|
1380
1396
|
if grad_norm is not None:
|
|
1381
1397
|
progress["grad_norm"] = grad_norm
|
|
1398
|
+
# a grad norm of exactly 0.0 while the lr is still nonzero means the backward pass
|
|
1399
|
+
# produced nothing for every trainable parameter. that is never legitimate: it is a
|
|
1400
|
+
# broken graph, not a small update. GRAD-001 shipped four runs that reported done and
|
|
1401
|
+
# billed while training nothing, because this number was recorded and never read.
|
|
1402
|
+
# fail the run instead of paying for a zero adapter that then deploys and serves.
|
|
1403
|
+
if grad_norm == 0.0 and (learning_rate_value is None or learning_rate_value > 0.0):
|
|
1404
|
+
zero_grad_steps.append(int(progress["step"] or 0))
|
|
1405
|
+
if len(zero_grad_steps) >= _MAX_ZERO_GRAD_STEPS:
|
|
1406
|
+
raise RuntimeError(
|
|
1407
|
+
"verl reported train/grad_norm=0.0 with a nonzero learning rate on "
|
|
1408
|
+
f"{len(zero_grad_steps)} consecutive steps: no gradient is reaching the "
|
|
1409
|
+
"lora parameters, so this run would train nothing. see GRAD-001"
|
|
1410
|
+
)
|
|
1411
|
+
else:
|
|
1412
|
+
zero_grad_steps.clear()
|
|
1382
1413
|
if learning_rate_value is not None:
|
|
1383
1414
|
progress["lr"] = learning_rate_value
|
|
1384
1415
|
|
|
@@ -1402,6 +1433,14 @@ def run_sft_train(spec=None) -> None:
|
|
|
1402
1433
|
return_code = 0
|
|
1403
1434
|
if resume_step < update_horizon:
|
|
1404
1435
|
watcher.start()
|
|
1436
|
+
# completeness is only a meaningful question when training ran to the end. an on_line
|
|
1437
|
+
# callback that raises (the zero-grad guard above, the lora+ guard) unwinds BEFORE
|
|
1438
|
+
# return_code is assigned, so deriving the flag from return_code alone would leave it at
|
|
1439
|
+
# its initial 0 and demand every required save from a run that stopped at step 2. the
|
|
1440
|
+
# watcher would then raise "required saves were not durably published" from the finally
|
|
1441
|
+
# and REPLACE the diagnosis with a downstream symptom. opd_train tracks the same flag for
|
|
1442
|
+
# the same reason.
|
|
1443
|
+
training_completed = False
|
|
1405
1444
|
try:
|
|
1406
1445
|
with liveness_heartbeat(
|
|
1407
1446
|
"sft_step",
|
|
@@ -1415,8 +1454,9 @@ def run_sft_train(spec=None) -> None:
|
|
|
1415
1454
|
on_line=on_line,
|
|
1416
1455
|
heartbeat=child_heartbeat,
|
|
1417
1456
|
)
|
|
1457
|
+
training_completed = return_code == 0
|
|
1418
1458
|
finally:
|
|
1419
|
-
watcher.stop(require_complete=
|
|
1459
|
+
watcher.stop(require_complete=training_completed)
|
|
1420
1460
|
train_wall = time.time() - train_started_at
|
|
1421
1461
|
device_peak_gpu_gb = gpu_sampler.stop_gb()
|
|
1422
1462
|
if return_code != 0:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "freesolo-flash-dev"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.65"
|
|
4
4
|
description = "Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
# RunPod Flash supports Python 3.11-3.12 (not 3.13 yet).
|
|
@@ -123,7 +123,7 @@ artifacts = ["flash/py.typed"]
|
|
|
123
123
|
# auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
|
|
124
124
|
# PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
|
|
125
125
|
# dev-channel release = bump this (and [project].version) and merge to `dev`.
|
|
126
|
-
version = "1.0.
|
|
126
|
+
version = "1.0.65"
|
|
127
127
|
|
|
128
128
|
[tool.pytest.ini_options]
|
|
129
129
|
pythonpath = ["."]
|
|
@@ -11,6 +11,7 @@ import math
|
|
|
11
11
|
import os
|
|
12
12
|
import re
|
|
13
13
|
import shutil
|
|
14
|
+
import socket
|
|
14
15
|
import sys
|
|
15
16
|
import textwrap
|
|
16
17
|
import threading
|
|
@@ -1202,6 +1203,52 @@ def test_concurrent_scorers_are_serialized_for_the_env():
|
|
|
1202
1203
|
server.shutdown()
|
|
1203
1204
|
|
|
1204
1205
|
|
|
1206
|
+
def test_reward_server_accept_queue_holds_a_whole_rollout_batch(monkeypatch):
|
|
1207
|
+
# verl opens one connection per episode and starts a whole step at once, so the accept queue
|
|
1208
|
+
# sees prompts_per_step * group_size connects in a burst. socketserver's default backlog of 5
|
|
1209
|
+
# overflows there and the kernel RESETS the excess, which reaches the client as
|
|
1210
|
+
# ConnectionResetError at getresponse(); bridge_post does not retry, so that kills the run.
|
|
1211
|
+
rollout_batch = 512 # the default 64x8 recipe
|
|
1212
|
+
|
|
1213
|
+
# record the argument the server actually hands to listen(). asserting on request_queue_size
|
|
1214
|
+
# alone cannot tell a working fix from a no-op: server_activate() reads that attribute once,
|
|
1215
|
+
# so a value set after server_bind() would never reach the socket at all.
|
|
1216
|
+
backlogs = []
|
|
1217
|
+
real_listen = socket.socket.listen
|
|
1218
|
+
|
|
1219
|
+
def spy_listen(self, *args):
|
|
1220
|
+
backlogs.append(args[0] if args else None)
|
|
1221
|
+
return real_listen(self, *args)
|
|
1222
|
+
|
|
1223
|
+
monkeypatch.setattr(socket.socket, "listen", spy_listen)
|
|
1224
|
+
|
|
1225
|
+
server, _url = rl_train.start_reward_server(
|
|
1226
|
+
lambda idx, solution: 1.0, example_count=8, rollout_batch=rollout_batch
|
|
1227
|
+
)
|
|
1228
|
+
try:
|
|
1229
|
+
assert server.request_queue_size >= rollout_batch
|
|
1230
|
+
assert backlogs, "server never called listen()"
|
|
1231
|
+
assert backlogs[-1] is not None, "listen() was called with no backlog argument"
|
|
1232
|
+
assert backlogs[-1] >= rollout_batch, f"listen() backlog is {backlogs[-1]}"
|
|
1233
|
+
finally:
|
|
1234
|
+
server.shutdown()
|
|
1235
|
+
server.server_close()
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
@pytest.mark.parametrize("rollout_batch", [0, 32, 64 * 8, 2048])
|
|
1239
|
+
def test_reward_bridge_backlog_never_falls_below_the_burst(rollout_batch):
|
|
1240
|
+
# a fixed constant would only move the cliff, so the queue is sized from the caller's burst.
|
|
1241
|
+
# an unspecified batch still keeps a floor well clear of socketserver's default of 5.
|
|
1242
|
+
server, _url = rl_train.start_reward_server(
|
|
1243
|
+
lambda idx, solution: 1.0, example_count=1, rollout_batch=rollout_batch
|
|
1244
|
+
)
|
|
1245
|
+
try:
|
|
1246
|
+
assert server.request_queue_size >= max(128, rollout_batch)
|
|
1247
|
+
finally:
|
|
1248
|
+
server.shutdown()
|
|
1249
|
+
server.server_close()
|
|
1250
|
+
|
|
1251
|
+
|
|
1205
1252
|
# ------------------------------- reward parity -------------------------------
|
|
1206
1253
|
class _BreakdownEnv:
|
|
1207
1254
|
def scores_breakdown(self, graded, ex, state):
|
|
@@ -1699,6 +1746,48 @@ def test_the_reentrant_shim_installs_vision_input_grads_only_for_multimodal_runs
|
|
|
1699
1746
|
assert rl_train.render_reentrant_checkpointing_shim(False, multimodal=True) == ""
|
|
1700
1747
|
|
|
1701
1748
|
|
|
1749
|
+
def test_the_reentrant_shim_enables_language_side_input_grads_before_checkpointing():
|
|
1750
|
+
"""GRAD-001: every rl run is lora, so lora freezes the embeddings and nothing entering the
|
|
1751
|
+
first checkpointed decoder layer requires grad. reentrant recompute then drops the backward
|
|
1752
|
+
for the whole segment -- where every lora parameter lives -- and the run reports success while
|
|
1753
|
+
training nothing. the vision hook only ever covered the patch embeddings on multimodal runs;
|
|
1754
|
+
text-only runs had no hook at all."""
|
|
1755
|
+
calls = []
|
|
1756
|
+
|
|
1757
|
+
class FakeModule:
|
|
1758
|
+
def enable_input_require_grads(self):
|
|
1759
|
+
calls.append("require_grads")
|
|
1760
|
+
|
|
1761
|
+
def gradient_checkpointing_enable(self, **kwargs):
|
|
1762
|
+
calls.append(("gc_enable", kwargs))
|
|
1763
|
+
|
|
1764
|
+
class FakeEngine:
|
|
1765
|
+
def __init__(self, checkpointing):
|
|
1766
|
+
self.model_config = SimpleNamespace(enable_gradient_checkpointing=checkpointing)
|
|
1767
|
+
|
|
1768
|
+
def _build_module(self):
|
|
1769
|
+
return FakeModule()
|
|
1770
|
+
|
|
1771
|
+
source = rl_train.render_reentrant_checkpointing_shim(True)
|
|
1772
|
+
start = source.index("def _flash_reentrant_build_module")
|
|
1773
|
+
end = source.index("_FlashReentrantEngine._build_module = _flash_reentrant_build_module")
|
|
1774
|
+
namespace = {"_flash_reentrant_original_build_module": FakeEngine._build_module}
|
|
1775
|
+
exec(compile(source[start:end], "sitecustomize.py", "exec"), namespace)
|
|
1776
|
+
build = namespace["_flash_reentrant_build_module"]
|
|
1777
|
+
|
|
1778
|
+
build(FakeEngine(checkpointing=True))
|
|
1779
|
+
# order matters: enabling checkpointing first captures the graph before any input requires
|
|
1780
|
+
# grad, so asserting mere presence would pass on a broken shim.
|
|
1781
|
+
assert calls[0] == "require_grads"
|
|
1782
|
+
assert calls[1] == ("gc_enable", {"gradient_checkpointing_kwargs": {"use_reentrant": True}})
|
|
1783
|
+
|
|
1784
|
+
# the guard is load-bearing: when verl left checkpointing OFF, touching the module at all
|
|
1785
|
+
# would turn on a feature verl deliberately declined and change the memory profile.
|
|
1786
|
+
calls.clear()
|
|
1787
|
+
build(FakeEngine(checkpointing=False))
|
|
1788
|
+
assert calls == []
|
|
1789
|
+
|
|
1790
|
+
|
|
1702
1791
|
@contextlib.contextmanager
|
|
1703
1792
|
def _vision_hook_installer(torch_module):
|
|
1704
1793
|
"""yield the rendered vision helper with a stand-in torch visible to it.
|
|
@@ -1831,6 +1920,10 @@ def test_the_reentrant_shim_flips_the_flag_and_leaves_uncheckpointed_models_alon
|
|
|
1831
1920
|
class _Module:
|
|
1832
1921
|
def __init__(self):
|
|
1833
1922
|
self.kwargs = None
|
|
1923
|
+
self.input_grads = False
|
|
1924
|
+
|
|
1925
|
+
def enable_input_require_grads(self):
|
|
1926
|
+
self.input_grads = True
|
|
1834
1927
|
|
|
1835
1928
|
def gradient_checkpointing_enable(self, gradient_checkpointing_kwargs=None):
|
|
1836
1929
|
self.kwargs = gradient_checkpointing_kwargs
|
|
@@ -1857,12 +1950,17 @@ def test_the_reentrant_shim_flips_the_flag_and_leaves_uncheckpointed_models_alon
|
|
|
1857
1950
|
sys.modules.setdefault(name, types.ModuleType(name))
|
|
1858
1951
|
sys.modules[module_stub.__name__] = module_stub
|
|
1859
1952
|
exec(rl_train.render_reentrant_checkpointing_shim(True), {})
|
|
1860
|
-
# checkpointing on -> the flag is put back to reentrant
|
|
1953
|
+
# checkpointing on -> the flag is put back to reentrant, and the lora-frozen embeddings
|
|
1954
|
+
# get input grads so the checkpointed segment actually produces a backward (GRAD-001)
|
|
1861
1955
|
engine = _Engine(True)
|
|
1862
|
-
|
|
1956
|
+
built = engine._build_module()
|
|
1957
|
+
assert built.kwargs == {"use_reentrant": True}
|
|
1958
|
+
assert built.input_grads is True
|
|
1863
1959
|
# checkpointing off -> untouched, so the shim cannot silently raise the memory profile
|
|
1864
1960
|
off = _Engine(False)
|
|
1865
|
-
|
|
1961
|
+
off_built = off._build_module()
|
|
1962
|
+
assert off_built.kwargs is None
|
|
1963
|
+
assert off_built.input_grads is False
|
|
1866
1964
|
finally:
|
|
1867
1965
|
for name, value in saved.items():
|
|
1868
1966
|
if value is None:
|
|
@@ -5,15 +5,18 @@ from __future__ import annotations
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import importlib.util
|
|
7
7
|
import os
|
|
8
|
+
import re
|
|
8
9
|
import sys
|
|
9
10
|
import types
|
|
10
11
|
from types import SimpleNamespace
|
|
11
12
|
|
|
12
13
|
import pytest
|
|
13
14
|
|
|
15
|
+
from flash.engine.worker.backend_common import parse_verl_metric
|
|
14
16
|
from flash.engine.worker.sft import _pretokenize_completion_only
|
|
15
17
|
from flash.engine.worker.sft_train import (
|
|
16
18
|
_LORAPLUS_READY_MARKER,
|
|
19
|
+
_MAX_ZERO_GRAD_STEPS,
|
|
17
20
|
_VERL_OPTIMIZER_IMPL,
|
|
18
21
|
_VERL_OPTIMIZER_NAME,
|
|
19
22
|
_build_verl_child_env,
|
|
@@ -478,6 +481,115 @@ def test_generated_sitecustomize_installs_linear_scheduler_and_required_loraplus
|
|
|
478
481
|
assert scheduler_calls == [("optimizer", {"num_warmup_steps": 2, "num_training_steps": 20})]
|
|
479
482
|
|
|
480
483
|
|
|
484
|
+
def test_reentrant_checkpointing_enables_input_grads_before_enabling_checkpointing():
|
|
485
|
+
"""GRAD-001: lora freezes the embeddings, so nothing entering the first checkpointed layer
|
|
486
|
+
requires grad and reentrant checkpointing returns no gradient at all. the shim must call
|
|
487
|
+
enable_input_require_grads() BEFORE gradient_checkpointing_enable(), or every sft run
|
|
488
|
+
trains nothing while reporting done and billing."""
|
|
489
|
+
calls = []
|
|
490
|
+
|
|
491
|
+
class FakeModule:
|
|
492
|
+
def enable_input_require_grads(self):
|
|
493
|
+
calls.append("require_grads")
|
|
494
|
+
|
|
495
|
+
def gradient_checkpointing_enable(self, **kwargs):
|
|
496
|
+
calls.append(("gc_enable", kwargs))
|
|
497
|
+
|
|
498
|
+
class FakeEngine:
|
|
499
|
+
def _build_module(self):
|
|
500
|
+
return FakeModule()
|
|
501
|
+
|
|
502
|
+
source = _render_sft_sitecustomize(
|
|
503
|
+
seed=1,
|
|
504
|
+
loraplus_ratio=16,
|
|
505
|
+
save_at_steps=(),
|
|
506
|
+
total_steps=4,
|
|
507
|
+
reentrant_gradient_checkpointing=True,
|
|
508
|
+
)
|
|
509
|
+
# execute only the reentrant block: the surrounding shim imports verl/torch at module scope.
|
|
510
|
+
block = source[source.index("def _flash_build_reentrant_module") :]
|
|
511
|
+
block = block[: block.index("_FlashFSDPEngine._build_module = _flash_build_reentrant_module")]
|
|
512
|
+
namespace = {"_flash_original_build_module": FakeEngine._build_module}
|
|
513
|
+
exec(compile(block, "shim.py", "exec"), namespace)
|
|
514
|
+
|
|
515
|
+
namespace["_flash_build_reentrant_module"](FakeEngine())
|
|
516
|
+
|
|
517
|
+
# order matters: enabling checkpointing first would capture the graph before any input
|
|
518
|
+
# requires grad, so asserting mere presence would pass on a broken shim.
|
|
519
|
+
assert calls[0] == "require_grads"
|
|
520
|
+
assert calls[1] == ("gc_enable", {"gradient_checkpointing_kwargs": {"use_reentrant": True}})
|
|
521
|
+
|
|
522
|
+
# the non-reentrant path never patches _build_module at all, so it must not appear.
|
|
523
|
+
non_reentrant = _render_sft_sitecustomize(
|
|
524
|
+
seed=1,
|
|
525
|
+
loraplus_ratio=16,
|
|
526
|
+
save_at_steps=(),
|
|
527
|
+
total_steps=4,
|
|
528
|
+
reentrant_gradient_checkpointing=False,
|
|
529
|
+
)
|
|
530
|
+
assert "enable_input_require_grads" not in non_reentrant
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def test_zero_grad_norm_at_nonzero_lr_fails_the_run():
|
|
534
|
+
"""GRAD-001: four runs reported done and charged while grad_norm was 0.0 on every step.
|
|
535
|
+
the number was parsed and recorded, never read. replay the real g4 log lines."""
|
|
536
|
+
|
|
537
|
+
def replay(lines):
|
|
538
|
+
zero_grad_steps: list[int] = []
|
|
539
|
+
for step, line in enumerate(lines):
|
|
540
|
+
grad_norm = parse_verl_metric(line, "train/grad_norm")
|
|
541
|
+
learning_rate_value = parse_verl_metric(line, "train/lr")
|
|
542
|
+
if grad_norm is None:
|
|
543
|
+
continue
|
|
544
|
+
if grad_norm == 0.0 and (learning_rate_value is None or learning_rate_value > 0.0):
|
|
545
|
+
zero_grad_steps.append(step)
|
|
546
|
+
if len(zero_grad_steps) >= _MAX_ZERO_GRAD_STEPS:
|
|
547
|
+
raise RuntimeError(
|
|
548
|
+
"verl reported train/grad_norm=0.0 with a nonzero learning rate on "
|
|
549
|
+
f"{len(zero_grad_steps)} consecutive steps: no gradient is reaching "
|
|
550
|
+
"the lora parameters, so this run would train nothing. see GRAD-001"
|
|
551
|
+
)
|
|
552
|
+
else:
|
|
553
|
+
zero_grad_steps.clear()
|
|
554
|
+
|
|
555
|
+
# verbatim shape of the g4 gsm8k lines (flash-1785592071-e56cf3c6): loss barely moves on a
|
|
556
|
+
# replayed identical batch because nothing is learning.
|
|
557
|
+
broken = [
|
|
558
|
+
"step:1 - train/loss:0.5470 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
559
|
+
"step:2 - train/loss:0.5437 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
560
|
+
"step:3 - train/loss:0.5474 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
561
|
+
"step:4 - train/loss:0.5444 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
562
|
+
]
|
|
563
|
+
with pytest.raises(RuntimeError, match=re.escape("grad_norm=0.0")):
|
|
564
|
+
replay(broken)
|
|
565
|
+
|
|
566
|
+
# a healthy run must not trip the guard.
|
|
567
|
+
replay(
|
|
568
|
+
[
|
|
569
|
+
"step:1 - train/loss:0.9 - train/grad_norm:1.4 - train/lr:0.0001",
|
|
570
|
+
"step:2 - train/loss:0.7 - train/grad_norm:0.9 - train/lr:0.0001",
|
|
571
|
+
]
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
# an isolated zero is a legitimately fully-masked micro-batch, not a severed graph.
|
|
575
|
+
replay(
|
|
576
|
+
[
|
|
577
|
+
"step:1 - train/loss:0.9 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
578
|
+
"step:2 - train/loss:0.7 - train/grad_norm:1.1 - train/lr:0.0001",
|
|
579
|
+
"step:3 - train/loss:0.6 - train/grad_norm:0.0 - train/lr:0.0001",
|
|
580
|
+
]
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# a decayed schedule reaching lr 0.0 produces a legitimate zero grad norm.
|
|
584
|
+
replay(
|
|
585
|
+
[
|
|
586
|
+
"step:1 - train/loss:0.5 - train/grad_norm:0.0 - train/lr:0.0",
|
|
587
|
+
"step:2 - train/loss:0.5 - train/grad_norm:0.0 - train/lr:0.0",
|
|
588
|
+
"step:3 - train/loss:0.5 - train/grad_norm:0.0 - train/lr:0.0",
|
|
589
|
+
]
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
|
|
481
593
|
def test_loraplus_shim_has_no_plain_lora_fallback():
|
|
482
594
|
source = render_loraplus_shim(16)
|
|
483
595
|
assert _LORAPLUS_READY_MARKER in source
|
|
@@ -615,7 +727,11 @@ def test_resume_credits_only_required_saves_that_are_durable(monkeypatch):
|
|
|
615
727
|
assert sft_train._durable_required_save_steps((3, 5, 9), 5) == {3}
|
|
616
728
|
|
|
617
729
|
|
|
618
|
-
def
|
|
730
|
+
def _stub_sft_run(monkeypatch, *, save_at_steps=(), watcher_cls=None):
|
|
731
|
+
"""monkeypatch every out-of-process dependency of run_sft_train and return (spec, captured).
|
|
732
|
+
|
|
733
|
+
the caller supplies its own ``run_verl_training`` fake, which is the only remaining seam.
|
|
734
|
+
"""
|
|
619
735
|
import flash.engine.worker as worker
|
|
620
736
|
from flash.engine.worker import sft_train
|
|
621
737
|
|
|
@@ -630,7 +746,7 @@ def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypa
|
|
|
630
746
|
max_context_tokens=1024,
|
|
631
747
|
max_examples=2,
|
|
632
748
|
max_steps=2,
|
|
633
|
-
save_at_steps=
|
|
749
|
+
save_at_steps=save_at_steps,
|
|
634
750
|
save_every=50,
|
|
635
751
|
init_from_adapter="",
|
|
636
752
|
),
|
|
@@ -683,7 +799,7 @@ def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypa
|
|
|
683
799
|
def stop_gb(self):
|
|
684
800
|
return 12.5
|
|
685
801
|
|
|
686
|
-
class
|
|
802
|
+
class _DefaultWatcher:
|
|
687
803
|
def __init__(self, **kwargs):
|
|
688
804
|
self.processed_steps = set()
|
|
689
805
|
|
|
@@ -696,7 +812,25 @@ def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypa
|
|
|
696
812
|
def raise_if_failed(self):
|
|
697
813
|
return None
|
|
698
814
|
|
|
815
|
+
Watcher = watcher_cls or _DefaultWatcher
|
|
816
|
+
|
|
699
817
|
captured = {"heartbeats": [], "published": [], "uploads": []}
|
|
818
|
+
# run_sft_train imports AutoProcessor at data-loading time and transformers is not installed in
|
|
819
|
+
# the cpu test env. this used to pass only because some EARLIER test module left a transformers
|
|
820
|
+
# stub in sys.modules, so running this file alone failed -- stub it here so the test stands on
|
|
821
|
+
# its own. monkeypatch.setitem restores whatever was there (real module or nothing) afterwards.
|
|
822
|
+
monkeypatch.setitem(
|
|
823
|
+
sys.modules,
|
|
824
|
+
"transformers",
|
|
825
|
+
sys.modules.get("transformers")
|
|
826
|
+
or _module(
|
|
827
|
+
"transformers",
|
|
828
|
+
AutoProcessor=SimpleNamespace(from_pretrained=lambda *a, **k: None),
|
|
829
|
+
# datasets' dill serializer issubclass()-checks against this while writing the
|
|
830
|
+
# parquet, so it has to be a real class rather than a namespace attribute.
|
|
831
|
+
PreTrainedTokenizerBase=type("PreTrainedTokenizerBase", (), {}),
|
|
832
|
+
),
|
|
833
|
+
)
|
|
700
834
|
monkeypatch.delenv("WANDB_API_KEY", raising=False)
|
|
701
835
|
monkeypatch.setattr(worker, "SEED", 7)
|
|
702
836
|
monkeypatch.setattr(worker, "RUN_ID", "test-sft-verl-orchestration")
|
|
@@ -765,6 +899,14 @@ def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypa
|
|
|
765
899
|
|
|
766
900
|
monkeypatch.setattr(sft_train, "_export_checkpoint_adapter", fake_export)
|
|
767
901
|
|
|
902
|
+
return spec, captured
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypatch):
|
|
906
|
+
from flash.engine.worker import sft_train
|
|
907
|
+
|
|
908
|
+
spec, captured = _stub_sft_run(monkeypatch)
|
|
909
|
+
|
|
768
910
|
def fake_training(command, *, env, on_step, on_line, heartbeat):
|
|
769
911
|
captured["command"] = command
|
|
770
912
|
captured["child_env"] = env
|
|
@@ -798,6 +940,61 @@ def test_run_sft_train_orchestrates_exact_dataset_and_resume_accounting(monkeypa
|
|
|
798
940
|
assert captured["meta"]["notes"]["realized_max_length"] > 0
|
|
799
941
|
|
|
800
942
|
|
|
943
|
+
def test_a_guard_failure_is_not_replaced_by_the_watcher_completeness_error(monkeypatch):
|
|
944
|
+
"""the zero-grad diagnosis must survive the finally block, not be overwritten by it.
|
|
945
|
+
|
|
946
|
+
an on_line guard raises from INSIDE run_verl_training, so return_code is never assigned and
|
|
947
|
+
keeps its initial 0. deriving require_complete from it would then demand every save_at_steps
|
|
948
|
+
entry from a run that died at step 2, and the watcher's "required saves were not durably
|
|
949
|
+
published" would unwind out of the finally in place of the real cause -- turning the one
|
|
950
|
+
error GRAD-001 exists to surface into a checkpointing red herring.
|
|
951
|
+
"""
|
|
952
|
+
from flash.engine.worker import sft_train
|
|
953
|
+
|
|
954
|
+
stopped: list[bool] = []
|
|
955
|
+
|
|
956
|
+
class Watcher:
|
|
957
|
+
def __init__(self, **kwargs):
|
|
958
|
+
self.processed_steps = set()
|
|
959
|
+
self.required_steps = frozenset(kwargs.get("required_steps", ()))
|
|
960
|
+
|
|
961
|
+
def start(self):
|
|
962
|
+
return None
|
|
963
|
+
|
|
964
|
+
def raise_if_failed(self):
|
|
965
|
+
return None
|
|
966
|
+
|
|
967
|
+
def stop(self, *, require_complete):
|
|
968
|
+
stopped.append(require_complete)
|
|
969
|
+
if require_complete:
|
|
970
|
+
missing = sorted(self.required_steps - self.processed_steps)
|
|
971
|
+
if missing:
|
|
972
|
+
raise RuntimeError(f"required saves were not durably published: {missing}")
|
|
973
|
+
|
|
974
|
+
# a required save the run never durably publishes: the guard raises on the same step, before
|
|
975
|
+
# the watcher has processed it. (the step is inside the 2-update horizon because
|
|
976
|
+
# validate_save_steps rejects anything beyond it at config time.)
|
|
977
|
+
spec, _ = _stub_sft_run(monkeypatch, save_at_steps=(2,), watcher_cls=Watcher)
|
|
978
|
+
|
|
979
|
+
def fake_training(command, *, env, on_step, on_line, heartbeat):
|
|
980
|
+
on_line(f"{_LORAPLUS_READY_MARKER} ratio=16 optimizer=AdamW\n")
|
|
981
|
+
for step in range(1, _MAX_ZERO_GRAD_STEPS + 1):
|
|
982
|
+
on_line(
|
|
983
|
+
f"step:{step} - train/loss:1.0 - train/grad_norm:0.0 - train/lr:5e-05 "
|
|
984
|
+
"- train/global_tokens:8\n"
|
|
985
|
+
)
|
|
986
|
+
raise AssertionError("the zero-grad guard should have stopped the run before this")
|
|
987
|
+
|
|
988
|
+
monkeypatch.setattr(sft_train, "run_verl_training", fake_training)
|
|
989
|
+
|
|
990
|
+
with pytest.raises(RuntimeError, match=re.escape("grad_norm=0.0")):
|
|
991
|
+
sft_train.run_sft_train(spec)
|
|
992
|
+
|
|
993
|
+
# the watcher still gets stopped -- it just is not asked to prove completeness for a run that
|
|
994
|
+
# never finished. without this, stop() raises and the grad_norm error never reaches the caller.
|
|
995
|
+
assert stopped == [False]
|
|
996
|
+
|
|
997
|
+
|
|
801
998
|
def test_overrides_enable_fused_linear_ce_for_long_context():
|
|
802
999
|
# 32k contexts must not materialize [tokens, vocab] logits; the fused torch-backend
|
|
803
1000
|
# linear-CE computes loss from hidden states in chunks (numerically exact CE).
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/ISSUE_TEMPLATE/bug_report.yml
RENAMED
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/ISSUE_TEMPLATE/feature_request.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/bake-kernel-cache.yml
RENAMED
|
File without changes
|
|
File without changes
|
{freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/main-source-guard.yml
RENAMED
|
File without changes
|
{freesolo_flash_dev-1.0.63 → freesolo_flash_dev-1.0.65}/.github/workflows/notify-tests-repo.yml
RENAMED
|
File without changes
|
|
File without changes
|