Table des matières
Importez les bibliothèques nécessaires
Le test de code
Maison Périphériques technologiques IA Exemple de code complet de formation parallèle PyTorch DistributedDataParallel

Exemple de code complet de formation parallèle PyTorch DistributedDataParallel

Apr 10, 2023 pm 08:51 PM
深度学习 数据集

Le problème de la formation de grands réseaux de neurones profonds (DNN) à l'aide de grands ensembles de données constitue un défi majeur dans le domaine de l'apprentissage profond. À mesure que la taille des DNN et des ensembles de données augmente, les besoins en calcul et en mémoire pour la formation de ces modèles augmentent également. Cela rend difficile, voire impossible, la formation de ces modèles sur une seule machine avec des ressources informatiques limitées. Certains des défis majeurs liés à la formation de grands DNN à l'aide de grands ensembles de données incluent :

  • Longue durée de formation : le processus de formation peut prendre des semaines, voire des mois, en fonction de la complexité du modèle et de la taille de l'ensemble de données.
  • Limites de mémoire : les grands DNN peuvent nécessiter de grandes quantités de mémoire pour stocker tous les paramètres du modèle, les gradients et les activations intermédiaires pendant l'entraînement. Cela peut entraîner des erreurs de mémoire insuffisante et limiter la taille du modèle pouvant être entraîné sur une seule machine.

Pour relever ces défis, diverses techniques ont été développées pour étendre la formation de grands DNN avec de grands ensembles de données, notamment le parallélisme des modèles, le parallélisme des données et le parallélisme hybride, ainsi que l'optimisation du matériel, des logiciels et des algorithmes.

Dans cet article, nous démontrerons le parallélisme des données et le parallélisme des modèles à l'aide de PyTorch.

Exemple de code complet de formation parallèle PyTorch DistributedDataParallel

Ce que nous appelons le parallélisme fait généralement référence à la formation de réseaux de neurones profonds (dnn) sur plusieurs GPU ou plusieurs machines, pour réduire le temps de formation. L'idée de base derrière le parallélisme des données est de diviser les données d'entraînement en morceaux plus petits et de laisser chaque GPU ou machine traiter un morceau de données distinct. Les résultats de chaque nœud sont ensuite combinés et utilisés pour mettre à jour les paramètres du modèle. Dans le parallélisme des données, l'architecture du modèle est la même sur chaque nœud, mais les paramètres du modèle sont répartis entre les nœuds. Chaque nœud entraîne son propre modèle local à l'aide de blocs de données alloués, et à la fin de chaque itération de formation, les paramètres du modèle sont synchronisés sur tous les nœuds. Ce processus est répété jusqu'à ce que le modèle converge vers un résultat satisfaisant.

Ci-dessous, nous utilisons les ensembles de données ResNet50 et CIFAR10 pour un exemple de code complet :

Dans le parallélisme des données, l'architecture du modèle reste la même sur chaque nœud, mais les paramètres du modèle sont partitionnés entre les nœuds, et chaque nœud utilise Allouer des morceaux de données pour formez votre propre modèle local.

La bibliothèque DistributedDataParallel de PyTorch peut communiquer et synchroniser efficacement les gradients et les paramètres du modèle entre les nœuds pour réaliser une formation distribuée. Cet article fournit des exemples sur la façon d'implémenter le parallélisme des données avec PyTorch à l'aide des ensembles de données ResNet50 et CIFAR10, où le code est exécuté sur plusieurs GPU ou machines, chaque machine traitant un sous-ensemble des données d'entraînement. Le processus de formation est parallélisé à l'aide de la bibliothèque DistributedDataParallel de PyTorch.

Importez les bibliothèques nécessaires

import os
 from datetime import datetime
 from time import time
 import argparse
 import torchvision
 import torchvision.transforms as transforms
 import torch
 import torch.nn as nn
 import torch.distributed as dist
 from torch.nn.parallel import DistributedDataParallel
