Constrain phase reranking to nearby sizes

This commit is contained in:
Meta Vens 2026-04-22 07:31:45 +01:00
commit 05385fce2a
3 changed files with 55 additions and 6 deletions

View file

@ -39,6 +39,7 @@ class SolverHyperParams:
phase_rerank_edge_concentration_weight: float = 0.10
phase_rerank_inference_penalty_weight: float = 0.05
phase_rerank_confidence_threshold: float = 0.12
phase_rerank_max_size_delta_ratio: float = 0.15
phase_rerank_margin: float = 0.004
def to_dict(self) -> dict[str, float]:

View file

@ -167,6 +167,7 @@ def _select_phase_candidate(
"stroke_wobble_error": foreground_stroke_wobble_error(preview, source),
"edge_concentration": foreground_edge_concentration(candidate_artifacts.target_rgba),
"inference_penalty": top_score - float(candidate.score),
"size_delta_ratio": _size_delta_ratio(inference, candidate_inference),
}
)
@ -186,6 +187,13 @@ def _select_phase_candidate(
best_rank = float("inf")
best_candidate = inference
for index, record in enumerate(candidate_records):
candidate_inference = record["inference"]
size_delta_ratio = float(record["size_delta_ratio"])
if (
candidate_inference.target_width != inference.target_width
or candidate_inference.target_height != inference.target_height
) and size_delta_ratio > solver_params.phase_rerank_max_size_delta_ratio:
continue
rank = (
solver_params.phase_rerank_support_weight * support_penalty[index]
+ solver_params.phase_rerank_edge_position_weight * edge_position_penalty[index]
@ -215,3 +223,9 @@ def _normalize_penalty(values, *, higher_is_better: bool = False) -> list[float]
if higher_is_better:
normalized = 1.0 - normalized
return normalized.astype(np.float32).tolist()
def _size_delta_ratio(a: InferenceResult, b: InferenceResult) -> float:
width_ratio = abs(b.target_width - a.target_width) / max(1.0, float(a.target_width))
height_ratio = abs(b.target_height - a.target_height) / max(1.0, float(a.target_height))
return max(width_ratio, height_ratio)

View file

@ -147,12 +147,12 @@ def test_phase_rerank_can_override_low_confidence_inference_pick(monkeypatch) ->
def test_phase_rerank_can_override_to_better_size_candidate(monkeypatch) -> None:
source = np.zeros((4, 4, 4), dtype=np.float32)
candidate_a = InferenceCandidate(target_width=2, target_height=2, phase_x=0.0, phase_y=0.0, score=0.91, breakdown={})
candidate_b = InferenceCandidate(target_width=3, target_height=3, phase_x=0.0, phase_y=0.0, score=0.88, breakdown={})
source = np.zeros((16, 16, 4), dtype=np.float32)
candidate_a = InferenceCandidate(target_width=16, target_height=16, phase_x=0.0, phase_y=0.0, score=0.91, breakdown={})
candidate_b = InferenceCandidate(target_width=18, target_height=18, phase_x=0.0, phase_y=0.0, score=0.88, breakdown={})
inference = InferenceResult(
target_width=2,
target_height=2,
target_width=16,
target_height=16,
phase_x=0.0,
phase_y=0.0,
confidence=0.0,
@ -168,7 +168,7 @@ def test_phase_rerank_can_override_to_better_size_candidate(monkeypatch) -> None
return DummyArtifacts(rgba)
def fake_support(source_rgba, output_rgba, *, target_width, target_height, phase_x, phase_y):
if target_width == 2:
if target_width == 16:
return {"score": 0.10}
return {"score": 0.01}
@ -180,6 +180,40 @@ def test_phase_rerank_can_override_to_better_size_candidate(monkeypatch) -> None
assert selected.target_height == candidate_b.target_height
def test_phase_rerank_rejects_large_size_jump(monkeypatch) -> None:
source = np.zeros((16, 16, 4), dtype=np.float32)
candidate_a = InferenceCandidate(target_width=16, target_height=16, phase_x=0.0, phase_y=0.0, score=0.91, breakdown={})
candidate_b = InferenceCandidate(target_width=24, target_height=24, phase_x=0.0, phase_y=0.0, score=0.88, breakdown={})
inference = InferenceResult(
target_width=16,
target_height=16,
phase_x=0.0,
phase_y=0.0,
confidence=0.0,
top_candidates=[candidate_a, candidate_b],
)
class DummyArtifacts:
def __init__(self, rgba: np.ndarray) -> None:
self.target_rgba = rgba
def fake_optimize_uv_field(source_rgba, inference, analysis, steps, seed, device, solver_params=None):
rgba = np.zeros((inference.target_height, inference.target_width, 4), dtype=np.float32)
return DummyArtifacts(rgba)
def fake_support(source_rgba, output_rgba, *, target_width, target_height, phase_x, phase_y):
if target_width == 16:
return {"score": 0.10}
return {"score": 0.01}
monkeypatch.setattr("repixelizer.pipeline.optimize_uv_field", fake_optimize_uv_field)
monkeypatch.setattr("repixelizer.pipeline.source_lattice_consistency_breakdown", fake_support)
selected = _select_phase_candidate(source, inference, analysis=object(), seed=7, device="cpu")
assert selected.target_width == candidate_a.target_width
assert selected.target_height == candidate_a.target_height
def test_phase_rerank_can_prefer_better_line_metrics(monkeypatch) -> None:
source = np.zeros((4, 4, 4), dtype=np.float32)
candidate_a = InferenceCandidate(target_width=2, target_height=2, phase_x=-0.2, phase_y=0.0, score=0.91, breakdown={})