File size: 5,601 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 | """
models/cnn.py
CNN pour images RGB 3 canaux β Intel Image Classification (228Γ228, 6 classes).
RΓGLE DE NORMALISATION :
La normalisation est faite UNIQUEMENT dans utils/prep.py (pipeline de donnΓ©es).
Les modΓ¨les reΓ§oivent des images dΓ©jΓ normalisΓ©es β il n'y a PAS de couche
Rescaling à l'intérieur des modèles. Cela garantit un comportement identique
entre training, evaluation et production (Flask).
"""
# ββ PyTorch βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import torch.nn as nn
import torch.nn.functional as F
class CNN_Torch(nn.Module):
"""
CNN PyTorch 4 blocs pour images RGB (3 canaux, 150Γ150).
EntrΓ©e : (B, 3, 150, 150) β normalisΓ©e ImageNet (mean/std)
Sortie : (B, num_classes) β logits bruts (CrossEntropyLoss)
Architecture :
Block 1 : Conv(3β32)Γ2 + BN + ReLU + MaxPool(2) 150β75
Block 2 : Conv(32β64)Γ2 + BN + ReLU + MaxPool(2) + Drop2d 75β37
Block 3 : Conv(64β128)Γ2 + BN + ReLU + MaxPool(2) + Drop2d 37β18
Block 4 : Conv(128β256)Γ2+ BN + ReLU + MaxPool(2) + Drop2d 18β9
GAP : AdaptiveAvgPool2d(1) β(B,256)
Head : Linear(256β256) + ReLU + Dropout + Linear(256βC)
"""
def __init__(self, num_classes: int = 6):
super().__init__()
self.features = nn.Sequential(
# Block 1 β 150Γ150 β 75Γ75
nn.Conv2d(3, 32, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(32), nn.ReLU(inplace=True),
nn.Conv2d(32, 32, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(32), nn.ReLU(inplace=True),
nn.MaxPool2d(2),
# Block 2 β 75Γ75 β 37Γ37
nn.Conv2d(32, 64, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(64), nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(64), nn.ReLU(inplace=True),
nn.MaxPool2d(2), nn.Dropout2d(0.10),
# Block 3 β 37Γ37 β 18Γ18
nn.Conv2d(64, 128, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(128), nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(128), nn.ReLU(inplace=True),
nn.MaxPool2d(2), nn.Dropout2d(0.15),
# Block 4 β 18Γ18 β 9Γ9
nn.Conv2d(128, 256, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(256), nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(256), nn.ReLU(inplace=True),
nn.MaxPool2d(2), nn.Dropout2d(0.20),
)
# (B,256,9,9) β (B,256,1,1) β (B,256)
self.gap = nn.AdaptiveAvgPool2d(1)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(256, 256),
nn.ReLU(inplace=True),
nn.Dropout(0.30),
nn.Linear(256, num_classes),
)
def forward(self, x):
return self.classifier(self.gap(self.features(x)))
# ββ TensorFlow / Keras ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def build_cnn_tf(num_classes: int = 6, input_shape: tuple = (228, 228, 3)):
"""
CNN TF reproduisant l'architecture du notebook de rΓ©fΓ©rence hassanraof.
Source : https://www.kaggle.com/code/hassanraof/intel-image-classification
EntrΓ©e : (B, 228, 228, 3) β valeurs [0, 1] normalisΓ©es par prep.py
Sortie : (B, num_classes) β softmax
Architecture (5 blocs conv) :
Block 1 : Conv(32, 5Γ5) β ReLU β MaxPool(2,2)
Block 2 : Conv(32, 5Γ5) β ReLU β MaxPool(2,2)
Block 3 : Conv(32, 3Γ3) β ReLU β MaxPool(2,2)
Block 4 : Conv(64, 3Γ3) β ReLU β MaxPool(2,2)
Block 5 : Conv(64, 3Γ3) β ReLU β MaxPool(2,2)
Head : Flatten β Dense(1024) β Dropout(0.20)
β Dense(124) β Dropout(0.20)
β Dense(num_classes, softmax)
β οΈ PAS de couche Rescaling ici β la normalisation est faite dans prep.py.
Ajouter Rescaling ici causerait une double normalisation.
"""
from tensorflow.keras import layers, models
return models.Sequential([
layers.Input(shape=input_shape),
# β PAS de Rescaling ici
# Block 1
layers.Conv2D(32, kernel_size=(5, 5), activation="relu"),
layers.MaxPooling2D(2, 2),
# Block 2
layers.Conv2D(32, kernel_size=(5, 5), activation="relu"),
layers.MaxPooling2D(2, 2),
# Block 3
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(2, 2),
# Block 4
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(2, 2),
# Block 5
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(2, 2),
# Head
layers.Flatten(),
layers.Dense(1024, activation="relu"),
layers.Dropout(0.20),
layers.Dense(124, activation="relu"),
layers.Dropout(0.20),
layers.Dense(num_classes, activation="softmax"),
], name="CNN_TF_hassanraof")
|