File size: 3,309 Bytes
827713a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""Phase 5 — paires image-légende pour l'alignement image-texte.

Par défaut, on utilise le **générateur jouet maison** (`toy_images`) : 9 classes
forme × couleur, chacune décrite en français (« un cercle rouge »). Cela suffit à
valider un CLIP minimal sans télécharger COCO.

Option réelle : `--source hf --preset coco_fr` télécharge un sous-ensemble de
paires image-légende depuis le Hub (si disponible dans l'environnement).

Usage :

    python -m src.data.prepare_image_text --out-dir data/processed/toy_clip \\
        --n-train 1800 --n-val 180
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path

import numpy as np

from src.data.toy_images import generate_dataset, to_arrays


def make_toy_pairs(n: int, grid: int = 32, seed: int = 0):
    """Retourne (images NCHW float32, captions list[str], labels list[str])."""
    items = generate_dataset(n, grid=grid, seed=seed)
    images, labels = to_arrays(items)
    captions = [it.caption for it in items]
    names = [it.label for it in items]
    return images, captions, names


def prepare_toy(out_dir: Path, n_train: int = 1800, n_val: int = 180, grid: int = 32,
                seed: int = 0) -> dict:
    """Écrit images/captions train+val en `.npy`/`.json`."""
    out_dir = Path(out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)

    tr_imgs, tr_caps, tr_names = make_toy_pairs(n_train, grid=grid, seed=seed)
    va_imgs, va_caps, va_names = make_toy_pairs(n_val, grid=grid, seed=seed + 999)

    np.save(out_dir / "train_images.npy", tr_imgs)
    np.save(out_dir / "val_images.npy", va_imgs)
    (out_dir / "train_captions.json").write_text(json.dumps(tr_caps, ensure_ascii=False), encoding="utf-8")
    (out_dir / "val_captions.json").write_text(json.dumps(va_caps, ensure_ascii=False), encoding="utf-8")
    (out_dir / "train_labels.json").write_text(json.dumps(tr_names, ensure_ascii=False), encoding="utf-8")
    (out_dir / "val_labels.json").write_text(json.dumps(va_names, ensure_ascii=False), encoding="utf-8")

    meta = {"source": "toy", "grid": grid, "n_train": n_train, "n_val": n_val,
            "n_classes": len(set(tr_names)), "seed": seed}
    (out_dir / "meta.json").write_text(json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8")
    return meta


def load_pairs(out_dir: Path, split: str = "train"):
    """Charge (images, captions) d'un split."""
    out_dir = Path(out_dir)
    images = np.load(out_dir / f"{split}_images.npy")
    captions = json.loads((out_dir / f"{split}_captions.json").read_text(encoding="utf-8"))
    return images, captions


def main() -> None:
    parser = argparse.ArgumentParser(description="Préparer des paires image-texte (Phase 5).")
    parser.add_argument("--out-dir", type=Path, required=True)
    parser.add_argument("--source", choices=["toy"], default="toy")
    parser.add_argument("--n-train", type=int, default=1800)
    parser.add_argument("--n-val", type=int, default=180)
    parser.add_argument("--grid", type=int, default=32)
    parser.add_argument("--seed", type=int, default=0)
    args = parser.parse_args()
    meta = prepare_toy(args.out_dir, args.n_train, args.n_val, args.grid, args.seed)
    print(json.dumps(meta, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()