Skip to content

Commit 4e04533

Browse files
shrutipatel31facebook-github-bot
authored andcommitted
New Complexity Rating Healthcheck (facebook#4556)
Summary: Pull Request resolved: facebook#4556 Differential Revision: D87163755
1 parent 20ba1ff commit 4e04533

File tree

5 files changed

+516
-0
lines changed

5 files changed

+516
-0
lines changed

ax/analysis/healthcheck/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ax.analysis.healthcheck.can_generate_candidates import (
99
CanGenerateCandidatesAnalysis,
1010
)
11+
from ax.analysis.healthcheck.complexity_rating import ComplexityRatingAnalysis
1112

1213
from ax.analysis.healthcheck.constraints_feasibility import (
1314
ConstraintsFeasibilityAnalysis,
@@ -33,4 +34,5 @@
3334
"ShouldGenerateCandidates",
3435
"SearchSpaceAnalysis",
3536
"RegressionAnalysis",
37+
"ComplexityRatingAnalysis",
3638
]
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
# pyre-strict
7+
8+
from typing import Any, final
9+
10+
import pandas as pd
11+
from ax.adapter.base import Adapter
12+
from ax.analysis.analysis import Analysis
13+
from ax.analysis.healthcheck.healthcheck_analysis import (
14+
create_healthcheck_analysis_card,
15+
HealthcheckAnalysisCard,
16+
HealthcheckStatus,
17+
)
18+
from ax.core.experiment import Experiment
19+
from ax.generation_strategy.generation_strategy import GenerationStrategy
20+
from ax.service.orchestrator import OrchestratorOptions
21+
from ax.utils.common.complexity_utils import (
22+
check_if_in_standard,
23+
DEFAULT_TIER_MESSAGES,
24+
format_tier_message,
25+
summarize_ax_optimization_complexity,
26+
TierMessages,
27+
)
28+
from pyre_extensions import none_throws, override
29+
30+
31+
@final
32+
class ComplexityRatingAnalysis(Analysis):
33+
"""
34+
Healthcheck that evaluates whether the experiment configuration is in the
35+
"standard" (fully tested and supported), "advanced" (technically supported
36+
but uses features that may not be well-tested or compatible with other advanced
37+
features), or unsupported.
38+
39+
Status Logic:
40+
- PASS: Configuration is in standard
41+
- WARNING: Configuration is advanced
42+
- FAIL: Configuration is unsupported
43+
44+
The healthcheck evaluates:
45+
- Search space complexity (number of parameters, parameter constraints, etc.)
46+
- Optimization config (number of objectives and outcome constraints)
47+
- Other settings (early stopping, global stopping, trial limits, etc.)
48+
"""
49+
50+
def __init__(
51+
self,
52+
options: OrchestratorOptions | None = None,
53+
tier_metadata: dict[str, Any] | None = None,
54+
tier_messages: TierMessages = DEFAULT_TIER_MESSAGES,
55+
) -> None:
56+
"""Initialize the ComplexityRatingAnalysis.
57+
58+
Args:
59+
options: The orchestrator options used for the optimization.
60+
Required to evaluate early stopping, global stopping, and
61+
failure rate settings.
62+
tier_metadata: Additional tier-related metadata from the orchestrator.
63+
Supported keys:
64+
- 'user_supplied_max_trials': Maximum number of trials.
65+
- 'uses_standard_api': Whether high-level configs are used (as
66+
opposed to low-level Ax abstractions), ensuring the full
67+
experiment configuration is known upfront.
68+
tier_messages: Custom tier-specific messages used when formatting
69+
the tier result. Defaults to DEFAULT_TIER_MESSAGES which contains
70+
generic messages suitable for most users. Pass a custom TierMessages
71+
instance to provide tool-specific descriptions, support SLAs,
72+
links to docs, or contact information.
73+
"""
74+
self.options = options
75+
self.tier_metadata: dict[str, Any] = (
76+
tier_metadata if tier_metadata is not None else {}
77+
)
78+
self.tier_messages = tier_messages
79+
80+
@override
81+
def validate_applicable_state(
82+
self,
83+
experiment: Experiment | None = None,
84+
generation_strategy: GenerationStrategy | None = None,
85+
adapter: Adapter | None = None,
86+
) -> str | None:
87+
if experiment is None:
88+
return "Experiment is required for ComplexityRatingAnalysis."
89+
if self.options is None:
90+
return (
91+
"OrchestratorOptions is required for ComplexityRatingAnalysis. "
92+
"Please pass options to the constructor."
93+
)
94+
return None
95+
96+
@override
97+
def compute(
98+
self,
99+
experiment: Experiment | None = None,
100+
generation_strategy: GenerationStrategy | None = None,
101+
adapter: Adapter | None = None,
102+
) -> HealthcheckAnalysisCard:
103+
experiment = none_throws(experiment)
104+
options = none_throws(self.options)
105+
optimization_summary = summarize_ax_optimization_complexity(
106+
experiment=experiment,
107+
options=options,
108+
tier_metadata=self.tier_metadata,
109+
)
110+
111+
# Determine tier
112+
tier, why_not_standard, why_not_supported = check_if_in_standard(
113+
optimization_summary
114+
)
115+
116+
# Build subtitle using custom messages if provided, else defaults
117+
subtitle = format_tier_message(
118+
tier=tier,
119+
why_not_is_in_standard=why_not_standard,
120+
why_not_supported=why_not_supported,
121+
tier_messages=self.tier_messages,
122+
)
123+
124+
# Determine status
125+
if tier == "Standard":
126+
status = HealthcheckStatus.PASS
127+
elif tier == "Advanced":
128+
status = HealthcheckStatus.WARNING
129+
else: # Unsupported
130+
status = HealthcheckStatus.FAIL
131+
132+
# Create dataframe with experiment summary
133+
df = pd.DataFrame(
134+
[
135+
{
136+
"Metric": "Optimization Complexity Rating",
137+
"Value": tier,
138+
},
139+
{
140+
"Metric": "Total Parameters",
141+
"Value": str(optimization_summary.num_params),
142+
},
143+
{
144+
"Metric": "Objectives",
145+
"Value": str(optimization_summary.num_objectives),
146+
},
147+
{
148+
"Metric": "Outcome Constraints",
149+
"Value": str(optimization_summary.num_outcome_constraints),
150+
},
151+
{
152+
"Metric": "Parameter Constraints",
153+
"Value": str(optimization_summary.num_parameter_constraints),
154+
},
155+
]
156+
)
157+
158+
return create_healthcheck_analysis_card(
159+
name=self.__class__.__name__,
160+
title="Complexity Rating Healthcheck",
161+
subtitle=subtitle,
162+
df=df,
163+
status=status,
164+
tier=tier,
165+
)

0 commit comments

Comments
 (0)