Tutoriel CNN PyTorch : Construire et Entraîner des Réseaux Neuronaux Convolutifs en Python

Les réseaux de neurones convolutifs (CNN) sont un pilier de la vision par ordinateur moderne, permettant des applications telles que la reconnaissance d’images, la détection faciale et les voitures autonomes. Ces réseaux sont conçus pour extraire automatiquement des motifs et des caractéristiques des images, les rendant plus puissants que les techniques traditionnelles d’apprentissage automatique pour les tâches visuelles.

Dans ce tutoriel, nous mettrons en place un CNN en utilisant PyTorch, un framework d’apprentissage profond à la fois convivial et hautement efficace pour la recherche et les applications de production.

Prérequis : Apprentissage profond et PyTorch

Avant d’entrer dans les détails des CNN, vous devez être familier avec le domaine de l’apprentissage profond et les bibliothèques Python que nous utiliserons lors de la configuration de notre environnement.

L’apprentissage profond est une sous-catégorie de l’apprentissage automatique, où la structure fondamentale du modèle est un réseau de données d’entrée, de couches cachées et de sorties. Un tel réseau peut avoir une ou plusieurs couches cachées. L’intuition originale derrière l’apprentissage profond était de créer des modèles inspirés de la façon dont le cerveau humain apprend : à travers des cellules interconnectées appelées neurones. C’est pourquoi nous continuons à appeler les modèles d’apprentissage profond des « réseaux » neuronaux. Ces structures de modèles en couches nécessitent beaucoup plus de données pour apprendre que les autres modèles d’apprentissage supervisé afin de déduire des motifs des données non structurées. Nous parlons généralement d’au moins des centaines de milliers de points de données.

Alors qu’il existe plusieurs cadres et packages pour implémenter des algorithmes d’apprentissage profond, nous nous concentrerons sur PyTorch, l’un des cadres les plus populaires et les mieux entretenus. En plus d’être utilisé par des ingénieurs en apprentissage profond dans l’industrie, PyTorch est un outil privilégié parmi les chercheurs. De nombreux articles sur l’apprentissage profond sont publiés en utilisant PyTorch. Il est conçu pour être intuitif et convivial, partageant beaucoup de points communs avec la bibliothèque Python NumPy. 

Si vous avez besoin d’une introduction sur ces concepts, envisagez de vous inscrire au cours Deep Learning with PyTorch dès aujourd’hui. 

Qu’est-ce qu’un Réseau de Neurones Convolutionnel (CNN) ?

Les réseaux de neurones convolutionnels, communément appelés CNN ou ConvNet, sont un type spécifique de réseau de neurones profonds bien adapté aux tâches de vision par ordinateur. L’invention des CNN remonte aux années 1980. Cependant, ils ne sont devenus populaires que dans les années 2010, suite aux avancées en informatique résultant de la mise en œuvre des unités de traitement graphique (GPUs). En effet, la popularisation rapide des CNN a contribué à faire revenir au premier plan le domaine des réseaux de neurones, conduisant ainsi à la soi-disant « troisième vague des réseaux de neurones » que nous vivons encore aujourd’hui.

Les CNN sont spécifiquement inspirés par le cortex visuel biologique. Le cortex comporte de petites régions de cellules sensibles à des zones spécifiques du champ visuel. Cette idée a été élargie par une expérience captivante menée par Hubel et Wiesel en 1962.

Les CNN tentent de reproduire cette fonctionnalité en créant des réseaux neuronaux complexes composés de différentes couches spécifiques à la tâche. Les CNN sont appelés « feed-forward » car l’information circule directement à travers le modèle. Il n’y a pas de connexions de rétroaction dans lesquelles les sorties du modèle sont renvoyées dans celui-ci, par rapport à d’autres modèles qui utilisent des techniques comme la rétropropagation.

En particulier, un CNN se compose généralement des couches suivantes:

Couche de convolution

