Skip to content

Commit 43827ea

Browse files
shrutipatel31facebook-github-bot
authored andcommitted
Extract early stopping message constants and helpers to OSS (#4751)
Summary: Pull Request resolved: #4751 Differential Revision: D90404643
1 parent 2b16f4e commit 43827ea

File tree

2 files changed

+73
-33
lines changed

2 files changed

+73
-33
lines changed

ax/analysis/healthcheck/early_stopping_healthcheck.py

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@
1717
)
1818
from ax.analysis.utils import validate_experiment
1919
from ax.core.base_trial import TrialStatus
20-
from ax.core.data import MAP_KEY
2120
from ax.core.experiment import Experiment
2221
from ax.core.map_metric import MapMetric
2322
from ax.core.optimization_config import MultiObjectiveOptimizationConfig
2423
from ax.early_stopping.dispatch import get_default_ess_or_none
2524
from ax.early_stopping.experiment_replay import replay_experiment
2625
from ax.early_stopping.strategies.base import BaseEarlyStoppingStrategy
2726
from ax.early_stopping.strategies.percentile import PercentileEarlyStoppingStrategy
28-
from ax.early_stopping.utils import estimate_early_stopping_savings
27+
from ax.early_stopping.utils import (
28+
EARLY_STOPPING_NUDGE_MSG,
29+
EARLY_STOPPING_NUDGE_TITLE,
30+
EARLY_STOPPING_SAVINGS_TITLE,
31+
estimate_early_stopping_savings,
32+
format_early_stopping_savings_message,
33+
)
2934
from ax.generation_strategy.generation_strategy import GenerationStrategy
3035
from ax.service.utils.early_stopping import get_early_stopping_metrics
3136
from pyre_extensions import none_throws, override
@@ -350,26 +355,10 @@ def _report_early_stopping_status(
350355
n_running = len(experiment.trial_indices_by_status[TrialStatus.RUNNING])
351356
n_ran = n_stopped + n_completed + n_failed + n_running
352357

353-
ess_msg = (
354-
f"Throughout this experiment, {n_stopped} trials were early stopped, "
355-
f"out of a total of {n_ran} trials. "
356-
)
357-
358-
if savings > 0:
359-
ess_msg += (
360-
f"The capacity savings (computed using {MAP_KEY}) are "
361-
f"estimated to be {savings * 100:.0f}%."
362-
)
363-
else:
364-
ess_msg += (
365-
"Capacity savings are not yet available. Either no trials have "
366-
"been early stopped, or no trials have completed (which is "
367-
"required to estimate savings). Check back once more trials are "
368-
"completed and/or early stopped."
369-
)
370-
371358
# Add multi-objective note if applicable
372-
subtitle = ess_msg
359+
subtitle = format_early_stopping_savings_message(
360+
n_stopped=n_stopped, n_ran=n_ran, savings=savings
361+
)
373362
if len(target_ess_metric_names) > 1:
374363
subtitle += (
375364
f"\n\nNote: Although {len(target_ess_metric_names)} metrics are "
@@ -397,7 +386,7 @@ def _report_early_stopping_status(
397386
)
398387

399388
return self._create_card(
400-
title="Capacity savings due to early stopping",
389+
title=EARLY_STOPPING_SAVINGS_TITLE,
401390
subtitle=subtitle,
402391
df=df,
403392
status=HealthcheckStatus.PASS,
@@ -437,13 +426,8 @@ def _report_early_stopping_nudge(
437426
best_metric_name = max(metric_to_savings, key=metric_to_savings.get)
438427
best_savings = metric_to_savings[best_metric_name]
439428

440-
subtitle = (
441-
"This sweep uses metrics that are **compatible with early stopping**! "
442-
"Using early stopping could have saved you both capacity and "
443-
"optimization wall time. For example, we estimate that using early "
444-
f"stopping on the '{best_metric_name}' metric could have provided "
445-
f"{best_savings:.0f}% capacity savings, with no regression in "
446-
"optimization performance."
429+
subtitle = EARLY_STOPPING_NUDGE_MSG.format(
430+
metric_name=best_metric_name, savings=best_savings
447431
)
448432

449433
# Append additional info if provided
@@ -462,10 +446,7 @@ def _report_early_stopping_nudge(
462446
]
463447
df = pd.DataFrame(metric_rows)
464448

465-
title = (
466-
f"{best_savings:.0f}% potential capacity savings if you turn on "
467-
f"early stopping feature"
468-
)
449+
title = EARLY_STOPPING_NUDGE_TITLE.format(savings=best_savings)
469450

470451
return self._create_card(
471452
title=title,

ax/early_stopping/utils.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,65 @@
1919

2020
logger: Logger = get_logger(__name__)
2121

22+
# Early stopping message constants for use in analysis and reporting
23+
EARLY_STOPPING_STATUS_MSG = (
24+
"Throughout this experiment, {n_stopped} trials were early stopped, out "
25+
"of a total of {n_ran} trials. "
26+
)
27+
28+
EARLY_STOPPING_SAVINGS_TITLE = "Capacity savings due to early stopping"
29+
30+
EARLY_STOPPING_SAVINGS_MSG = (
31+
"The capacity savings (computed using {map_key}) are estimated to be "
32+
"{savings:.0f}%."
33+
)
34+
35+
EARLY_STOPPING_SAVINGS_TBD = (
36+
"Capacity savings are not yet available. Either no trials have been early "
37+
"stopped, or no trials have completed (which is required to estimate "
38+
"savings). Check back once more trials are completed and/or early stopped."
39+
)
40+
41+
EARLY_STOPPING_NUDGE_MSG = (
42+
"This sweep uses metrics that are **compatible with early stopping**! "
43+
"Using early stopping could have saved you both capacity and optimization "
44+
"wall time. For example, we estimate that using early stopping on the "
45+
"'{metric_name}' metric could have provided {savings:.0f}% capacity "
46+
"savings, with no regression in optimization performance."
47+
)
48+
49+
EARLY_STOPPING_NUDGE_TITLE = (
50+
"{savings:.0f}% potential capacity savings if you turn on early stopping feature"
51+
)
52+
53+
54+
def format_early_stopping_savings_message(
55+
n_stopped: int,
56+
n_ran: int,
57+
savings: float,
58+
) -> str:
59+
"""Format a message describing early stopping status and savings.
60+
61+
Args:
62+
n_stopped: Number of trials that were early stopped.
63+
n_ran: Total number of trials that ran.
64+
savings: Resource savings as a fraction (0.0 to 1.0). For example, 0.11
65+
indicates 11% savings.
66+
67+
Returns:
68+
A formatted message string describing the early stopping status and
69+
either the estimated savings percentage or a note that savings are
70+
not yet available.
71+
"""
72+
msg = EARLY_STOPPING_STATUS_MSG.format(n_stopped=n_stopped, n_ran=n_ran)
73+
74+
if savings > 0:
75+
msg += EARLY_STOPPING_SAVINGS_MSG.format(map_key=MAP_KEY, savings=savings * 100)
76+
else:
77+
msg += EARLY_STOPPING_SAVINGS_TBD
78+
79+
return msg
80+
2281

2382
def _is_worse(a: Any, b: Any, minimize: bool) -> Any:
2483
"""Determine if value `a` is worse than value `b` based on optimization direction.

0 commit comments

Comments
 (0)