HyperAI
Back to Headlines

ConvNeXt : Le CNN Qui Défie les Transformers Visuels

il y a 17 jours

Récapitulatif de la recherche sur ConvNeXt : Une Architecture de CNN Rivalisant avec ViT En 2022, Liu et ses collaborateurs ont introduit ConvNeXt, une architecture de réseau de neurones convolutifs (CNN) qui défie les Vision Transformers (ViT) dans la publication "A ConvNet for the 2020s". Bien que les ViT aient remis en question l'efficacité des CNN traditionnels, comme ResNet, cette étude montre qu'en adaptant certaines configurations des ViT aux CNN, il est possible d'obtenir des performances comparables, voire supérieures, avec une complexité de calcul moindre. 1. L'exploration des Paramètres Hyperparamétriques Les auteurs de ConvNeXt ont appliqué une série de modifications à l'architecture ResNet pour améliorer ses performances. Ils ont expérimenté cinq aspects principaux : la conception macro, ResNeXt, le flacon inversé, les grandes tailles de noyau et la conception micro. Conception Macro : - Changement du Rapport des Stages : Les chercheurs ont ajusté le rapport des stages de ResNet-50 à 1:1:3:1, similaire à celui de Swin-T, ce qui a permis une amélioration de l'exactitude de 0,6% (de 78,8% à 79,4%). - Modification de la Couche de Convolution Initiale : En s'inspirant de ViT, ils ont modifié la première couche de convolution de ResNet avec un noyau de 4x4 et un décalage de 4. Cette modification a légèrement amélioré l'exactitude à 79,5%. Adoption de ResNeXt : - Utilisation de Convolutions de Groupe : Les auteurs ont appliqué la convolution de groupe, également connue sous le nom de convolution profonde (depthwise convolution), dans les blocs bottleneck. Cela a réduit l'exactitude à 78,3% mais a diminué la complexité computationnelle. - Élargissement de la Largeur du Modèle : Les auteurs ont ensuite augmenté la largeur du modèle en utilisant plus de canaux, suivant la configuration de Swin-T. Cette modification a considérablement amélioré l'exactitude à 80,5%. Flacon Inversé : - Structure Inversée : Les blocs ConvNeXt ont adopté une structure de type flacon inversé (narrow → wide → narrow) inspirée de l'architecture des Transformers. Cette structure a légèrement amélioré l'exactitude à 80,6%. Grandes Tailles de Noyau : - Positionnement de la Convolution Profonde : En plaçant la convolution profonde au début du bloc, l'accuracy a baissé à 79,9%, mais cette configuration a permis d'effectuer des expériences sur la taille du noyau. - Taille de Noyau 7x7 : En utilisant un noyau de 7x7 pour la convolution profonde, ils ont récupéré l'exactitude de 80,6% avec une complexité computationnelle inférieure (4,6 vs 4,2 GFLOPS). Conception Micro : - Remplacement de ReLU par GELU : Le changement de l'activation ReLU par GELU n'a pas affecté l'exactitude (reste à 80,6%). - Réduction des Fonctions d'Activation : En plaçant GELU seulement entre les deux convolutions ponctuelles (1x1), l'exactitude a augmenté à 81,3%, alignant ConvNeXt à Swin-T. - Normalisation de Batch : En remplaçant la normalisation de batch par une seule couche de norme avant la première convolution ponctuelle, l'exactitude est passée à 81,4%. - Normalisation de Calque : En substituant la normalisation de batch par une norme de calque, l'accuracy a encore augmenté à 81,5%. - Couche de Flottaison Séparée : L'utilisation de couches de flottaison séparées à chaque transition de stage a amélioré l'exactitude finale à 82,0%. 2. Détails de l'Architecture ConvNeXt ConvNeXt comprend plusieurs modifications clés qui le distinguent des architectures traditionnelles de ResNet et de ViT : Blocs ConvNeXt : - Convolutions Proiples : La structure de chaque bloc ConvNeXt suit un schéma de type flacon inversé. - Couche de Projection : Utilisée uniquement dans les transitions de stage pour ajuster la dimension de la connexion résiduelle. Implémentation des Blocs ConvNeXt : - Première Couche : Convolution profonde (7x7) avec un noyau de 4x4 et un décalage de 4, suivie de layer norm. - Blocs Principaux : Enchaînement de convolutions ponctuelles (1x1) et de fonction d'activation GELU. Transitions Entre Stages : - Downsampling : Réduire les dimensions spatiales par 2 sans perdre d'information en utilisant des convolutions supplémentaires et des normes de calque. 3. Implémentation de ConvNeXt avec PyTorch Pour faciliter la compréhension de l'architecture ConvNeXt, nous allons implémenter une version simplifiée de ConvNeXt-T avec PyTorch. Importation des Modules : python import torch import torch.nn as nn Bloc ConvNeXt : ```python class ConvNeXtBlock(nn.Module): def init(self, num_channels): super().init() hidden_channels = num_channels * 4 self.conv0 = nn.Conv2d(in_channels=num_channels, out_channels=num_channels, kernel_size=7, stride=1, padding=3, groups=num_channels) self.norm = nn.LayerNorm(normalized_shape=num_channels) self.conv1 = nn.Conv2d(in_channels=num_channels, out_channels=hidden_channels, kernel_size=1, stride=1, padding=0) self.gelu = nn.GELU() self.conv2 = nn.Conv2d(in_channels=hidden_channels, out_channels=num_channels, kernel_size=1, stride=1, padding=0) def forward(self, x): residual = x x = self.conv0(x) x = x.permute(0, 2, 3, 1) x = self.norm(x) x = x.permute(0, 3, 1, 2) x = self.conv1(x) x = self.gelu(x) x = self.conv2(x) x = x + residual return x ``` Bloc de Transition ConvNeXt : ```python class ConvNeXtBlockTransition(nn.Module): def init(self, in_channels, out_channels): super().init() hidden_channels = out_channels * 4 self.projection = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=2, padding=0) self.conv0 = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=7, stride=1, padding=3, groups=in_channels) self.norm0 = nn.LayerNorm(normalized_shape=out_channels) self.conv1 = nn.Conv2d(in_channels=out_channels, out_channels=hidden_channels, kernel_size=1, stride=1, padding=0) self.gelu = nn.GELU() self.conv2 = nn.Conv2d(in_channels=hidden_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0) self.norm1 = nn.LayerNorm(normalized_shape=out_channels) self.downsample = nn.Conv2d(in_channels=out_channels, out_channels=out_channels, kernel_size=2, stride=2) def forward(self, x): residual = self.projection(x) x = self.conv0(x) x = x.permute(0, 2, 3, 1) x = self.norm0(x) x = x.permute(0, 3, 1, 2) x = self.conv1(x) x = self.gelu(x) x = self.conv2(x) x = x.permute(0, 2, 3, 1) x = self.norm1(x) x = x.permute(0, 3, 1, 2) x = self.downsample(x) x = x + residual return x ``` Architecture Complète ConvNeXt-T : ```python IN_CHANNELS = 3 IMAGE_SIZE = 224 NUM_BLOCKS = [3, 3, 9, 3] OUT_CHANNELS = [96, 192, 384, 768] NUM_CLASSES = 1000 class ConvNeXt(nn.Module): def init(self): super().init() self.stem = nn.Conv2d(in_channels=IN_CHANNELS, out_channels=OUT_CHANNELS[0], kernel_size=4, stride=4) self.normstem = nn.LayerNorm(normalized_shape=OUT_CHANNELS[0]) self.res2 = nn.ModuleList([ConvNeXtBlock(num_channels=OUT_CHANNELS[0]) for _ in range(NUM_BLOCKS[0])]) self.res3 = nn.ModuleList([ConvNeXtBlockTransition(in_channels=OUT_CHANNELS[0], out_channels=OUT_CHANNELS[1])] + [ConvNeXtBlock(num_channels=OUT_CHANNELS[1]) for _ in range(NUM_BLOCKS[1]-1)]) self.res4 = nn.ModuleList([ConvNeXtBlockTransition(in_channels=OUT_CHANNELS[1], out_channels=OUT_CHANNELS[2])] + [ConvNeXtBlock(num_channels=OUT_CHANNELS[2]) for _ in range(NUM_BLOCKS[2]-1)]) self.res5 = nn.ModuleList([ConvNeXtBlockTransition(in_channels=OUT_CHANNELS[2], out_channels=OUT_CHANNELS[3])] + [ConvNeXtBlock(num_channels=OUT_CHANNELS[3]) for _ in range(NUM_BLOCKS[3]-1)]) self.avgpool = nn.AdaptiveAvgPool2d(output_size=(1,1)) self.normpool = nn.LayerNorm(normalized_shape=OUT_CHANNELS[3]) self.fc = nn.Linear(in_features=OUT_CHANNELS[3], out_features=NUM_CLASSES) self.relu = nn.ReLU() def forward(self, x): x = self.relu(self.stem(x)) x = x.permute(0, 2, 3, 1) x = self.normstem(x) x = x.permute(0, 3, 1, 2) for block in self.res2: x = block(x) for block in self.res3: x = block(x) for block in self.res4: x = block(x) for block in self.res5: x = block(x) x = self.avgpool(x) x = x.permute(0, 2, 3, 1) x = self.normpool(x) x = x.permute(0, 3, 1, 2) x = x.reshape(x.shape[0], -1) x = self.fc(x) return x ``` Test de l'Implémentation : python convnext_test = ConvNeXt() x_test = torch.rand(1, IN_CHANNELS, IMAGE_SIZE, IMAGE_SIZE) out_test = convnext_test(x_test) print(out_test.size()) # torch.Size([1, 1000]) 4. Évaluation et Impact Industriel L'étude de ConvNeXt a suscité un intérêt considérable dans l'industrie car elle démontre que les CNN, malgré leur ancienneté, peuvent toujours rivaliser avec les architectures plus récentes comme les ViT. Cela ouvre la voie à une intégration plus large de ConvNeXt dans des applications pratiques qui nécessitent des modèles performants et efficaces en termes de calcul. Profil de l'Entreprise : Meta, qui se distingue par ses contributions innovantes dans la recherche en IA, a soutenu cette initiative. Grâce à leurs ressources, ils ont pu effectuer une analyse approfondie et fournir une implémentation robuste de ConvNeXt, accessible via leur dépôt GitHub. Conclusion : ConvNeXt représente une avancée significative dans le domaine des CNN, montrant que la performance n'est pas uniquement liée à l'architecture, mais aussi aux configurations fines d'un modèle. Cette découverte encourage les ingénieurs et les chercheurs à revoir les configurations standard des modèles CNN existants, offrant potentiellement des améliorations substantielles sans la nécessité d'une nouvelle architecture fondamentale. Vérifiez le dépôt GitHub de Meta [2] pour une implémentation plus approfondie et la notebook complet [7] pour une compréhension pratique.

Related Links

Towards Data Science