C’est le premier bloc de construction d’un CNN. Comme son nom l’indique, la tâche mathématique principale effectuée est appelée convolution, qui est l’application d’une fonction de fenêtre coulissante à une matrice de pixels représentant une image. La fonction coulissante appliquée à la matrice est appelée noyau ou filtre. Dans la couche de convolution, plusieurs filtres de taille égale sont appliqués, et chaque filtre est utilisé pour reconnaître un motif spécifique de l’image, comme la courbure des chiffres, les bords, la forme entière des chiffres, et plus encore. 

Fonction d’activation

Normalement, une fonction d’activation ReLU est appliquée après chaque opération de convolution. Cette fonction aide le réseau à apprendre des relations non linéaires entre les caractéristiques de l’image, rendant le réseau plus robuste pour identifier différents motifs. Elle aide également à atténuer les problèmes de gradient nul. 

Couche de mise en commun

Le but de la couche de pooling est d’extraire les fonctionnalités les plus significatives de la matrice convoluée. Cela est fait en appliquant des opérations d’agrégation, qui réduisent la dimension de la carte de fonctionnalités (matrice convoluée), réduisant ainsi la mémoire utilisée pendant l’entraînement du réseau. Le pooling est également pertinent pour atténuer le surajustement.

Couches entièrement connectées

Ces couches se trouvent dans la dernière couche du réseau de neurones convolutionnel, et leurs entrées correspondent à la matrice unidimensionnelle aplatie générée par la dernière couche de pooling. Des fonctions d’activation ReLU leur sont appliquées pour la non-linéarité. 

Architecture du Réseau de Neurones Convolutionnel. Source: DataCamp

Vous pouvez lire une explication plus détaillée des mathématiques derrière les CNN dans notre tutoriel, Réseaux de Neurones Convolutionnels en Python.

Pourquoi utiliser les CNN pour la classification d’images ?

Les réseaux de neurones convolutifs ont été l’une des innovations les plus influentes dans le domaine de la vision par ordinateur. Ils ont surpassé de nombreux modèles d’apprentissage automatique traditionnels, tels que les SVM et les arbres de décision, et ont produit des résultats à la pointe de la technologie.

De plus, les couches convolutives confèrent aux CNN leurs caractéristiques invariantes de translation, leur permettant d’identifier et d’extraire des motifs et des caractéristiques des données, indépendamment des variations de position, d’orientation, d’échelle ou de translation.

Les CNN se sont révélés efficaces dans de nombreuses études de cas et applications réelles, telles que :

  • La classification d’images, la détection d’objets, la segmentation, la reconnaissance faciale ;
  • Les voitures autonomes qui exploitent des systèmes de vision basés sur des CNN ;
  • La classification de structures cristallines utilisant un réseau de neurones convolutif ;
  • Les systèmes de caméras de sécurité.

Au-delà des tâches de classification d’images, les CNN sont polyvalents et peuvent être appliqués à une gamme d’autres domaines, tels que le traitement du langage naturel, l’analyse de séries temporelles et la reconnaissance vocale.

Implémentation d’un CNN avec PyTorch

Maintenant que vous êtes familiarisé avec la théorie des CNN, nous sommes prêts à passer à la pratique. Dans cette section, nous allons construire et entraîner un CNN simple avec PyTorch. Notre objectif est de construire un modèle pour classer les chiffres dans les images. Pour entraîner et tester notre modèle, nous utiliserons le célèbre ensemble de données MNIST, une collection de 70 000 images en niveaux de gris de 28×28 pixels avec des chiffres écrits à la main.

1. Importation des bibliothèques requises

Vous trouverez ci-dessous les bibliothèques que nous utiliserons pour ce tutoriel. En essence, nous utiliserons PyTorch pour construire notre CNN, et le module de vision par ordinateur de PyTorch torchvision, pour télécharger et charger l’ensemble de données MNIST. Enfin, nous utiliserons également torchmetrics pour évaluer les performances de notre modèle.

import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch from torch import optim from torch import nn from torch.utils.data import DataLoader from tqdm import tqdm # !pip install torchvision import torchvision import torch.nn.functional as F import torchvision.datasets as datasets import torchvision.transforms as transforms # !pip install torchmetrics import torchmetrics