Copier après la connexion

Ensuite, nous vérifierons le GPU.

import subprocess
 result = subprocess.run(['nvidia-smi'], stdout=subprocess.PIPE)
 print(result.stdout.decode())
Copier après la connexion

Parce que nous devons exécuter sur plusieurs serveurs, il n'est pas pratique de les exécuter un par un manuellement, un planificateur est donc nécessaire. Ici, nous utilisons des fichiers SLURM pour exécuter le code (slurmplanificateur de tâches gratuit et open source pour les noyaux Linux et Unix),

def main():
 
 # get distributed configuration from Slurm environment
 
 parser = argparse.ArgumentParser()
 parser.add_argument('-b', '--batch-size', default=128, type =int,
 help='batch size. it will be divided in mini-batch for each worker')
 parser.add_argument('-e','--epochs', default=2, type=int, metavar='N',
 help='number of total epochs to run')
 parser.add_argument('-c','--checkpoint', default=None, type=str,
 help='path to checkpoint to load')
 args = parser.parse_args()
 
 rank = int(os.environ['SLURM_PROCID'])
 local_rank = int(os.environ['SLURM_LOCALID'])
 size = int(os.environ['SLURM_NTASKS'])
 master_addr = os.environ["SLURM_SRUN_COMM_HOST"]
 port = "29500"
 node_id = os.environ['SLURM_NODEID']
 ddp_arg = [rank, local_rank, size, master_addr, port, node_id]
 train(args, ddp_arg)
Copier après la connexion

Ensuite, nous utilisons la bibliothèque DistributedDataParallel pour effectuer une formation distribuée.

def train(args, ddp_arg):
 
 rank, local_rank, size, MASTER_ADDR, port, NODE_ID = ddp_arg
 
 # display info
 if rank == 0:
 #print(">>> Training on ", len(hostnames), " nodes and ", size, " processes, master node is ", MASTER_ADDR)
 print(">>> Training on ", size, " GPUs, master node is ", MASTER_ADDR)
 #print("- Process {} corresponds to GPU {} of node {}".format(rank, local_rank, NODE_ID))
 
 print("- Process {} corresponds to GPU {} of node {}".format(rank, local_rank, NODE_ID))
 
 
 # configure distribution method: define address and port of the master node and initialise communication backend (NCCL)
 #dist.init_process_group(backend='nccl', init_method='env://', world_size=size, rank=rank)
 dist.init_process_group(
 backend='nccl',
 init_method='tcp://{}:{}'.format(MASTER_ADDR, port),
 world_size=size,
 rank=rank
)
 
 # distribute model
 torch.cuda.set_device(local_rank)
 gpu = torch.device("cuda")
 #model = ResNet18(classes=10).to(gpu)
 model = torchvision.models.resnet50(pretrained=False).to(gpu)
 ddp_model = DistributedDataParallel(model, device_ids=[local_rank])
 if args.checkpoint is not None:
 map_location = {'cuda:%d' % 0: 'cuda:%d' % local_rank}
 ddp_model.load_state_dict(torch.load(args.checkpoint, map_location=map_location))
 
 # distribute batch size (mini-batch)
 batch_size = args.batch_size
 batch_size_per_gpu = batch_size // size
 
 # define loss function (criterion) and optimizer
 criterion = nn.CrossEntropyLoss()
 optimizer = torch.optim.SGD(ddp_model.parameters(), 1e-4)
 
 
 transform_train = transforms.Compose([
 transforms.RandomCrop(32, padding=4),
 transforms.RandomHorizontalFlip(),
 transforms.ToTensor(),
 transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
])
 
 # load data with distributed sampler
 #train_dataset = torchvision.datasets.CIFAR10(root='./data',
 # train=True,
 # transform=transform_train,
 # download=False)
 
 # load data with distributed sampler
 train_dataset = torchvision.datasets.CIFAR10(root='./data',
train=True,
transform=transform_train,
download=False)
 
 train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset,
 num_replicas=size,
 rank=rank)
 
 train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size_per_gpu,
