fix: filter frozen pools by requested task_types subset
This commit is contained in:
@@ -320,9 +320,15 @@ def _filter_untrainable_types(
|
|||||||
"""
|
"""
|
||||||
diag_by_type = Counter(u.task_type for u in build_units(pools.diagnosis))
|
diag_by_type = Counter(u.task_type for u in build_units(pools.diagnosis))
|
||||||
val_by_type = Counter(u.task_type for u in build_units(pools.validation))
|
val_by_type = Counter(u.task_type for u in build_units(pools.validation))
|
||||||
|
# 先按调用方显式 task_types 收窄候选集:未请求的题型(哪怕可训练)不得进入
|
||||||
|
# keep,否则冻结全局 pools 后 batch/diagnosis 会训练非请求题型,而 gate 只覆盖
|
||||||
|
# 请求题型 → 静默语义偏差(I-4)。task_types=None 表示全部题型皆为候选。
|
||||||
|
candidates = set(diag_by_type) | set(val_by_type)
|
||||||
|
if task_types is not None:
|
||||||
|
candidates &= set(task_types)
|
||||||
keep: set[str] = set()
|
keep: set[str] = set()
|
||||||
dropped: list[tuple[str, str]] = []
|
dropped: list[tuple[str, str]] = []
|
||||||
for tt in set(diag_by_type) | set(val_by_type):
|
for tt in candidates:
|
||||||
n_val = val_by_type.get(tt, 0)
|
n_val = val_by_type.get(tt, 0)
|
||||||
n_units = diag_by_type.get(tt, 0) + n_val
|
n_units = diag_by_type.get(tt, 0) + n_val
|
||||||
if n_val < eval_min_per_class:
|
if n_val < eval_min_per_class:
|
||||||
|
|||||||
@@ -490,6 +490,33 @@ class TestFilterUntrainableTypes:
|
|||||||
assert "P" not in new_types
|
assert "P" not in new_types
|
||||||
assert "A" in new_types
|
assert "A" in new_types
|
||||||
|
|
||||||
|
def test_task_types_subset_drops_non_requested_trainable(self) -> None:
|
||||||
|
"""指定 task_types 子集时:非请求但可训练的题型也被剔除出 diag/val。
|
||||||
|
|
||||||
|
回归 I-4:pools 过滤此前只按可训练性 keep、不按 task_types 收窄,导致
|
||||||
|
冻结全局 pools 后 batch/diagnosis 会训练非请求题型(gate 只覆盖请求题型
|
||||||
|
→ 静默语义偏差)。此处 A、B 均可训,仅请求 A,B 必须被剔除。
|
||||||
|
"""
|
||||||
|
# 题型 A:diag=8 + val=2 → units=10、val=2,可训
|
||||||
|
diag = [_FakeQuestion(question_id=f"A-d{i}", task_type="A") for i in range(8)]
|
||||||
|
val = [_FakeQuestion(question_id=f"A-v{i}", task_type="A") for i in range(2)]
|
||||||
|
# 题型 B:diag=8 + val=2 → units=10、val=2,同样可训(但未被请求)
|
||||||
|
diag += [_FakeQuestion(question_id=f"B-d{i}", task_type="B") for i in range(8)]
|
||||||
|
val += [_FakeQuestion(question_id=f"B-v{i}", task_type="B") for i in range(2)]
|
||||||
|
pools = _FakePools(diagnosis=diag, validation=val, test=[])
|
||||||
|
|
||||||
|
new_pools, new_types = _filter_untrainable_types(
|
||||||
|
pools,
|
||||||
|
task_types=["A"],
|
||||||
|
eval_min_per_class=2,
|
||||||
|
trainable_min_units=8,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 非请求题型 B(可训)被剔除出 diag/val
|
||||||
|
assert {q.task_type for q in new_pools.diagnosis} == {"A"}
|
||||||
|
assert {q.task_type for q in new_pools.validation} == {"A"}
|
||||||
|
assert new_types == ["A"]
|
||||||
|
|
||||||
def test_all_filtered_raises(self) -> None:
|
def test_all_filtered_raises(self) -> None:
|
||||||
"""所有题型都被剔除时 fail-fast:raise RuntimeError 并列出剔除原因。"""
|
"""所有题型都被剔除时 fail-fast:raise RuntimeError 并列出剔除原因。"""
|
||||||
diag = [_FakeQuestion(question_id="B-d0", task_type="B")] # val=0 < 2
|
diag = [_FakeQuestion(question_id="B-d0", task_type="B")] # val=0 < 2
|
||||||
|
|||||||
Reference in New Issue
Block a user