2. Chargement et prétraitement de l’ensemble de données

PyTorch dispose également d’un riche écosystème d’outils et d’extensions, y compris torchvision, un module pour la vision par ordinateur. Torchvision inclut plusieurs ensembles de données d’images qui peuvent être utilisés pour l’entraînement et le test des réseaux neuronaux. Dans notre tutoriel, nous utiliserons l’ensemble de données MNIST. 

Tout d’abord, nous allons télécharger et convertir l’ensemble de données MNIST en un tenseur, la structure de données centrale dans PyTorch, similaire aux tableaux NumPy mais avec des capacités d’accélération GPU.

Ensuite, nous utiliserons également DataLoader pour gérer le regroupement et le mélange à la fois des ensembles de données d’entraînement et de test. Un DataLoader PyTorch peut être créé à partir d’un Dataset pour charger des données, les diviser en lots et effectuer des transformations sur les données si nécessaire. Ensuite, il renvoie un échantillon de données prêt pour l’entraînement. Dans le code ci-dessous, nous chargeons les données et les sauvegardons dans des DataLoaders avec une taille de lot de 60 images:

batch_size = 60 train_dataset = datasets.MNIST(root="dataset/", download=True, train=True, transform=transforms.ToTensor()) train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) test_dataset = datasets.MNIST(root="dataset/", download=True, train=False, transform=transforms.ToTensor()) test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

Éventuellement, l’ensemble de données d’entraînement pourrait être encore divisé en deux partitions d’entraînement et de validation. La validation est une technique utilisée en apprentissage profond pour évaluer la performance du modèle pendant l’entraînement. Cela aide à détecter le surajustement potentiel et le sous-ajustement de nos modèles, et c’est particulièrement utile pour optimiser les hyperparamètres. Cependant, pour des raisons de simplicité, nous n’utiliserons pas de validation pour ce tutoriel. Si vous souhaitez en savoir plus sur la validation, vous pouvez consulter une explication complète dans notre Cours d’Introduction à l’Apprentissage Profond avec PyTorch.

Maintenant que nous avons nos données, voyons à quoi ressemble un lot aléatoire de chiffres:

def imshow(img): npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) plt.show() # obtenir quelques images d'entraînement aléatoires dataiter = iter(dataloader_train) images, labels = next(dataiter) labels # afficher les images imshow(torchvision.utils.make_grid(images))

3. Définition de l’architecture du CNN

Pour résoudre le problème de classification, nous utiliserons la classe nn.Module, le bloc de construction de PyTorch pour créer de manière intuitive des architectures de réseaux neuronaux sophistiquées.

Dans le code ci-dessous, nous créons une classe appelée CNN, qui hérite des propriétés de la classe nn.Module. La classe CNN sera le modèle d’un réseau de neurones convolutif avec deux couches de convolution, suivies d’une couche entièrement connectée.

En PyTorch, nous utilisons nn.Conv2d pour définir une couche de convolution. Nous lui passons le nombre de cartes de caractéristiques d’entrée et de sortie. Nous définissons également certains des paramètres pour que la couche de convolution fonctionne, y compris la taille du noyau ou du filtre et le padding.

Ensuite, nous ajoutons une couche de max pooling avec nn.MaxPool2d. Nous faisons glisser une fenêtre sans chevauchement sur la sortie de la couche de convolution précédente. À chaque position, nous sélectionnons la valeur maximale de la fenêtre pour la transmettre en avant. Cette opération réduit les dimensions spatiales des cartes de caractéristiques, réduisant le nombre de paramètres et la complexité computationnelle dans le réseau. Enfin, nous ajoutons une couche linéaire entièrement connectée.

La fonction forward() définit comment les différentes couches sont connectées, ajoutant plusieurs fonctions d’activation ReLU après chaque couche de convolution.

