Veto repeated materialized configs
This commit is contained in:
@@ -109,6 +109,9 @@ declarative intervention grammar + coverage-relative validator。
|
|||||||
- normalized full-config signature:no-repeat 不能只看 patch signature;base config 与
|
- normalized full-config signature:no-repeat 不能只看 patch signature;base config 与
|
||||||
no-op patch 必须被识别为同一 full config;`48911b6` 已实现并在 dash1 bad-start
|
no-op patch 必须被识别为同一 full config;`48911b6` 已实现并在 dash1 bad-start
|
||||||
validation 中通过;
|
validation 中通过;
|
||||||
|
- materialized effective signature:runtime-only proposal 必须先按真实执行路径继承
|
||||||
|
incumbent topology,再做 no-repeat;已加入 shared signature/canonicalization,并在
|
||||||
|
CLI 进入 trial 前 hard-veto 重复 LLM/manual/harness proposal;
|
||||||
- Failure invalidation 有保守 region predicate 和 retry/unblock 条件;
|
- Failure invalidation 有保守 region predicate 和 retry/unblock 条件;
|
||||||
- grammar/policy/capability 都有 version 和 anti-overfitting static checks;
|
- grammar/policy/capability 都有 version 和 anti-overfitting static checks;
|
||||||
- LLM/BO 只能选择合法 candidate,不能绕过 validator。
|
- LLM/BO 只能选择合法 candidate,不能绕过 validator。
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ from dataclasses import replace
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .compare import run_compare
|
from .compare import run_compare
|
||||||
|
from .config_signature import (
|
||||||
|
materialized_effective_config_signature,
|
||||||
|
tested_config_signature_index,
|
||||||
|
)
|
||||||
from .harness import (
|
from .harness import (
|
||||||
build_harness_context,
|
build_harness_context,
|
||||||
build_harness_guided_proposal,
|
build_harness_guided_proposal,
|
||||||
@@ -24,6 +28,7 @@ from .spec import (
|
|||||||
Proposal,
|
Proposal,
|
||||||
SpecError,
|
SpecError,
|
||||||
StudySpec,
|
StudySpec,
|
||||||
|
StudyState,
|
||||||
load_structured_file,
|
load_structured_file,
|
||||||
load_study_spec,
|
load_study_spec,
|
||||||
to_jsonable,
|
to_jsonable,
|
||||||
@@ -37,6 +42,32 @@ def _is_empty_config_patch(proposal: Proposal) -> bool:
|
|||||||
return not proposal.config_patch.env_patch and not proposal.config_patch.flag_patch
|
return not proposal.config_patch.env_patch and not proposal.config_patch.flag_patch
|
||||||
|
|
||||||
|
|
||||||
|
def _reject_repeated_effective_config(
|
||||||
|
*,
|
||||||
|
study: StudySpec,
|
||||||
|
state: StudyState,
|
||||||
|
proposal: Proposal,
|
||||||
|
proposal_name: str,
|
||||||
|
) -> None:
|
||||||
|
if proposal.should_stop:
|
||||||
|
return
|
||||||
|
tested = tested_config_signature_index(study, state)
|
||||||
|
signature = materialized_effective_config_signature(
|
||||||
|
study=study,
|
||||||
|
state=state,
|
||||||
|
proposal=proposal,
|
||||||
|
)
|
||||||
|
matching_trials = tested.get(signature)
|
||||||
|
if not matching_trials:
|
||||||
|
return
|
||||||
|
raise SpecError(
|
||||||
|
f"Proposal {proposal_name} repeats an already tested effective full config "
|
||||||
|
"after materialization. "
|
||||||
|
f"matching_trial_ids={matching_trials}. "
|
||||||
|
"Choose a different eligible candidate or return should_stop=true."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _latency_percentiles(summary: object, metric: str) -> dict[str, float]:
|
def _latency_percentiles(summary: object, metric: str) -> dict[str, float]:
|
||||||
if not isinstance(summary, dict):
|
if not isinstance(summary, dict):
|
||||||
return {}
|
return {}
|
||||||
@@ -334,6 +365,12 @@ def cmd_study_tune(args: argparse.Namespace) -> int:
|
|||||||
raw_proposal_path = store.study_root(study.study_id) / "proposals" / f"{proposal_name}.raw.txt"
|
raw_proposal_path = store.study_root(study.study_id) / "proposals" / f"{proposal_name}.raw.txt"
|
||||||
raw_proposal_path.write_text(proposal_text, encoding="utf-8")
|
raw_proposal_path.write_text(proposal_text, encoding="utf-8")
|
||||||
proposal = parse_proposal_text(proposal_text, study)
|
proposal = parse_proposal_text(proposal_text, study)
|
||||||
|
_reject_repeated_effective_config(
|
||||||
|
study=study,
|
||||||
|
state=state,
|
||||||
|
proposal=proposal,
|
||||||
|
proposal_name=proposal_name,
|
||||||
|
)
|
||||||
store.write_proposal(study.study_id, proposal_name, proposal)
|
store.write_proposal(study.study_id, proposal_name, proposal)
|
||||||
if proposal.should_stop:
|
if proposal.should_stop:
|
||||||
is_harness_stop = proposal_name.startswith("harness-stop-")
|
is_harness_stop = proposal_name.startswith("harness-stop-")
|
||||||
|
|||||||
148
src/aituner/config_signature.py
Normal file
148
src/aituner/config_signature.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
from dataclasses import replace
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from .spec import ConfigPatch, Proposal, StudySpec, StudyState
|
||||||
|
|
||||||
|
|
||||||
|
TOPOLOGY_FLAG_KEYS = {
|
||||||
|
"tensor-parallel-size",
|
||||||
|
"data-parallel-size",
|
||||||
|
"expert-parallel-size",
|
||||||
|
"enable-expert-parallel",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def normalized_config_patch(config_patch: Any) -> dict[str, dict[str, Any]]:
|
||||||
|
if isinstance(config_patch, ConfigPatch):
|
||||||
|
env_patch: Any = config_patch.env_patch
|
||||||
|
flag_patch: Any = config_patch.flag_patch
|
||||||
|
elif isinstance(config_patch, dict):
|
||||||
|
env_patch = config_patch.get("env_patch")
|
||||||
|
flag_patch = config_patch.get("flag_patch")
|
||||||
|
else:
|
||||||
|
env_patch = {}
|
||||||
|
flag_patch = {}
|
||||||
|
return {
|
||||||
|
"env_patch": _canonical_env_map(env_patch if isinstance(env_patch, dict) else {}),
|
||||||
|
"flag_patch": _canonical_flag_map(flag_patch if isinstance(flag_patch, dict) else {}),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def effective_config_signature(study: StudySpec, config_patch: Any) -> str:
|
||||||
|
patch = normalized_config_patch(config_patch)
|
||||||
|
payload = {
|
||||||
|
"env": _canonical_env_map({**study.engine.base_envs, **patch["env_patch"]}),
|
||||||
|
"flags": _canonical_flag_map({**study.engine.base_flags, **patch["flag_patch"]}),
|
||||||
|
}
|
||||||
|
return json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
|
def materialize_proposal_for_execution(
|
||||||
|
*,
|
||||||
|
study: StudySpec,
|
||||||
|
state: StudyState,
|
||||||
|
proposal: Proposal,
|
||||||
|
) -> Proposal:
|
||||||
|
flag_patch = dict(proposal.config_patch.flag_patch)
|
||||||
|
env_patch = dict(proposal.config_patch.env_patch)
|
||||||
|
if not flag_patch and not env_patch:
|
||||||
|
return proposal
|
||||||
|
if TOPOLOGY_FLAG_KEYS.intersection(flag_patch):
|
||||||
|
return proposal
|
||||||
|
if not state.best_trial_id:
|
||||||
|
return proposal
|
||||||
|
incumbent = next(
|
||||||
|
(trial for trial in state.trials if trial.trial_id == state.best_trial_id),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if incumbent is None or not isinstance(incumbent.config_patch, dict):
|
||||||
|
return proposal
|
||||||
|
incumbent_patch = incumbent.config_patch.get("flag_patch")
|
||||||
|
if not isinstance(incumbent_patch, dict):
|
||||||
|
return proposal
|
||||||
|
inherited_topology = {
|
||||||
|
key: value
|
||||||
|
for key, value in incumbent_patch.items()
|
||||||
|
if key in TOPOLOGY_FLAG_KEYS and study.engine.base_flags.get(key) != value
|
||||||
|
}
|
||||||
|
if not inherited_topology:
|
||||||
|
return proposal
|
||||||
|
merged_flag_patch = dict(inherited_topology)
|
||||||
|
merged_flag_patch.update(flag_patch)
|
||||||
|
return replace(
|
||||||
|
proposal,
|
||||||
|
config_patch=ConfigPatch(
|
||||||
|
env_patch=env_patch,
|
||||||
|
flag_patch=merged_flag_patch,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def materialized_effective_config_signature(
|
||||||
|
*,
|
||||||
|
study: StudySpec,
|
||||||
|
state: StudyState,
|
||||||
|
proposal: Proposal,
|
||||||
|
) -> str:
|
||||||
|
materialized = materialize_proposal_for_execution(
|
||||||
|
study=study,
|
||||||
|
state=state,
|
||||||
|
proposal=proposal,
|
||||||
|
)
|
||||||
|
return effective_config_signature(study, materialized.config_patch)
|
||||||
|
|
||||||
|
|
||||||
|
def tested_config_signature_index(study: StudySpec, state: StudyState) -> dict[str, list[str]]:
|
||||||
|
index: dict[str, list[str]] = {}
|
||||||
|
for trial in state.trials:
|
||||||
|
signature = effective_config_signature(study, trial.config_patch)
|
||||||
|
index.setdefault(signature, []).append(trial.trial_id)
|
||||||
|
return index
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical_env_map(payload: dict[str, Any]) -> dict[str, str]:
|
||||||
|
return {str(key): str(value) for key, value in payload.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical_flag_map(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
return {str(key): _canonical_flag_value(value) for key, value in payload.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical_flag_value(value: Any) -> Any:
|
||||||
|
if value is None or isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
if isinstance(value, int):
|
||||||
|
return value
|
||||||
|
if isinstance(value, float):
|
||||||
|
return int(value) if value.is_integer() else value
|
||||||
|
if isinstance(value, str):
|
||||||
|
return _canonical_string_flag_value(value)
|
||||||
|
if isinstance(value, list):
|
||||||
|
return [_canonical_flag_value(item) for item in value]
|
||||||
|
if isinstance(value, tuple):
|
||||||
|
return [_canonical_flag_value(item) for item in value]
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return {str(key): _canonical_flag_value(item) for key, item in value.items()}
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def _canonical_string_flag_value(value: str) -> Any:
|
||||||
|
stripped = value.strip()
|
||||||
|
if not stripped:
|
||||||
|
return stripped
|
||||||
|
try:
|
||||||
|
parsed_int = int(stripped, 10)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return parsed_int
|
||||||
|
try:
|
||||||
|
parsed_float = float(stripped)
|
||||||
|
except ValueError:
|
||||||
|
return stripped
|
||||||
|
if parsed_float.is_integer():
|
||||||
|
return int(parsed_float)
|
||||||
|
return parsed_float
|
||||||
@@ -5,6 +5,10 @@ import hashlib
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from .config_signature import (
|
||||||
|
effective_config_signature as _shared_effective_config_signature,
|
||||||
|
normalized_config_patch as _shared_normalized_config_patch,
|
||||||
|
)
|
||||||
from .lca import EPSILON, WorkloadProfile
|
from .lca import EPSILON, WorkloadProfile
|
||||||
from .spec import ConfigPatch, Proposal, StudySpec, StudyState, TrialSummary
|
from .spec import ConfigPatch, Proposal, StudySpec, StudyState, TrialSummary
|
||||||
|
|
||||||
@@ -2203,7 +2207,6 @@ def _state_tested_signatures(study: StudySpec, state: StudyState) -> set[str]:
|
|||||||
return {
|
return {
|
||||||
_effective_config_signature(study, trial.config_patch)
|
_effective_config_signature(study, trial.config_patch)
|
||||||
for trial in state.trials
|
for trial in state.trials
|
||||||
if isinstance(trial.config_patch, dict)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2872,20 +2875,8 @@ def _config_signature(config_patch: Any) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _effective_config_signature(study: StudySpec, config_patch: Any) -> str:
|
def _effective_config_signature(study: StudySpec, config_patch: Any) -> str:
|
||||||
patch = _normalized_config_patch(config_patch)
|
return _shared_effective_config_signature(study, config_patch)
|
||||||
payload = {
|
|
||||||
"env": {**study.engine.base_envs, **patch["env_patch"]},
|
|
||||||
"flags": {**study.engine.base_flags, **patch["flag_patch"]},
|
|
||||||
}
|
|
||||||
return json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
|
||||||
|
|
||||||
|
|
||||||
def _normalized_config_patch(config_patch: Any) -> dict[str, dict[str, Any]]:
|
def _normalized_config_patch(config_patch: Any) -> dict[str, dict[str, Any]]:
|
||||||
if not isinstance(config_patch, dict):
|
return _shared_normalized_config_patch(config_patch)
|
||||||
config_patch = {}
|
|
||||||
env_patch = config_patch.get("env_patch")
|
|
||||||
flag_patch = config_patch.get("flag_patch")
|
|
||||||
return {
|
|
||||||
"env_patch": env_patch if isinstance(env_patch, dict) else {},
|
|
||||||
"flag_patch": flag_patch if isinstance(flag_patch, dict) else {},
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from dataclasses import replace
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from .config_signature import materialize_proposal_for_execution
|
||||||
from .spec import (
|
from .spec import (
|
||||||
ConfigPatch,
|
|
||||||
Proposal,
|
Proposal,
|
||||||
SamplingSearchSpec,
|
SamplingSearchSpec,
|
||||||
StudySpec,
|
StudySpec,
|
||||||
@@ -17,14 +17,6 @@ from .spec import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_TOPOLOGY_FLAG_KEYS = {
|
|
||||||
"tensor-parallel-size",
|
|
||||||
"data-parallel-size",
|
|
||||||
"expert-parallel-size",
|
|
||||||
"enable-expert-parallel",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StudyStore:
|
class StudyStore:
|
||||||
def __init__(self, root: Path | None = None):
|
def __init__(self, root: Path | None = None):
|
||||||
base = root or Path(".aituner") / "studies"
|
base = root or Path(".aituner") / "studies"
|
||||||
@@ -85,7 +77,7 @@ class StudyStore:
|
|||||||
state: StudyState,
|
state: StudyState,
|
||||||
proposal: Proposal,
|
proposal: Proposal,
|
||||||
) -> tuple[TrialSpec, StudyState]:
|
) -> tuple[TrialSpec, StudyState]:
|
||||||
proposal = _inherit_incumbent_topology_for_runtime_patch(
|
proposal = materialize_proposal_for_execution(
|
||||||
study=study,
|
study=study,
|
||||||
state=state,
|
state=state,
|
||||||
proposal=proposal,
|
proposal=proposal,
|
||||||
@@ -268,47 +260,6 @@ def _parallel_size_for_proposal(*, study: StudySpec, proposal: Proposal) -> int:
|
|||||||
return _parallel_size_for_config(study=study, flag_patch=proposal.config_patch.flag_patch)
|
return _parallel_size_for_config(study=study, flag_patch=proposal.config_patch.flag_patch)
|
||||||
|
|
||||||
|
|
||||||
def _inherit_incumbent_topology_for_runtime_patch(
|
|
||||||
*,
|
|
||||||
study: StudySpec,
|
|
||||||
state: StudyState,
|
|
||||||
proposal: Proposal,
|
|
||||||
) -> Proposal:
|
|
||||||
flag_patch = dict(proposal.config_patch.flag_patch)
|
|
||||||
env_patch = dict(proposal.config_patch.env_patch)
|
|
||||||
if not flag_patch and not env_patch:
|
|
||||||
return proposal
|
|
||||||
if _TOPOLOGY_FLAG_KEYS.intersection(flag_patch):
|
|
||||||
return proposal
|
|
||||||
if not state.best_trial_id:
|
|
||||||
return proposal
|
|
||||||
incumbent = next(
|
|
||||||
(trial for trial in state.trials if trial.trial_id == state.best_trial_id),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
if incumbent is None or not isinstance(incumbent.config_patch, dict):
|
|
||||||
return proposal
|
|
||||||
incumbent_patch = incumbent.config_patch.get("flag_patch")
|
|
||||||
if not isinstance(incumbent_patch, dict):
|
|
||||||
return proposal
|
|
||||||
inherited_topology = {
|
|
||||||
key: value
|
|
||||||
for key, value in incumbent_patch.items()
|
|
||||||
if key in _TOPOLOGY_FLAG_KEYS and study.engine.base_flags.get(key) != value
|
|
||||||
}
|
|
||||||
if not inherited_topology:
|
|
||||||
return proposal
|
|
||||||
merged_flag_patch = dict(inherited_topology)
|
|
||||||
merged_flag_patch.update(flag_patch)
|
|
||||||
return replace(
|
|
||||||
proposal,
|
|
||||||
config_patch=ConfigPatch(
|
|
||||||
env_patch=env_patch,
|
|
||||||
flag_patch=merged_flag_patch,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _parallel_size_for_trial_id(*, study: StudySpec, study_root: Path, trial_id: str) -> int | None:
|
def _parallel_size_for_trial_id(*, study: StudySpec, study_root: Path, trial_id: str) -> int | None:
|
||||||
trial_spec_path = study_root / "trials" / trial_id / "trial_spec.json"
|
trial_spec_path = study_root / "trials" / trial_id / "trial_spec.json"
|
||||||
if not trial_spec_path.exists():
|
if not trial_spec_path.exists():
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from aituner.cli import main as cli_main
|
from aituner.cli import main as cli_main
|
||||||
from aituner.compare import _aggregate_summary, load_compare_spec, run_compare
|
from aituner.compare import _aggregate_summary, load_compare_spec, run_compare
|
||||||
|
from aituner.config_signature import materialized_effective_config_signature
|
||||||
from aituner.engine import build_launch_recipe
|
from aituner.engine import build_launch_recipe
|
||||||
from aituner.http_client import (
|
from aituner.http_client import (
|
||||||
HttpClientError,
|
HttpClientError,
|
||||||
@@ -382,14 +383,101 @@ class CoreFlowTests(unittest.TestCase):
|
|||||||
study,
|
study,
|
||||||
{"env_patch": {}, "flag_patch": {"tensor-parallel-size": 8}},
|
{"env_patch": {}, "flag_patch": {"tensor-parallel-size": 8}},
|
||||||
)
|
)
|
||||||
|
noop_tp_string = _effective_config_signature(
|
||||||
|
study,
|
||||||
|
{"env_patch": {}, "flag_patch": {"tensor-parallel-size": "8"}},
|
||||||
|
)
|
||||||
changed_tp = _effective_config_signature(
|
changed_tp = _effective_config_signature(
|
||||||
study,
|
study,
|
||||||
{"env_patch": {}, "flag_patch": {"tensor-parallel-size": 4}},
|
{"env_patch": {}, "flag_patch": {"tensor-parallel-size": 4}},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(baseline, noop_tp)
|
self.assertEqual(baseline, noop_tp)
|
||||||
|
self.assertEqual(baseline, noop_tp_string)
|
||||||
self.assertNotEqual(baseline, changed_tp)
|
self.assertNotEqual(baseline, changed_tp)
|
||||||
|
|
||||||
|
def test_materialized_signature_inherits_incumbent_topology(self) -> None:
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
tmp_path = Path(tmp)
|
||||||
|
study_path = _write_study_assets(
|
||||||
|
tmp_path,
|
||||||
|
engine_overrides={
|
||||||
|
"base_flags": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 8000,
|
||||||
|
"tensor-parallel-size": 4,
|
||||||
|
"data-parallel-size": 2,
|
||||||
|
"max-num-seqs": 64,
|
||||||
|
},
|
||||||
|
"tunable_flags": [
|
||||||
|
"tensor-parallel-size",
|
||||||
|
"data-parallel-size",
|
||||||
|
"max-num-seqs",
|
||||||
|
],
|
||||||
|
"topology_constraints": {
|
||||||
|
"allowed_tensor_parallel_sizes": [1, 2, 4, 8],
|
||||||
|
"allowed_data_parallel_sizes": [1, 2, 4, 8],
|
||||||
|
"allowed_tp_dp_products": [1, 2, 4, 8],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
study = load_study_spec(study_path)
|
||||||
|
state = StudyState(
|
||||||
|
study_id=study.study_id,
|
||||||
|
best_trial_id="trial-0002",
|
||||||
|
best_parallel_size=8,
|
||||||
|
trials=[
|
||||||
|
TrialSummary(
|
||||||
|
trial_id="trial-0002",
|
||||||
|
status="completed",
|
||||||
|
parallel_size=8,
|
||||||
|
config_patch={
|
||||||
|
"env_patch": {},
|
||||||
|
"flag_patch": {
|
||||||
|
"tensor-parallel-size": 2,
|
||||||
|
"data-parallel-size": 4,
|
||||||
|
"max-num-seqs": 160,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
runtime_only = Proposal.from_dict(
|
||||||
|
{
|
||||||
|
"observation": "Try the same runtime cap.",
|
||||||
|
"diagnosis": "This should materialize on incumbent topology.",
|
||||||
|
"config_patch": {"env_patch": {}, "flag_patch": {"max-num-seqs": 160}},
|
||||||
|
"expected_effects": ["no-op after topology inheritance"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
explicit = Proposal.from_dict(
|
||||||
|
{
|
||||||
|
"observation": "Explicit duplicate.",
|
||||||
|
"diagnosis": "Same effective execution config.",
|
||||||
|
"config_patch": {
|
||||||
|
"env_patch": {},
|
||||||
|
"flag_patch": {
|
||||||
|
"tensor-parallel-size": "2",
|
||||||
|
"data-parallel-size": "4",
|
||||||
|
"max-num-seqs": "160",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"expected_effects": ["same config"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
materialized_effective_config_signature(
|
||||||
|
study=study,
|
||||||
|
state=state,
|
||||||
|
proposal=runtime_only,
|
||||||
|
),
|
||||||
|
materialized_effective_config_signature(
|
||||||
|
study=study,
|
||||||
|
state=state,
|
||||||
|
proposal=explicit,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_lca_workload_profile_uses_standard_10d_features(self) -> None:
|
def test_lca_workload_profile_uses_standard_10d_features(self) -> None:
|
||||||
window = WindowRecord(
|
window = WindowRecord(
|
||||||
window_id="w1",
|
window_id="w1",
|
||||||
@@ -6019,6 +6107,105 @@ class CoreFlowTests(unittest.TestCase):
|
|||||||
self.assertTrue(honored)
|
self.assertTrue(honored)
|
||||||
self.assertEqual(honored[-1]["stop_authorized_by"], "llm_after_veto_budget")
|
self.assertEqual(honored[-1]["stop_authorized_by"], "llm_after_veto_budget")
|
||||||
|
|
||||||
|
def test_cli_tune_rejects_repeated_materialized_llm_config(self) -> None:
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
tmp_path = Path(tmp)
|
||||||
|
study_path = _write_study_assets(
|
||||||
|
tmp_path,
|
||||||
|
engine_overrides={
|
||||||
|
"base_flags": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 8000,
|
||||||
|
"tensor-parallel-size": 4,
|
||||||
|
"data-parallel-size": 2,
|
||||||
|
"max-num-seqs": 64,
|
||||||
|
},
|
||||||
|
"tunable_flags": [
|
||||||
|
"tensor-parallel-size",
|
||||||
|
"data-parallel-size",
|
||||||
|
"max-num-seqs",
|
||||||
|
],
|
||||||
|
"topology_constraints": {
|
||||||
|
"allowed_tensor_parallel_sizes": [1, 2, 4, 8],
|
||||||
|
"allowed_data_parallel_sizes": [1, 2, 4, 8],
|
||||||
|
"allowed_tp_dp_products": [1, 2, 4, 8],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
spec = json.loads(study_path.read_text(encoding="utf-8"))
|
||||||
|
spec["llm"]["use_harness"] = False
|
||||||
|
spec["llm"]["endpoint"] = {
|
||||||
|
"provider": "custom",
|
||||||
|
"base_url": "http://localhost:9/v1",
|
||||||
|
"model": "test-model",
|
||||||
|
"api_key_env": "AITUNER_TEST_KEY",
|
||||||
|
}
|
||||||
|
study_path.write_text(json.dumps(spec), encoding="utf-8")
|
||||||
|
study = load_study_spec(study_path)
|
||||||
|
store_root = tmp_path / "store"
|
||||||
|
store = StudyStore(store_root)
|
||||||
|
store.init_study(spec_path=study_path, study=study)
|
||||||
|
store.save_state(
|
||||||
|
StudyState(
|
||||||
|
study_id=study.study_id,
|
||||||
|
best_trial_id="trial-0002",
|
||||||
|
best_parallel_size=8,
|
||||||
|
best_sampling_u=0.125,
|
||||||
|
best_request_rate=3.0,
|
||||||
|
best_request_rate_per_gpu=0.375,
|
||||||
|
next_trial_index=3,
|
||||||
|
trials=[
|
||||||
|
TrialSummary(
|
||||||
|
trial_id="trial-0002",
|
||||||
|
status="completed",
|
||||||
|
parallel_size=8,
|
||||||
|
best_sampling_u=0.125,
|
||||||
|
best_request_rate=3.0,
|
||||||
|
best_request_rate_per_gpu=0.375,
|
||||||
|
config_patch={
|
||||||
|
"env_patch": {},
|
||||||
|
"flag_patch": {
|
||||||
|
"tensor-parallel-size": 2,
|
||||||
|
"data-parallel-size": 4,
|
||||||
|
"max-num-seqs": 160,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
repeated_runtime_patch = json.dumps(
|
||||||
|
{
|
||||||
|
"observation": "Try the same runtime setting.",
|
||||||
|
"diagnosis": "This is duplicate after topology inheritance.",
|
||||||
|
"config_patch": {"env_patch": {}, "flag_patch": {"max-num-seqs": 160}},
|
||||||
|
"expected_effects": ["should be vetoed"],
|
||||||
|
"why_not_previous_failures": "",
|
||||||
|
"should_stop": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
stderr = io.StringIO()
|
||||||
|
with mock.patch("aituner.cli.run_trial") as run_trial_mock, mock.patch(
|
||||||
|
"aituner.cli.call_llm_for_proposal", return_value=repeated_runtime_patch
|
||||||
|
), contextlib.redirect_stderr(stderr):
|
||||||
|
exit_code = cli_main(
|
||||||
|
[
|
||||||
|
"study",
|
||||||
|
"tune",
|
||||||
|
"--spec",
|
||||||
|
str(study_path),
|
||||||
|
"--store-root",
|
||||||
|
str(store_root),
|
||||||
|
"--skip-baseline",
|
||||||
|
"--max-trials",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.assertEqual(exit_code, 2)
|
||||||
|
run_trial_mock.assert_not_called()
|
||||||
|
self.assertIn("repeats an already tested effective full config", stderr.getvalue())
|
||||||
|
self.assertIn("trial-0002", stderr.getvalue())
|
||||||
|
|
||||||
def test_cli_tune_uses_harness_stop_before_llm(self) -> None:
|
def test_cli_tune_uses_harness_stop_before_llm(self) -> None:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
tmp_path = Path(tmp)
|
tmp_path = Path(tmp)
|
||||||
|
|||||||
Reference in New Issue
Block a user