Welcome to the AAPB Evaluations repository! This guide will help you understand how to contribute new evaluation tasks for CLAMS applications.
This repository provides a framework for evaluating the performance of CLAMS apps in various metadata extraction tasks on AAPB-based datasets. Primary component you can contribute is evaluate.py scripts within each evaluation task directory. Each script is responsible for processing gold standard annotations and CLAMS app outputs, calculating relevant metrics, and generating comprehensive reports.
At the heart of every evaluate.py is the ClamsAAPBEvaluationTask abstract base class (ABC) defined in common/__init__.py. This class provides the foundational structure and common utilities needed to develop new evaluation tasks, including:
- Standardized Input Handling: Mechanisms to locate and process gold standard (human-annotated) files and prediction (CLAMS app/workflow output) files.
- Metric Calculation Orchestration: A workflow for comparing gold and prediction data, calculating relevant metrics.
- Report Generation: Tools to automatically generate formatted Markdown reports summarizing evaluation results.
The common package also provides shared utilities:
common/metrics.py: Wrappers around evaluation metrics fromsklearnandjiwer, includingprecision_recall_fscore,wer/cer, and metric key constants (MACRO_AVG_PRECISION,MACRO_AVG_RECALL,MACRO_AVG_F1).common/helpers.py: Utility functions for timestamp and range matching, such asmatch_nearest_pointsandfind_range_index.
See the docstrings in each module for detailed signatures and usage.
To contribute a new evaluation, create a new Python module (e.g., YourEvaluationTask/evaluate.py) that subclasses ClamsAAPBEvaluationTask and implements its abstract methods. See TimePointLabeling/evaluate.py as a reference implementation.
from common import ClamsAAPBEvaluationTask
class YourEvaluationTask(ClamsAAPBEvaluationTask):
"""
Describe what this evaluation task assesses, the metrics
used, and any configurable behavior.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)The class docstring is rendered verbatim in the "Evaluation method" section of the generated Markdown report. Write it as user-facing documentation using Markdown formatting — describe the methodology, metrics, and any configurable behavior.
You must implement the following methods. See the docstrings in common/__init__.py for detailed parameter and return type documentation.
_read_gold(self, gold_file, **kwargs): Read a single gold standard file and return processed data suitable for comparison._read_pred(self, pred_file, gold, **kwargs): Read a prediction MMIF file and return a(pred, updated_gold)tuple. Thegoldparameter is the output of_read_goldfor the same GUID. When your task requires aligning gold and prediction data (e.g., matching timestamps), return the aligned gold as the second element — it will replace the original gold passed to_compare_pair. ReturnNoneas the second element if gold needs no modification._compare_pair(self, guid, gold, pred): Calculate evaluation metrics for a single document._compare_all(self, golds, preds): Calculate aggregate metrics across all documents (used whenby_guid=False). RaiseNotImplementedErrorif your task only supports per-GUID evaluation.
You must implement _finalize_results(self), which is called automatically by write_report() before rendering. This method aggregates per-GUID results into a final form suitable for the report.
The data flow is:
_compare_pairstores per-GUID metrics inself._calculations(adictkeyed by GUID)._finalize_resultsreads fromself._calculations, computes aggregates (e.g., an overall average row), and writes the final output toself._results.write_report()rendersself._resultsin the report. The type ofself._resultsdetermines the rendering format — see the_finalize_resultsandwrite_reportdocstrings for supported types.
The base class supports two optional report sections — a confusion matrix and a side-by-side view — controlled by constructor kwargs cf and sbs. Pass these in your __init__ before calling super().__init__():
def __init__(self, batchname, **kwargs):
# enable confusion matrix in the report
super().__init__(batchname, cf=True, **kwargs)cf=True: Appends a "Confusion Matrix" section by callingwrite_confusion_matrix().sbs=True: Appends a "Side-by-side view" section by callingwrite_side_by_side_view().
Both methods are abstract. Every subclass must implement them, even when the evaluation doesn't use that format — in which case, raise NotImplementedError. Each method should return a Markdown-formatted string.
For classification tasks where gold and prediction label vocabularies differ, the base class provides label mapping infrastructure through CLI arguments, a parsing helper, and automatic report rendering.
The prep_argparser() method adds three label-related CLI arguments:
--label-map: Space-separated mappings. Supports identity format (A B C) and explicit mapping (A:x B:x C:y). Target values are automatically identity-mapped to handle predictions using pre-collapsed labels.--label-map-json: JSON string alternative, mutually exclusive with--label-map.--default-label: Fallback label for unmapped entries (default:"-").
Use parse_label_map_args(args) to convert parsed CLI args into a normalized dict, then pass it to your evaluator's constructor:
args = parser.parse_args()
label_map = YourEvaluationTask.parse_label_map_args(args)
evaluator = YourEvaluationTask(
batchname=args.batchname,
label_map=label_map,
default_label=args.default_label,
...
)When a label map is present, write_report() automatically includes the full mapping table in the report.
To surface other task-specific settings in the report (e.g., matching tolerance, thresholds), populate a self._eval_config dict in your __init__:
self._eval_config = {'Timestamp matching tolerance': '5ms'}Each key-value pair is rendered as a bullet in the "Data and Evaluation Specs" section.
The ClamsAAPBEvaluationTask provides a default argument parser via prep_argparser(). Call this method and add task-specific arguments:
if __name__ == '__main__':
parser = YourEvaluationTask.prep_argparser()
parser.add_argument('--my-param', type=int, help='...')
args = parser.parse_args()
label_map = YourEvaluationTask.parse_label_map_args(args)
eval_task = YourEvaluationTask(
batchname=args.batchname,
gold_loc=args.golds,
pred_loc=args.preds,
label_map=label_map,
default_label=args.default_label,
)
eval_task.calculate_metrics(by_guid=True)
report = eval_task.write_report()
args.export.write(report.getvalue())Common arguments provided by the base class:
-p,--preds: Directory containing prediction MMIF files.-g,--golds: Directory containing gold standard files.-e,--export: Filename to export the Markdown report (defaults to stdout).-b,--batchname: Batch name from theaapb-annotationsrepository.--source-directory: Optional directory for original source files.--label-map,--label-map-json,--default-label: Label remapping options (see Section 5).
- Gold files: Typically
.tsv,.csv, or.txtfiles. The_read_goldmethod in your subclass will interpret these. - Prediction files: Always
.mmiffiles (or rarely.json) generated by CLAMS workflows. The_read_predmethod will parse these.
The write_report() method automatically generates a Markdown report including:
- Evaluation task name and timestamp.
- Class docstring as the evaluation method description.
- Data and evaluation specs (batch name, gold location, code version, label mapping,
_eval_configentries). - Workflow specs (CLAMS workflow ID and app profilings).
- Raw results (rendering depends on
self._resultstype — see Section 3). - Optional confusion matrix and/or side-by-side view (see Section 4).
The framework automatically includes the git commit hash of your evaluation script in the report, indicating whether the code is "dirty" (has uncommitted changes) or a specific commit. Ensure your evaluation scripts are part of a git repository for accurate version tracking.
- Modularity: Keep your
_read_gold,_read_pred,_compare_pair, and_compare_allmethods focused on their specific tasks. - Error handling: Implement robust error handling within your
_read_predmethod, especially for parsing potentially malformed MMIF files. Warnings for skipped GUIDs are automatically handled by the framework. - Documentation: Write your class docstring as user-facing methodology documentation. Document
_read_goldand_read_predto explain expected data formats. - Testing: Ensure you write unit tests for your custom
_read_gold,_read_pred, and_comparemethods.
By following these guidelines, you can effectively contribute new and robust evaluation tasks to the AAPB Evaluations project.