class CNN(nn.Module): def __init__(self, in_channels, num_classes): """ Building blocks of convolutional neural network. Parameters: * in_channels: Number of channels in the input image (for grayscale images, 1) * num_classes: Number of classes to predict. In our problem, 10 (i.e digits from 0 to 9). """ super(CNN, self).__init__() # 1ère couche convolutive self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=8, kernel_size=3, padding=1) # Couche de pooling maximale self.pool = nn.MaxPool2d(kernel_size=2, stride=2) # 2ème couche convolutive self.conv2 = nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3, padding=1) # Couche entièrement connectée self.fc1 = nn.Linear(16 * 7 * 7, num_classes) def forward(self, x): """ Define the forward pass of the neural network. Parameters: x: Input tensor. Returns: torch.Tensor The output tensor after passing through the network. """ x = F.relu(self.conv1(x)) # Appliquer la première convolution et l'activation ReLU x = self.pool(x) # Appliquer le pooling maximal x = F.relu(self.conv2(x)) # Appliquer la deuxième convolution et l'activation ReLU x = self.pool(x) # Appliquer le pooling maximal x = x.reshape(x.shape[0], -1) # Aplatir le tenseur x = self.fc1(x) # Appliquer la couche entièrement connectée return x x = x.reshape(x.shape[0], -1) # Aplatir le tenseur x = self.fc1(x) # Appliquer la couche entièrement connectée return x

Une fois que nous avons défini la classe CNN, nous pouvons créer notre modèle et le déplacer vers l’appareil où il sera entraîné et exécuté. 

Les réseaux neuronaux, y compris les CNN, montrent de meilleures performances lorsqu’ils fonctionnent sur des GPU, mais cela peut ne pas être le cas sur votre ordinateur. Par conséquent, nous exécuterons le modèle sur un GPU uniquement s’il est disponible; sinon, nous utiliserons un CPU classique.

device = "cuda" if torch.cuda.is_available() else "cpu" model = CNN(in_channels=1, num_classes=10).to(device) print(model) >>> CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )

4. Entraînement du modèle CNN

Maintenant que nous avons notre modèle, il est temps de l’entraîner. Pour ce faire, nous devrons d’abord déterminer comment nous mesurerons les performances du modèle. Étant donné que nous avons affaire à un problème de classification multi-classes, nous utiliserons la fonction de perte d’entropie croisée, disponible dans PyTorch sous le nom de nn.CrossEntropyLoss. Nous utiliserons également l’optimiseur Adam, l’un des algorithmes d’optimisation les plus populaires. 

# Définir la fonction de perte criterion = nn.CrossEntropyLoss() # Définir l'optimiseur optimizer = optim.Adam(model.parameters(), lr=0.001)

Nous itérerons sur dix époques et des lots d’entraînement pour former le modèle et effectuer la séquence habituelle d’étapes pour chaque lot, comme indiqué ci-dessous.

num_epochs=10 for epoch in range(num_epochs): # Itérer sur les lots d'entraînement print(f"Epoch [{epoch + 1}/{num_epochs}]") for batch_index, (data, targets) in enumerate(tqdm(dataloader_train)): data = data.to(device) targets = targets.to(device) scores = model(data) loss = criterion(scores, targets) optimizer.zero_grad() loss.backward() optimizer.step()
Epoch [1/10] 100%|██████████| 1000/1000 [00:13<00:00, 72.94it/s] Epoch [2/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.27it/s] Epoch [3/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.16it/s] Epoch [4/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.00it/s] Epoch [5/10] 100%|██████████| 1000/1000 [00:13<00:00, 75.69it/s] Epoch [6/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.24it/s] Epoch [7/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.23it/s] Epoch [8/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.16it/s] Epoch [9/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.96it/s] Epoch [10/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.93it/s]

5. Évaluation du modèle

Une fois le modèle entraîné, nous pouvons évaluer ses performances sur l’ensemble de données de test. Nous utiliserons la précision, une métrique populaire pour les problèmes de classification. La précision mesure la proportion de cas correctement classés par rapport au nombre total d’objets dans l’ensemble de données. Elle est calculée en divisant le nombre de prédictions correctes par le nombre total de prédictions faites par le modèle.

