2026-07-10 00:22:50 +08:00
# ModelHub Submission Runner
2026-07-10 01:44:16 +08:00
This package automates ModelScope model discovery and ModelHub submission.
2026-07-10 00:22:50 +08:00
It currently supports:
- one-shot submission planning via `main.py`
- daily batch execution via `run_daily.sh`
- continuous queue refill via `run_poll.sh`
2026-07-10 02:02:08 +08:00
- multiple ModelHub tokens read from `KEY.md` and `KEYS.md`
2026-07-10 00:22:50 +08:00
- automatic task/framework/template selection across the supported GPU catalog
2026-08-05 18:21:59 +08:00
- adaptive long-term/recent GPU exploitation with a persistent local snapshot
2026-08-04 20:22:08 +08:00
- live queue/throughput-aware GPU weighting and confidence-ranked framework selection
2026-07-10 00:22:50 +08:00
## Layout
- `main.py` : core discovery, scoring, dedup, and submission
- `daily_runner.py` : daily wave orchestration
- `poll_runner.py` : long-running queue refiller
2026-08-12 08:19:53 +08:00
- `queue_cleanup.py` : fail-closed cleanup for certain OOM, architecture, and age policies
2026-07-10 00:22:50 +08:00
- `runner_common.py` : shared token / key file loading
2026-07-10 02:02:08 +08:00
- `hf_discovery.py` : ModelScope model discovery and inspection (keeps the legacy module name)
- `modelhub_client.py` : ModelHub API client and token-pool routing
2026-07-10 00:22:50 +08:00
- `history_stats.py` : online history aggregation, ranking, and warnings
2026-08-11 00:59:40 +08:00
- `candidate_preflight.py` : deterministic repository, memory, context, and compatibility gates
2026-08-10 21:44:42 +08:00
- `failure_taxonomy.py` : deterministic/platform/semantic failure routing
2026-08-12 08:02:51 +08:00
- `architecture_compatibility.py` : exact architecture identities and learned compatibility keys
2026-08-11 00:59:40 +08:00
- `llm_classifier.py` : offline-only experimental ambiguity-analysis helper
2026-07-10 00:22:50 +08:00
- `template_selector.py` : template lookup and GPU normalization
- `task_registry.py` : task-type and framework selection rules
- `tests/` : unit tests and regression coverage
## Key Files
2026-07-10 02:02:08 +08:00
- `KEY.md` : primary ModelScope and ModelHub tokens
- `KEYS.md` : optional supplemental ModelHub tokens
2026-07-10 00:22:50 +08:00
- `templates/public_submit/adapt_task_templates.jsonl` : public submit templates
2026-07-10 02:02:08 +08:00
The runner reads both files automatically. Add more accounts by appending
`XC_TOKEN3` , `XC_TOKEN4` , and so on to `KEYS.md` .
2026-07-10 00:22:50 +08:00
Template lookup is also relative. The selector searches from the current working
directory and the module directory. The primary project layout is:
- `templates/public_submit/adapt_task_templates.jsonl`
It still accepts the legacy fallback path below for compatibility with older
deployments:
- `model adaptation/templates/public_submit/adapt_task_templates.jsonl`
If your Space keeps templates in another location, set `MODELHUB_TEMPLATE_FILE`
to the exact JSONL path.
## Quick Start
Run a single daily batch:
```bash
cd /path/to/submmit
# testing: one run defaults to 3 targets if daily-target is not specified
bash run_daily.sh --rounds 1
```
Run the continuous queue refiller:
```bash
cd /path/to/submmit
bash run_poll.sh
```
Dry-run either entrypoint to inspect candidate selection without submitting:
```bash
cd /path/to/submmit
bash run_daily.sh --dry-run
bash run_poll.sh --dry-run
```
## Behavior
- The runner auto-discovers all safe GPU/template combinations from the public submit catalog.
2026-08-05 18:21:59 +08:00
- Automatic GPU selection uses exact 70/30 accepted-task scheduling: long-term
Wilson-ranked top 3 GPUs and the top GPUs from the latest 1,000 terminal tasks.
There is no all-GPU exploration category.
2026-08-04 20:22:08 +08:00
- Within each category, weighted-fair scheduling uses estimated queue backlog hours,
recent public throughput/success, machine availability, and worker concurrency.
Unavailable or stalled GPU pools are circuit-broken instead of continuing to absorb work.
- Compatible frameworks are ranked by ModelHub public aggregate success statistics
2026-08-05 18:21:59 +08:00
plus capped local GPU+framework evidence, with a 300-sample public minimum and
Wilson confidence bounds. Missing or undersized public evidence receives zero
traffic rather than falling back to exploration.
2026-08-04 20:22:08 +08:00
- New frameworks are discovered from the live catalog but get no novelty bonus.
They are eligible only with a complete official build config that passes local
2026-08-05 18:21:59 +08:00
validation and a confidence score at least 10% above the best incumbent.
- Five consecutive local failures pause a GPU/framework pair for 12 hours; a
sub-20% rate over the latest 20 terminal tasks pauses it for 6 hours.
2026-08-12 08:02:51 +08:00
- An explicit "framework does not support this model/architecture" failure learns
a 30-day GPU + framework + task + architecture block. Architecture identity
2026-08-12 08:19:53 +08:00
comes from candidate `config.json` plus exact unsupported `model_type` or
`architectures` strings in the runtime log, never from repository names. A newer success clears the block, and
2026-08-12 08:02:51 +08:00
generic unsupported backend/operator messages cannot create one.
2026-08-12 08:19:53 +08:00
- Blacklist additions are persisted and detected every three poll cycles. A new
rule immediately launches a lightweight architecture-only queue scan. Exact
matching waiting tasks are stopped after two state checks; running tasks and
tasks without local framework/task metadata are protected.
2026-08-02 16:59:44 +08:00
- A strategy generation lasts exactly 200 platform-accepted submissions. Rejected API calls and
duplicates do not advance it. The next cycle refreshes platform history before submitting again.
- Strategy state is stored in `.modelhub_state/gpu_strategy.json` ; a generation never recalculates
during candidate submission.
2026-08-02 17:45:21 +08:00
- Candidate discovery starts with the configured recent window, then automatically expands to
7 days, 30 days, and older history (up to 3,000 models) when the recent pool is exhausted.
- Model verification responses are cached across poll cycles for 15 minutes. Local model/GPU
failures cool down after 24 hours instead of remaining permanently blocked.
2026-08-02 18:48:47 +08:00
- Community deduplication is model/GPU-specific: another GPU's adaptation does not block the
current GPU. Every actual submission performs a fresh uncached check for its exact GPU.
- If the community lookup is unavailable, submission is deferred. A platform model-uniqueness
rejection permanently excludes only that model/GPU combination from future local retries.
2026-07-10 00:22:50 +08:00
- Each model can be submitted at most once per GPU.
2026-07-10 02:02:08 +08:00
- Multiple ModelHub tokens are pooled and used to route submissions to the account with available async capacity.
2026-08-01 16:50:50 +08:00
- Concurrent submissions reserve account slots locally, and an account-capacity race automatically falls through to another account.
- Concurrent local processes claim model/GPU pairs in `.modelhub_state/submission_claims.jsonl` ; shared ledger, history, and outcome files use process locks and atomic replacement.
2026-08-02 16:59:44 +08:00
- ModelScope list pages are paced and cached for 15 minutes. HTTP 429 responses use exponential
backoff and `Retry-After` ; pages already downloaded remain usable and the failed page is retried
on the next cycle.
- Every third poll cycle, a full account gets one controlled capacity probe. A successful probe
raises that account's persisted known limit; a capacity rejection enters cooldown.
2026-08-02 17:45:21 +08:00
- Each `[scan]` log records the discovery stage and candidate yield. The final `[daily] wave_done`
log includes `skip_reasons` , making empty candidate pools distinguishable from API failures.
2026-08-11 00:52:16 +08:00
- At startup and every 120 poll cycles, active tasks are checked with the same recursive-size
memory rule as new submissions. Only tasks whose own repository size times `1.20` exceeds
their selected GPU capacity are stopped, after a fresh account-scoped active-state check.
Incomplete size/capacity evidence is never used for cancellation.
2026-08-11 01:41:26 +08:00
- Models older than seven days may occupy only the current account capacity minus its final 10
positions. The account pool enforces this per-account boundary atomically and updates it when
capacity probing discovers a higher limit. Cleanup stops OOM tasks first, recalculates the
surviving queue order, and applies the same limit-minus-10 boundary on startup. Scheduled
2026-08-12 01:04:34 +08:00
cleanup relaxes to limit minus 5 to avoid excessive pruning. Age cleanup stops waiting tasks
only; running tasks are protected and rechecked after OOM cleanup, immediately before the
age-only stop batch. Recent
overflow tasks stay, and unknown ModelScope timestamps never authorize a cancellation.
2026-07-10 00:22:50 +08:00
## Important Flags
Common flags:
- `--daily-target` : total target submissions for the day; `0` means unlimited
2026-07-10 01:44:16 +08:00
- `--min-downloads` : ModelScope download floor
2026-07-10 00:22:50 +08:00
- `--history-stats-threshold` : local ledger threshold before using online history stats
2026-07-10 02:02:08 +08:00
- `--max-scan-models` : hard cap on scanned HF models for a run (0 = auto)
2026-07-10 00:22:50 +08:00
- `--scan-multiplier` : multiplier used for auto scan cap derivation from quota/queue capacity
- `--read-concurrency` : concurrent HTTP reads while scanning model candidates (default 4)
- `--max-submits-per-run` : max tasks to submit per run cycle (0 = unlimited)
- `--submit-concurrency` : concurrent task submissions (default auto, uses 0)
- `--skip-outcome-sync` : skip outcome sync before scanning
- `--skip-history-archive` : skip history archive download for this run
- `--dry-run` : plan only, do not submit
2026-08-02 16:59:44 +08:00
- `--gpu-strategy-refresh-submissions` : accepted tasks per strategy generation (default `200` )
- `--disable-gpu-strategy` : restore legacy ordering; explicit `--gpu/--gpus` also bypasses adaptive selection
2026-08-04 20:22:08 +08:00
- `--disable-market-intelligence` : disable live queue/throughput and framework-stat weighting
2026-07-10 00:22:50 +08:00
- `run_daily.sh` injects `--daily-target 3` when no daily-target flag is provided. Set `SUBMIT_DAILY_TARGET` or pass `--daily-target` explicitly for a different target.
`run_poll.sh` adds:
2026-08-01 16:50:50 +08:00
- `--poll-interval-seconds` : sleep when all accounts are saturated (default 15)
- `--idle-interval-seconds` : sleep when a cycle submits nothing (default 60)
2026-07-10 02:02:08 +08:00
- `--max-scan-models` : hard cap on scanned HF models for this cycle (0 = auto)
2026-07-10 00:22:50 +08:00
- `--scan-multiplier` : multiplier used for auto scan cap derivation from quota/queue capacity
- `--max-submits-per-run` : max tasks to submit per poll cycle (0 = unlimited)
- `--skip-outcome-sync` : skip outcome sync before scanning
- `--skip-history-archive` : skip history archive download for this cycle
- `--submit-concurrency` : concurrent task submission calls used by each cycle (0 = auto)
2026-08-01 16:50:50 +08:00
- `--post-cycle-cooldown-seconds` : pause after a successful cycle before next cycle (default 2)
2026-07-10 00:22:50 +08:00
- `--max-cycles` : optional hard stop for testing or batch windows
2026-08-11 01:29:54 +08:00
- `--disable-queue-cleanup` : disable automatic OOM and old-overflow queue cleanup
2026-08-11 01:41:26 +08:00
The first automatic cleanup removes models older than seven days beyond each
account's discovered capacity minus 10. Later scheduled cleanups use capacity
minus 5, while admission continues to reserve the final 10 slots for recent
models. Override these suffix sizes with `MODELHUB_RECENT_MODEL_RESERVE_SLOTS`
and `MODELHUB_DYNAMIC_OLD_MODEL_CLEANUP_RESERVE_SLOTS` .
2026-07-10 00:22:50 +08:00
2026-08-12 01:04:34 +08:00
Every successful worker-initiated stop is persisted as `policy_cancelled` in the
outcome store. It is excluded from GPU/framework success rates, local failure
cooldowns, and circuit breakers. If a task races to a real success before the
stop takes effect, that success remains authoritative.
2026-08-10 21:44:42 +08:00
Failure-informed preflight is enabled by default. It rejects deterministic
missing-file and predicted-OOM cases, clamps unsafe context-length arguments,
and records its decisions in `candidatePreflight` and each candidate's
`preflightMetadata` . Use `--disable-candidate-preflight` only for diagnosis.
The memory gate totals the complete recursive repository and applies the same
20% overhead observed in ModelHub `PREFLIGHT_OOM` reports. All 14 currently
verifiable GPU types have evidence-backed capacities; an incomplete repository
size is deferred instead of estimated. See `../docs/gpu-memory-capacity-2026-08-10.md` .
2026-08-11 00:59:40 +08:00
The online runner never constructs an LLM client. A DashScope key or any
`MODELHUB_QWEN_*` /`MODELHUB_LLM_CLASSIFIER_*` environment variable cannot enable
inference. `llm_classifier.py` remains available only for deliberately invoked,
offline experiments whose output is reviewed before being converted into a
deterministic rule.
2026-08-10 21:44:42 +08:00
Outcome sync also classifies a bounded set of this worker's failed-task ZIP logs.
2026-08-11 00:59:40 +08:00
Hard error signatures run first; ambiguous runtime roots remain explicitly
unclassified and are never sent to an LLM. Platform faults are excluded from
long-term compatibility scores and use a short 30-minute breaker after three
consecutive failures. Failed log downloads are persisted and stop after three
attempts.
2026-08-10 21:44:42 +08:00
2026-07-10 00:22:50 +08:00
## Output
Run artifacts are written under:
- `runs/` : one-shot submission runs
- `daily_runs/` : batch orchestration runs
- `poll_runs/` : poller cycles
Each run typically includes:
- `summary.json`
- `pre_submit_report.json`
- `candidates.jsonl`
- `submitted.jsonl`
- `skipped.jsonl`
- `failed.jsonl`
2026-08-02 16:59:44 +08:00
Persistent local scheduler state is written under `.modelhub_state/` :
2026-08-05 18:21:59 +08:00
- `gpu_strategy.json` : GPU ranks, generation progress, and 70/30 accepted counters
2026-08-04 20:22:08 +08:00
- `market_intelligence.json` : cached public queue, throughput, health, and framework statistics
2026-08-02 16:59:44 +08:00
- `account_capacity.json` : learned per-account active-task limits
2026-08-02 18:48:47 +08:00
- `submission_exclusions.jsonl` : non-retryable model/GPU uniqueness rejections
2026-08-11 00:52:16 +08:00
- `queue_cleanup_latest.json` : latest active-task sizing evidence and cancellation result
2026-08-12 08:19:53 +08:00
- `architecture_compatibility_blacklist.json` : current dynamic compatibility blocks and evidence
2026-08-02 16:59:44 +08:00
2026-07-10 00:22:50 +08:00
## Verification
Run the full test suite:
```bash
cd /path/to/submmit
python3 -m unittest discover -s tests -v
```
## Notes
- This is a submission automation tool, not a scheduler daemon. Use `screen` , `tmux` ,
`nohup` , or `systemd` if you want it to keep running in the background.
- The platform still enforces per-account async capacity limits, so the poller can
keep the queue close to full but cannot override the platform cap.
- `bash run_poll.sh` now defaults to unlimited mode and keeps refilling until you stop the process manually.
2026-08-01 16:50:50 +08:00
- Queue polling defaults to 15 seconds, successful-cycle cooldown to 2 seconds,
and per-cycle submissions to all available slots. Override these values when
the platform requires a lower request rate.