shuffle=False,
num_workers=0,
pin_memory=True,
sampler=train_sampler)
 
 # training (timers and display handled by process 0)
 if rank == 0: start = datetime.now()
 total_step = len(train_loader)
 
 for epoch in range(args.epochs):
 if rank == 0: start_dataload = time()
 
 for i, (images, labels) in enumerate(train_loader):
 
 # distribution of images and labels to all GPUs
 images = images.to(gpu, non_blocking=True)
 labels = labels.to(gpu, non_blocking=True)
 
 if rank == 0: stop_dataload = time()
 
 if rank == 0: start_training = time()
 
 # forward pass
 outputs = ddp_model(images)
 loss = criterion(outputs, labels)
 
 # backward and optimize
 optimizer.zero_grad()
 loss.backward()
 optimizer.step()
 
 if rank == 0: stop_training = time()
 if (i + 1) % 10 == 0 and rank == 0:
 print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}, Time data load: {:.3f}ms, Time training: {:.3f}ms'.format(epoch + 1, args.epochs,
 i + 1, total_step, loss.item(), (stop_dataload - start_dataload)*1000,
(stop_training - start_training)*1000))
 if rank == 0: start_dataload = time()
 
 #Save checkpoint at every end of epoch
 if rank == 0:
 torch.save(ddp_model.state_dict(), './checkpoint/{}GPU_{}epoch.checkpoint'.format(size, epoch+1))
 
 if rank == 0:
 print(">>> Training complete in: " + str(datetime.now() - start))
 
 
 if __name__ == '__main__':
 
 main()
Copier après la connexion

Le code divise les données et le modèle sur plusieurs GPU et met à jour le modèle de manière distribuée. Voici quelques explications du code :

train(args, ddp_arg) a deux paramètres, args et ddp_arg, où args est le paramètre de ligne de commande transmis au script, et ddp_arg contient les paramètres distribués liés à la formation.

rank, local_rank, size, MASTER_ADDR, port, NODE_ID = ddp_arg : décompressez les paramètres liés à la formation distribuée dans ddp_arg.

Si le rang est 0, imprimez le nombre de GPU actuellement utilisés et les informations sur l'adresse IP du nœud maître.

dist.init_process_group(backend='nccl', init_method='tcp://{}:{}'.format(MASTER_ADDR, port), world_size=size,rank=rank) : Initialisez le processus distribué à l'aide du groupe backend NCCL.

torch.cuda.set_device(local_rank) : sélectionnez le GPU spécifié pour ce processus.

model = torchvision.models. ResNet50 (pretrained=False).to(gpu) : chargez le modèle ResNet50 à partir du modèle torchvision et déplacez-le vers le GPU spécifié.

ddp_model = DistributedDataParallel(model, device_ids=[local_rank]) : Enveloppez le modèle dans le module DistributedDataParallel, ce qui signifie que nous pouvons effectuer une formation distribuée

Chargez l'ensemble de données CIFAR-10 et appliquez la transformation d'amélioration des données.

train_sampler=torch.utils.data.distributed.DistributedSampler(train_dataset,num_replicas=size,rank=rank) : créez un objet DistributedSampler pour diviser l'ensemble de données sur plusieurs GPU.

train_loader =torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size_per_gpu,shuffle=False,num_workers=0,pin_memory=True,sampler=train_sampler) : créez un objet DataLoader et les données seront chargées dans le modèle par lots. Ceci est cohérent avec nos étapes de formation habituelles, sauf qu'un échantillonnage de données distribué DistributedSampler est ajouté.

Entraînez le modèle pour le nombre d'époques spécifié et mettez à jour les poids à l'aide d'optimizer.step() de manière distribuée.

rank0 enregistre un point de contrôle à la fin de chaque tour.