Tout d’abord, nous mettons en place la métrique de précision à partir de torchmetrics. Ensuite, nous utilisons la méthode .eval du modèle pour mettre le modèle en mode d’évaluation, car certaines couches des modèles PyTorch se comportent différemment aux étapes d’entraînement par rapport aux étapes de test. Nous ajoutons également un contexte Python avec torch.no_grad, indiquant que nous ne calculerons pas de gradient.

Ensuite, nous itérons sur les exemples de test sans calcul de gradient. Pour chaque lot de test, nous obtenons les sorties du modèle, prenons la classe la plus probable, et la passons à la fonction de précision avec les étiquettes. Enfin, nous calculons les métriques et affichons les résultats. Nous avons obtenu un score de précision de 0,98, ce qui signifie que notre modèle a correctement classé 98% des chiffres. Pas mal !

# Configuration de la métrique de précision multiclasse acc = Accuracy(task="multiclass",num_classes=10) # Itération sur les lots de jeu de données model.eval() with torch.no_grad(): for images, labels in dataloader_test: # Obtenir les probabilités prédites pour le lot de données de test outputs = model(images) _, preds = torch.max(outputs, 1) acc(preds, labels) precision(preds, labels) recall(preds, labels) # Calcul de la précision totale du test test_accuracy = acc.compute() print(f"Test accuracy: {test_accuracy}") >>> Test accuracy: 0.9857000112533569

Vous pouvez également utiliser d’autres métriques de classification populaires, y compris le rappel et la précision. Nous vous expliquons tout sur ces métriques avec des exemples pratiques dans notre Cours intermédiaire sur l’apprentissage profond avec PyTorch.

Amélioration des performances du modèle

Bien que notre modèle CNN atteigne de bonnes performances, il existe plusieurs stratégies que nous pouvons utiliser pour améliorer davantage sa précision, sa robustesse et sa généralisation aux nouvelles données.

Dans cette section, nous explorerons des techniques clés telles que l’augmentation des données, le réglage des hyperparamètres et l’apprentissage par transfert pour optimiser les performances de notre modèle.

Les techniques d’augmentation des données

Augmentation des données est une technique utilisée pour améliorer la précision de notre modèle en créant aléatoirement de nouvelles données d’entraînement. Par exemple, lors du chargement, on peut appliquer des transformations aux images d’entraînement, telles que le redimensionnement, le retournement horizontal ou vertical, la rotation aléatoire, et ainsi de suite. De cette manière, on peut créer des images augmentées et leur attribuer la même étiquette que l’image originale, augmentant ainsi la taille de l’ensemble d’entraînement.

Ajouter des transformations aléatoires aux images originales nous permet de générer plus de données tout en augmentant la taille et la diversité de l’ensemble d’entraînement. Cela rend le modèle plus robuste aux variations et aux distorsions couramment rencontrées dans les images du monde réel, et réduit le surapprentissage car le modèle apprend à ignorer les transformations aléatoires.

Cependant, il est important d’être prudent avec l’augmentation des données, car parfois cela peut nuire au processus d’entraînement. Par exemple, dans notre problème, si nous appliquons le retournement vertical au chiffre « 6 », il ressemblera au chiffre « 9 ». Le passer au modèle étiqueté comme « 6 » confondra le modèle et nuira à l’entraînement. Ces exemples montrent que, parfois, des augmentations spécifiques peuvent impacter l’étiquette.

Réglage des hyperparamètres

Une autre stratégie pour améliorer les performances de notre modèle consiste à modifier les valeurs des hyperparamètres impliqués dans les différentes couches du modèle. Ce réglage des hyperparamètres nécessite une compréhension approfondie des mathématiques derrière les réseaux neuronaux et de l’importance des différents hyperparamètres.

Par exemple, vous pourriez ajuster vos couches CNN en modifiant la taille des filtres ou en augmentant le padding. Vous pourriez également définir une valeur différente pour les poids initiaux des neurones.

