CHAIR Hallucination Rate
Problem Statement
Given the object words a VLM produced for each image and the ground-truth objects actually present, compute the two CHAIR hallucination rates and list which objects were hallucinated.
Background
CHAIR (Caption Hallucination Assessment with Image Relevance) measures how often a captioner names objects that are not in the image. It has two variants:
CHAIR_i is instance-level (how noisy is the average mention) and CHAIR_s is sentence-level (what fraction of outputs are contaminated at all). CHAIR_s is always at least as alarming as CHAIR_i, because one bad word condemns a whole caption.
Three details are load-bearing:
- Synonym mapping. Raw caption words are mapped to canonical MSCOCO categories - "man", "woman", "person" all map to person. Words absent from the map are not object mentions at all and are simply dropped.
- Deduplicate within a caption. A caption saying "dog" twice mentions one object. Deduplicate after mapping, per caption, so "man" and "woman" in the same sentence count once.
- Order. The hallucinated-object list you return must be sorted alphabetically, and unique. A raw Python set has no defined iteration order, so sort it before returning - the same trap that makes hallucination-eval scripts produce different output on different runs.
Your Task
Implement:
def chair_metrics(captions, ground_truth, synonym_map):
Return [chair_i, chair_s, hallucinated_objects] where the first two are floats rounded to 4 decimals and the third is a sorted list of the unique canonical object names that were hallucinated anywhere in the dataset.
Input Format
- captions - list of n lists of raw word strings, one list per image
- ground_truth - list of n lists of canonical object names present in that image
- synonym_map - dict mapping a raw word to its canonical object name
Output Format
[float, float, [str, ...]]
Sample
caps = [["a", "man", "riding", "a", "horse"], ["dog", "dog", "frisbee"]]
gt = [["person", "horse"], ["dog"]]
syn = {"man": "person", "woman": "person", "horse": "horse", "dog": "dog", "frisbee": "frisbee"}
print(chair_metrics(caps, gt, syn))
Output:
[0.25, 0.5, ['frisbee']]
Example
caps = [["a", "man", "riding", "a", "horse"], ["dog", "dog", "frisbee"]]
gt = [["person", "horse"], ["dog"]]
syn = {"man": "person", "woman": "person", "horse": "horse", "dog": "dog", "frisbee": "frisbee"}
print(chair_metrics(caps, gt, syn))[0.25, 0.5, ['frisbee']]
Caption 1 mentions person and horse, both present. Caption 2 mentions dog (twice, counted once) and frisbee, which is absent. That is 1 hallucination out of 4 mentions = 0.25, and 1 of 2 captions contaminated = 0.5.
Constraints
- Map every word through
synonym_map; words that are not keys are NOT object mentions - Deduplicate canonical objects WITHIN each caption, after mapping
chair_idivides by the total number of (deduplicated) mentions across all captionschair_sdivides by the number of captions- The returned object list must be UNIQUE and SORTED alphabetically - never return a raw
set - Return
0.0forchair_iwhen there are no mentions at all - Round both rates to 4 decimals