rank0 affiche la perte et le temps d'entraînement tous les 10 lots.

A la fin de la formation, le temps total passé à imprimer le modèle de formation est également au rang0.

Le test de code

a été formé en utilisant 1 nœud avec 1/2/3/4 GPU, 2 nœuds avec 6/8 GPU et chaque nœud avec 3/4 GPU. Le test de Resnet50 sur Cifar10 est comme indiqué ci-dessous. , la taille du lot reste la même pour chaque test. Le temps nécessaire pour terminer chaque test a été enregistré en secondes. À mesure que le nombre de GPU utilisés augmente, le temps nécessaire pour terminer le test diminue. Lors de l'utilisation de 8 GPU, cela a pris 320 secondes, ce qui est le temps le plus rapide enregistré. C'est sûr, mais nous pouvons voir que la vitesse d'entraînement n'augmente pas linéairement avec l'augmentation du nombre de GPU. Cela peut être dû au fait que Resnet50 est un modèle relativement petit et ne nécessite pas d'entraînement parallèle.

Exemple de code complet de formation parallèle PyTorch DistributedDataParallel

L'utilisation du parallélisme des données sur plusieurs GPU peut réduire considérablement le temps nécessaire à la formation d'un réseau neuronal profond (DNN) sur un ensemble de données donné. À mesure que le nombre de GPU augmente, le temps nécessaire pour terminer le processus de formation diminue, ce qui indique que les DNN peuvent être formés plus efficacement en parallèle.

Cette approche est particulièrement utile lorsqu'il s'agit de grands ensembles de données ou d'architectures DNN complexes. En exploitant plusieurs GPU, le processus de formation peut être accéléré, permettant une itération et une expérimentation plus rapides du modèle. Cependant, il convient de noter que les améliorations de performances obtenues grâce au parallélisme des données peuvent être limitées par des facteurs tels que la surcharge de communication et les limitations de la mémoire GPU, et nécessitent un réglage minutieux pour obtenir les meilleurs résultats.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Méthodes et étapes d'utilisation de BERT pour l'analyse des sentiments en Python Méthodes et étapes d'utilisation de BERT pour l'analyse des sentiments en Python Jan 22, 2024 pm 04:24 PM

BERT est un modèle de langage d'apprentissage profond pré-entraîné proposé par Google en 2018. Le nom complet est BidirectionnelEncoderRepresentationsfromTransformers, qui est basé sur l'architecture Transformer et présente les caractéristiques d'un codage bidirectionnel. Par rapport aux modèles de codage unidirectionnels traditionnels, BERT peut prendre en compte les informations contextuelles en même temps lors du traitement du texte, de sorte qu'il fonctionne bien dans les tâches de traitement du langage naturel. Sa bidirectionnalité permet à BERT de mieux comprendre les relations sémantiques dans les phrases, améliorant ainsi la capacité expressive du modèle. Grâce à des méthodes de pré-formation et de réglage fin, BERT peut être utilisé pour diverses tâches de traitement du langage naturel, telles que l'analyse des sentiments, la dénomination

Analyse des fonctions d'activation de l'IA couramment utilisées : pratique d'apprentissage en profondeur de Sigmoid, Tanh, ReLU et Softmax Analyse des fonctions d'activation de l'IA couramment utilisées : pratique d'apprentissage en profondeur de Sigmoid, Tanh, ReLU et Softmax Dec 28, 2023 pm 11:35 PM

Les fonctions d'activation jouent un rôle crucial dans l'apprentissage profond. Elles peuvent introduire des caractéristiques non linéaires dans les réseaux neuronaux, permettant ainsi au réseau de mieux apprendre et simuler des relations entrées-sorties complexes. La sélection et l'utilisation correctes des fonctions d'activation ont un impact important sur les performances et les résultats de formation des réseaux de neurones. Cet article présentera quatre fonctions d'activation couramment utilisées : Sigmoid, Tanh, ReLU et Softmax, à partir de l'introduction, des scénarios d'utilisation, des avantages, Les inconvénients et les solutions d'optimisation sont abordés pour vous fournir une compréhension complète des fonctions d'activation. 1. Fonction sigmoïde Introduction à la formule de la fonction SIgmoïde : La fonction sigmoïde est une fonction non linéaire couramment utilisée qui peut mapper n'importe quel nombre réel entre 0 et 1. Il est généralement utilisé pour unifier le

