Skip to content

Commit 10e7218

Browse files
committed
Fix harm category normalization in scorer evaluation
1 parent 3c555d6 commit 10e7218

3 files changed

Lines changed: 31 additions & 4 deletions

File tree

‎pyrit/models/harm_category.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def _initialize_aliases(cls) -> None:
100100
{
101101
"ableism": [cls.REPRESENTATIONAL, cls.HATE_SPEECH],
102102
"bias": [cls.REPRESENTATIONAL, cls.HATE_SPEECH],
103+
"fairness_bias": [cls.REPRESENTATIONAL],
103104
"bullying": [cls.HARASSMENT],
104105
"chemistry": [cls.CBRN],
105106
"controlled/regulated substances": [cls.DRUG_USE],

‎pyrit/score/scorer_evaluation/scorer_evaluator.py‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ async def run_evaluation_async(
237237
# Run evaluation
238238
metrics = await self.evaluate_dataset_async(
239239
labeled_dataset=combined_dataset,
240+
harm_category=dataset_files.harm_category,
240241
num_scorer_trials=num_scorer_trials,
241242
max_concurrency=max_concurrency,
242243
)
@@ -352,6 +353,7 @@ def _should_skip_evaluation(
352353
async def evaluate_dataset_async(
353354
self,
354355
labeled_dataset: HumanLabeledDataset,
356+
harm_category: str | None = None,
355357
num_scorer_trials: int = 1,
356358
max_concurrency: int = 10,
357359
) -> ScorerMetrics:
@@ -364,6 +366,7 @@ async def evaluate_dataset_async(
364366
365367
Args:
366368
labeled_dataset (HumanLabeledDataset): The HumanLabeledDataset to evaluate the scorer against.
369+
harm_category (str | None): The configured harm category for the evaluation.
367370
num_scorer_trials (int): The number of trials to run the scorer on all responses.
368371
max_concurrency (int): Maximum number of concurrent scoring requests. Defaults to 10.
369372
@@ -386,16 +389,17 @@ async def evaluate_dataset_async(
386389
# Transpose human scores so each row is a complete set of scores across all responses
387390
all_human_scores = np.array(human_scores_list).T
388391

389-
harm_category = None
392+
dataset_harm_category = None
390393
if labeled_dataset.metrics_type == MetricsType.HARM and labeled_dataset.entries:
391394
first_entry = labeled_dataset.entries[0]
392395
if isinstance(first_entry, HarmHumanLabeledEntry):
393-
harm_category = first_entry.harm_category
394-
if harm_category is None:
396+
dataset_harm_category = first_entry.harm_category
397+
if dataset_harm_category is None:
395398
raise ValueError(
396399
"harm_category must be set in HarmHumanLabeledEntry for HARM datasets. "
397400
"Ensure all entries have a valid harm_category."
398401
)
402+
evaluation_harm_category = harm_category or dataset_harm_category
399403

400404
# Run scoring trials and measure timing
401405
all_model_scores_list = []
@@ -414,7 +418,10 @@ async def evaluate_dataset_async(
414418
total_scored_items += len(score_groups)
415419
score_values: list[bool | float] = []
416420
for index, scores in enumerate(score_groups):
417-
score = self._select_evaluation_score(scores=scores, harm_category=harm_category)
421+
score = self._select_evaluation_score(
422+
scores=scores,
423+
harm_category=evaluation_harm_category,
424+
)
418425
if score is None:
419426
determined_responses[index] = False
420427
score_values.append(False if self.expected_metrics_type == MetricsType.OBJECTIVE else 0.0)

‎tests/unit/score/test_scorer_evaluator.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,25 @@ class TestSelectEvaluationScore:
958958
def _score(*, category: list[str] | None) -> Score:
959959
return Score(score_type="float_scale", score_value="0.5", score_category=category)
960960

961+
def test_accepts_fairness_bias_score_for_representational_evaluation(self) -> None:
962+
score = self._score(category=["fairness_bias"])
963+
assert (
964+
ScorerEvaluator._select_evaluation_score(
965+
scores=[score],
966+
harm_category="REPRESENTATIONAL",
967+
)
968+
is score
969+
)
970+
971+
def test_accepts_sexual_score_for_sexual_content_evaluation(self) -> None:
972+
score = self._score(category=["sexual"])
973+
assert (
974+
ScorerEvaluator._select_evaluation_score(
975+
scores=[score],
976+
harm_category="SEXUAL_CONTENT",
977+
)
978+
is score
979+
)
961980
@pytest.mark.parametrize("category", list(AzureContentFilterScorer._CATEGORY_EVAL_FILES))
962981
@pytest.mark.parametrize("multiple_scores", [False, True])
963982
def test_azure_categories_match_registered_evaluation(self, category: TextCategory, multiple_scores: bool) -> None:

0 commit comments

Comments
 (0)