File size: 1,863 Bytes
a745a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import os
from typing import Any

from PIL import Image
from pycocoevalcap.cider.cider import Cider
from tqdm import tqdm


def generate_caption(model: Any, processor: Any, image: Image.Image, device) -> str:
    """
    Run the captioning model on a single image and return the decoded caption.
    """
    inputs = processor(images=image, return_tensors="pt").to(device)

    with getattr(__import__("torch"), "no_grad")():
        torch = __import__("torch")
        generated_ids = model.generate(
            **inputs,
            max_length=30,
            num_beams=5,
        )

    caption = processor.decode(
        generated_ids[0],
        skip_special_tokens=True,
    )
    return caption


def evaluate_cider(model: Any, processor: Any, val_dataset, device, max_samples: int = 200) -> float:
    """
    Compute CIDEr score on a validation subset.

    Expects a PyTorch `Subset`/`Dataset` where:
    - `val_dataset.indices[idx]` gives the underlying index
    - `val_dataset.dataset.annotations[...]` is a list of dicts with
      keys `image` and `captions`.
    """
    import torch  # local import to avoid hard dependency for non-training paths

    model.eval()

    cider_scorer = Cider()
    ground_truth = {}
    predictions = {}

    for idx in tqdm(range(min(max_samples, len(val_dataset))), desc="CIDEr Eval"):
        real_idx = val_dataset.indices[idx]
        ann = val_dataset.dataset.annotations[real_idx]

        image_path = os.path.join("train2017", ann["image"])
        image = Image.open(image_path).convert("RGB")

        pred_caption = generate_caption(model, processor, image, device)

        ground_truth[idx] = ann["captions"]
        predictions[idx] = [pred_caption]

    score, _ = cider_scorer.compute_score(ground_truth, predictions)

    print(f"CIDEr Score: {score:.4f}")

    model.train()
    return score