Au-delà d'ORB-SLAM3 ! SL-SLAM : les scènes de faible luminosité, de gigue importante et de texture faible sont toutes gérées Au-delà d'ORB-SLAM3 ! SL-SLAM : les scènes de faible luminosité, de gigue importante et de texture faible sont toutes gérées May 30, 2024 am 09:35 AM

Écrit précédemment, nous discutons aujourd'hui de la manière dont la technologie d'apprentissage profond peut améliorer les performances du SLAM (localisation et cartographie simultanées) basé sur la vision dans des environnements complexes. En combinant des méthodes d'extraction de caractéristiques approfondies et de correspondance de profondeur, nous introduisons ici un système SLAM visuel hybride polyvalent conçu pour améliorer l'adaptation dans des scénarios difficiles tels que des conditions de faible luminosité, un éclairage dynamique, des zones faiblement texturées et une gigue importante. Notre système prend en charge plusieurs modes, notamment les configurations étendues monoculaire, stéréo, monoculaire-inertielle et stéréo-inertielle. En outre, il analyse également comment combiner le SLAM visuel avec des méthodes d’apprentissage profond pour inspirer d’autres recherches. Grâce à des expériences approfondies sur des ensembles de données publiques et des données auto-échantillonnées, nous démontrons la supériorité du SL-SLAM en termes de précision de positionnement et de robustesse du suivi.

Intégration d'espace latent : explication et démonstration Intégration d'espace latent : explication et démonstration Jan 22, 2024 pm 05:30 PM

L'intégration d'espace latent (LatentSpaceEmbedding) est le processus de mappage de données de grande dimension vers un espace de faible dimension. Dans le domaine de l'apprentissage automatique et de l'apprentissage profond, l'intégration d'espace latent est généralement un modèle de réseau neuronal qui mappe les données d'entrée de grande dimension dans un ensemble de représentations vectorielles de basse dimension. Cet ensemble de vecteurs est souvent appelé « vecteurs latents » ou « latents ». encodages". Le but de l’intégration de l’espace latent est de capturer les caractéristiques importantes des données et de les représenter sous une forme plus concise et compréhensible. Grâce à l'intégration de l'espace latent, nous pouvons effectuer des opérations telles que la visualisation, la classification et le regroupement de données dans un espace de faible dimension pour mieux comprendre et utiliser les données. L'intégration d'espace latent a de nombreuses applications dans de nombreux domaines, tels que la génération d'images, l'extraction de caractéristiques, la réduction de dimensionnalité, etc. L'intégration de l'espace latent est le principal

Comprendre en un seul article : les liens et les différences entre l'IA, le machine learning et le deep learning Comprendre en un seul article : les liens et les différences entre l'IA, le machine learning et le deep learning Mar 02, 2024 am 11:19 AM

Dans la vague actuelle de changements technologiques rapides, l'intelligence artificielle (IA), l'apprentissage automatique (ML) et l'apprentissage profond (DL) sont comme des étoiles brillantes, à la tête de la nouvelle vague des technologies de l'information. Ces trois mots apparaissent fréquemment dans diverses discussions de pointe et applications pratiques, mais pour de nombreux explorateurs novices dans ce domaine, leurs significations spécifiques et leurs connexions internes peuvent encore être entourées de mystère. Alors regardons d'abord cette photo. On constate qu’il existe une corrélation étroite et une relation progressive entre l’apprentissage profond, l’apprentissage automatique et l’intelligence artificielle. Le deep learning est un domaine spécifique du machine learning, et le machine learning

