File size: 5,955 Bytes
7902c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

# ══════════════════════════════════════════════════════════════════════════════
# PYTORCH β€” Transforms & DataLoaders
# ══════════════════════════════════════════════════════════════════════════════
def get_pytorch_transforms(img_size: int = 150):
    """
    Retourne (train_transform, val_transform).
    Augmentation scène-aware pour le dataset Intel (6 classes naturelles RGB).
    """
    from torchvision import transforms

    # Statistiques ImageNet β€” optimal pour images naturelles RGB 3 canaux
    MEAN = [0.485, 0.456, 0.406]
    STD  = [0.229, 0.224, 0.225]

    train_transform = transforms.Compose([
        transforms.Resize((img_size, img_size)),
        transforms.RandomHorizontalFlip(p=0.5),
        transforms.RandomVerticalFlip(p=0.1),
        transforms.RandomRotation(degrees=40),
        transforms.ColorJitter(
            brightness=0.3, contrast=0.2, saturation=0.1, hue=0.05
        ),
        transforms.RandomGrayscale(p=0.05),
        transforms.ToTensor(),
        transforms.Normalize(MEAN, STD),      # ← normalisation ici, pas dans le modΓ¨le
        transforms.RandomErasing(p=0.15, scale=(0.02, 0.15)),
    ])

    val_transform = transforms.Compose([
        transforms.Resize((img_size, img_size)),
        transforms.ToTensor(),
        transforms.Normalize(MEAN, STD),      # ← mΓͺme normalisation en val/test
    ])

    return train_transform, val_transform


def get_pytorch_loaders(
    train_dir: str,
    test_dir:  str,
    img_size:  int = 150,
    batch_size: int = 64,
):
    from torch.utils.data import DataLoader
    from torchvision import datasets

    train_tf, val_tf = get_pytorch_transforms(img_size)

    train_loader = DataLoader(
        datasets.ImageFolder(train_dir, transform=train_tf),
        batch_size=batch_size, shuffle=True,
        num_workers=2, pin_memory=True,
    )
    test_loader = DataLoader(
        datasets.ImageFolder(test_dir, transform=val_tf),
        batch_size=batch_size, shuffle=False,
        num_workers=2, pin_memory=True,
    )
    return train_loader, test_loader


# ══════════════════════════════════════════════════════════════════════════════
# TENSORFLOW β€” Dataset pipeline
# ══════════════════════════════════════════════════════════════════════════════
def get_tf_datasets(
    train_dir: str,
    test_dir: str,
    img_size: int = 228,
    batch_size: int = 64,
):
    import tensorflow as tf

    # Same preprocessing as in the notebook
    norm_layer = tf.keras.layers.Rescaling(1.0 / 255.0)

    # ── Raw loading ──────────────────────────────────────────────────────────
    train_ds = tf.keras.utils.image_dataset_from_directory(
        train_dir,
        seed=123,
        image_size=(img_size, img_size),
        batch_size=batch_size,
        shuffle=True,
        label_mode="int",
    )

    test_ds = tf.keras.utils.image_dataset_from_directory(
        test_dir,
        seed=123,
        image_size=(img_size, img_size),
        batch_size=batch_size,
        shuffle=False,
        label_mode="int",
    )

    # ── Normalization only ───────────────────────────────────────────────────
    train_ds = train_ds.map(
        lambda x, y: (norm_layer(x), y),
        num_parallel_calls=tf.data.AUTOTUNE
    )

    test_ds = test_ds.map(
        lambda x, y: (norm_layer(x), y),
        num_parallel_calls=tf.data.AUTOTUNE
    )

    # ── Performance ──────────────────────────────────────────────────────────
    train_ds = train_ds.prefetch(tf.data.AUTOTUNE)
    test_ds = test_ds.prefetch(tf.data.AUTOTUNE)

    return train_ds, test_ds

# ══════════════════════════════════════════════════════════════════════════════
# INFÉRENCE — Preprocessing image unique (Flask / production)
# ══════════════════════════════════════════════════════════════════════════════
def preprocess_image_pytorch(pil_img, img_size: int = 150):
    """PrΓ©pare une image PIL pour l'infΓ©rence PyTorch. Retourne (1,3,H,W)."""
    import torch
    from torchvision import transforms

    tf = transforms.Compose([
        transforms.Resize((img_size, img_size)),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
    ])
    return tf(pil_img).unsqueeze(0)


def preprocess_image_tf(pil_img, img_size: int = 150):
    """
    PrΓ©pare une image PIL pour l'infΓ©rence TensorFlow. Retourne (1,H,W,3).
    Normalisation identique au pipeline val/test : Γ·255 β†’ [0,1].
    """
    import numpy as np
    arr = np.array(pil_img.resize((img_size, img_size)), dtype=np.float32)
    arr = arr / 255.0              # ← mΓͺme normalisation que normalize_only()
    return np.expand_dims(arr, 0)  # (1, H, W, 3)