Étant donné que nous ne connaîtrons pas les valeurs optimales des hyperparamètres à l’avance, un certain degré d’essais et d’erreurs sera nécessaire. Cela se fait généralement à travers une technique appelée recherche en grille, qui vous permet d’évaluer systématiquement un modèle sur une grille de valeurs de paramètres.

Cependant, soyez prudent lorsque vous utilisez cette technique, car elle est généralement coûteuse en termes de calcul, surtout lorsqu’il s’agit de réseaux neuronaux complexes et de grands ensembles de données d’entraînement.

De même, vous pourriez augmenter la complexité de votre modèle en ajoutant plus de couches convolutionnelles et linéaires. Cependant, soyez prudent lorsque vous ajoutez de nouvelles couches, car le nombre de neurones peut augmenter considérablement, ce qui entraîne des temps d’entraînement plus longs et un risque de surapprentissage.

Vous pouvez en apprendre davantage sur le réglage des hyperparamètres dans notre Cours d’Introduction au Deep Learning avec PyTorch.

Utilisation de modèles pré-entraînés

Former des modèles d’apprentissage en profondeur à partir de zéro est un processus long et fastidieux, et cela nécessite généralement beaucoup de données d’entraînement. Au lieu de cela, nous pouvons souvent utiliser des modèles pré-entraînés, c’est-à-dire des modèles qui ont déjà été entraînés sur une tâche.

Parfois, nous pouvons réutiliser directement un modèle pré-entraîné s’il peut déjà résoudre la tâche qui nous intéresse. À d’autres occasions, nous pourrions avoir besoin d’ajuster le modèle pré-entraîné pour qu’il convienne à la nouvelle tâche. Cela est connu sous le nom de transfert d’apprentissage.

Utiliser des modèles pré-entraînés dans PyTorch est assez facile. Torchvision fournit une collection de modèles pré-entraînés pour diverses tâches liées aux images. Ces modèles sont pré-entraînés sur de grands ensembles de données d’images et sont facilement disponibles. Consultez notre Formation sur l’apprentissage en profondeur pour les images avec PyTorch pour tout apprendre à leur sujet.

Déployer le modèle CNN

Après avoir formé votre modèle de classification très précis dans PyTorch, vous pouvez maintenant sauvegarder le modèle et ses poids pré-entraînés pour une utilisation future et le partager avec votre équipe, en vous assurant qu’ils peuvent le charger sans problème.

Pour sauvegarder un modèle, nous pouvons utiliser torch.save. Une extension de fichier courante pour les modèles torch est soit pt soit pth. Pour sauvegarder les poids du modèle, nous passons model.state_dict à torch.save en fournissant le nom du fichier de sortie, par exemple, MulticlassCNN.pth.

Pour charger un modèle enregistré, nous initialisons un nouveau modèle avec la même architecture. Ensuite, nous utilisons la méthode load state dict avec torch.load pour charger les paramètres dans le nouveau modèle.

# Enregistrer le modèle torch.save(model.state_dict(), 'MulticlassCNN.pth') # Créer un nouveau modèle loaded_model = CNN(in_channels=1, num_classes=10) # Charger le modèle enregistré loaded_model.load_state_dict(torch.load('MulticlassCNN.pth')) print(loaded_model) CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )

Conclusion

Nous avons couvert un aperçu complet des CNN, en fournissant des détails sur chaque couche de l’architecture CNN. De plus, nous avons fourni un guide sur la manière d’implémenter un CNN en PyTorch, en couvrant les principales étapes, du chargement des données et de la conception du modèle à l’entraînement et à l’évaluation du modèle. Enfin, nous avons également analysé plusieurs stratégies pour améliorer les performances de notre modèle. Nous avons appliqué toutes ces compétences à un scénario réel lié à une tâche de classification multi-classe. 

Il y a beaucoup à apprendre sur le deep learning, sans doute l’un des domaines les plus passionnants et exigeants en IA. Heureusement, DataCamp est là pour vous aider. Consultez nos ressources et cours dédiés et devenez un expert en réseaux neuronaux :

Source:
https://www.datacamp.com/tutorial/pytorch-cnn-tutorial