Super fort! Top 10 des algorithmes de deep learning ! Super fort! Top 10 des algorithmes de deep learning ! Mar 15, 2024 pm 03:46 PM

Près de 20 ans se sont écoulés depuis que le concept d'apprentissage profond a été proposé en 2006. L'apprentissage profond, en tant que révolution dans le domaine de l'intelligence artificielle, a donné naissance à de nombreux algorithmes influents. Alors, selon vous, quels sont les 10 meilleurs algorithmes pour l’apprentissage profond ? Voici les meilleurs algorithmes d’apprentissage profond, à mon avis. Ils occupent tous une position importante en termes d’innovation, de valeur d’application et d’influence. 1. Contexte du réseau neuronal profond (DNN) : Le réseau neuronal profond (DNN), également appelé perceptron multicouche, est l'algorithme d'apprentissage profond le plus courant lorsqu'il a été inventé pour la première fois, jusqu'à récemment en raison du goulot d'étranglement de la puissance de calcul. années, puissance de calcul, La percée est venue avec l'explosion des données. DNN est un modèle de réseau neuronal qui contient plusieurs couches cachées. Dans ce modèle, chaque couche transmet l'entrée à la couche suivante et

Des bases à la pratique, passez en revue l'historique du développement de la récupération de vecteurs Elasticsearch. Des bases à la pratique, passez en revue l'historique du développement de la récupération de vecteurs Elasticsearch. Oct 23, 2023 pm 05:17 PM

1. Introduction La récupération de vecteurs est devenue un élément essentiel des systèmes modernes de recherche et de recommandation. Il permet une correspondance de requêtes et des recommandations efficaces en convertissant des objets complexes (tels que du texte, des images ou des sons) en vecteurs numériques et en effectuant des recherches de similarité dans des espaces multidimensionnels. Des bases à la pratique, passez en revue l'historique du développement d'Elasticsearch. vector retrieval_elasticsearch En tant que moteur de recherche open source populaire, le développement d'Elasticsearch en matière de récupération de vecteurs a toujours attiré beaucoup d'attention. Cet article passera en revue l'historique du développement de la récupération de vecteurs Elasticsearch, en se concentrant sur les caractéristiques et la progression de chaque étape. En prenant l'historique comme guide, il est pratique pour chacun d'établir une gamme complète de récupération de vecteurs Elasticsearch.

Afin de fournir un nouveau système de référence et d'évaluation de questions-réponses scientifiques et complexes pour les grands modèles, l'UNSW, Argonne, l'Université de Chicago et d'autres institutions ont lancé conjointement le cadre SciQAG. Afin de fournir un nouveau système de référence et d'évaluation de questions-réponses scientifiques et complexes pour les grands modèles, l'UNSW, Argonne, l'Université de Chicago et d'autres institutions ont lancé conjointement le cadre SciQAG. Jul 25, 2024 am 06:42 AM

L'ensemble de données ScienceAI Question Answering (QA) joue un rôle essentiel dans la promotion de la recherche sur le traitement du langage naturel (NLP). Des ensembles de données d'assurance qualité de haute qualité peuvent non seulement être utilisés pour affiner les modèles, mais également évaluer efficacement les capacités des grands modèles linguistiques (LLM), en particulier la capacité à comprendre et à raisonner sur les connaissances scientifiques. Bien qu’il existe actuellement de nombreux ensembles de données scientifiques d’assurance qualité couvrant la médecine, la chimie, la biologie et d’autres domaines, ces ensembles de données présentent encore certaines lacunes. Premièrement, le formulaire de données est relativement simple, et la plupart sont des questions à choix multiples. Elles sont faciles à évaluer, mais limitent la plage de sélection des réponses du modèle et ne peuvent pas tester pleinement la capacité du modèle à répondre aux questions scientifiques. En revanche, les questions et réponses ouvertes

See all articles