| """Evaluate multi-positive bidirectional retrieval and visualize similarities.""" |
|
|
| import argparse |
| import json |
| from pathlib import Path |
| import matplotlib.pyplot as plt |
| import numpy as np |
| import yaml |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
|
|
|
|
| def recall(scores, query_ids, candidate_ids, k): |
| top = np.argsort(-scores, axis=1)[:, :min(k, scores.shape[1])] |
| return float(np.mean([np.isin(candidate_ids[index], query_ids[row]).any() for row, index in enumerate(top)])) |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--config", type=Path, default=ROOT / "conf/config.yaml") |
| parser.add_argument("--input", type=Path); parser.add_argument("--output-dir", type=Path) |
| args = parser.parse_args(); config = yaml.safe_load(args.config.read_text()) |
| source = args.input or ROOT / config["paths"]["inference_dir"] / "retrieval.npz" |
| if not source.is_file(): raise FileNotFoundError("Run inference before evaluation") |
| archive = np.load(source); scores, ids = archive["similarities"], archive["pair_ids"] |
| metrics = {} |
| for k in (1, 5, 10): |
| metrics[f"image_to_text_R@{k}"] = recall(scores, ids, ids, k) |
| metrics[f"text_to_image_R@{k}"] = recall(scores.T, ids, ids, k) |
| metrics["mean_recall"] = float(np.mean(list(metrics.values()))) |
| metrics.update(samples=int(len(ids)), protocol=str(archive["protocol"]), checkpoint=str(archive["checkpoint"]), |
| multi_positive=True, data_source=str(archive["data_source"])) |
| output = args.output_dir or ROOT / config["paths"]["evaluation_dir"]; output.mkdir(parents=True, exist_ok=True) |
| (output / "metrics.json").write_text(json.dumps(metrics, indent=2) + "\n") |
| figure, axis = plt.subplots(figsize=(5.4, 4.5)); image = axis.imshow(scores, cmap="magma") |
| axis.set(xlabel="Text candidate", ylabel="Image query", title="RemoteCLIP cosine similarity") |
| figure.colorbar(image, ax=axis); figure.tight_layout(); figure.savefig(output / "similarity_matrix.png", dpi=160); plt.close(figure) |
| print(json.dumps(metrics, indent=2)); print(f"evaluation={output}") |
|
|
|
|
| if __name__ == "__main__": main() |
|
|