Ce référentiel contient le code pour exploiter les questions Cloze pour la classification du texte à quelques coups et l'inférence du langage naturel et ce n'est pas seulement la taille qui compte: les modèles de petits langues sont également des apprenants à quelques coups. Les articles introduisent la formation d'exploitation des modèles (TEP), une procédure de formation semi-supervisée qui reformule des exemples d'entrée en tant que phrases de style Cloze. Dans les paramètres à faibles ressources, les TEP et les IPET surpassent considérablement une formation régulière régulière, diverses lignes de base semi-supervisées et même GPT-3 malgré le besoin de 99,9% de paramètres en moins. La variante itérative de PET (IPET) forme plusieurs générations de modèles et peut même être utilisée sans aucune donnée de formation.
| # Exemples | Mode de formation | Yelp (plein) | Les nouvelles de l'AG | Questions Yahoo | MNLI |
|---|---|---|---|---|---|
| 0 | sans surveillance | 33.8 | 69.5 | 44.0 | 39.1 |
| ipet | 56.7 | 87.5 | 70.7 | 53.6 | |
| 100 | supervisé | 53.0 | 86.0 | 62.9 | 47.9 |
| ANIMAL DE COMPAGNIE | 61.9 | 88.3 | 69.2 | 74.7 | |
| ipet | 62.9 | 89.6 | 71.2 | 78.4 |
Remarque : Pour reproduire exactement les résultats ci-dessus, assurez-vous d'utiliser v1.1.0 ( --branch v1.1.0 ).
? Installation
Utilisation de la CLI
Utilisation de l'API
? Formez votre propre animal de compagnie
Citation
Toutes les exigences pour TEP peuvent être trouvées dans requirements.txt . Vous pouvez installer tous les packages requis avec pip install -r requirements.txt .
L'interface de ligne de commande cli.py dans ce référentiel prend actuellement en charge trois modes de formation différents (PET, IPET, formation supervisée), deux méthodes d'évaluation supplémentaires (non supervisées et amorçage) et 13 tâches différentes. Pour les critiques de Yelp, AG's News, Yahoo Questions, MNLI et X-position, consultez le document original pour plus de détails. Pour les 8 tâches de superglue, consultez cet article.
Pour former et évaluer un modèle TEP pour l'une des tâches prises en charge, exécutez simplement la commande suivante:
python3 cli.py
--method pet
--pattern_ids $PATTERN_IDS
--data_dir $DATA_DIR
--model_type $MODEL_TYPE
--model_name_or_path $MODEL_NAME_OR_PATH
--task_name $TASK
--output_dir $OUTPUT_DIR
--do_train
--do_eval
où
$PATTERN_IDS Spécifie les PVP à utiliser. Par exemple, si vous souhaitez utiliser tous les modèles, spécifiez PATTERN_IDS 0 1 2 3 4 pour les nouvelles d'Ag et les questions Yahoo ou PATTERN_IDS 0 1 2 3 pour les critiques Yelp et MNLI.$DATA_DIR est le répertoire contenant les fichiers de train et de test (vérifiez tasks.py pour voir comment ces fichiers doivent être nommés et formatés pour chaque tâche).$MODEL_TYPE est le nom du modèle utilisé, par exemple albert , bert ou roberta .$MODEL_NAME est le nom d'un modèle pré-entraîné (par exemple, roberta-large ou albert-xxlarge-v2 ) ou le chemin vers un modèle pré-entraîné.$TASK_NAME est le nom de la tâche pour former et évaluer.$OUTPUT_DIR est le nom du répertoire dans lequel le modèle formé et les résultats d'évaluation sont enregistrés. Vous pouvez en outre spécifier divers paramètres de formation pour les deux modèles de TEP correspondant à des PVP individuels (préfixe --pet_ ) et pour le modèle de classification de séquence final (préfixe --sc_ ). Par exemple, les paramètres par défaut utilisés pour notre évaluation de superglue sont:
--pet_per_gpu_eval_batch_size 8
--pet_per_gpu_train_batch_size 2
--pet_gradient_accumulation_steps 8
--pet_max_steps 250
--pet_max_seq_length 256
--pet_repetitions 3
--sc_per_gpu_train_batch_size 2
--sc_per_gpu_unlabeled_batch_size 2
--sc_gradient_accumulation_steps 8
--sc_max_steps 5000
--sc_max_seq_length 256
--sc_repetitions 1
Pour chaque modèle $P et la répétition $I , l'exécution de la commande ci-dessus crée un répertoire $OUTPUT_DIR/p$Pi$I qui contient les fichiers suivants:
pytorch_model.bin : le modèle à finetuned, peut-être avec certains fichiers spécifiques au modèle (par exemple, spiece.model , special_tokens_map.json )wrapper_config.json : la configuration du modèle utilisétrain_config.json : la configuration utilisée pour la formationeval_config.json : La configuration utilisée pour l'évaluationlogits.txt : les prédictions du modèle sur les données non marquéeseval_logits.txt : La prédiction du modèle sur les données d'évaluationresults.json : un fichier JSON contenant des résultats tels que la précision finale du modèlepredictions.jsonl : un fichier de prédiction pour l'ensemble d'évaluation au format de superglue Le modèle final (distillé) pour chaque répétition $I peux être trouvé dans $OUTPUT_DIR/final/p0-i$I , qui contient les mêmes fichiers que celles décrites ci-dessus.
Si votre GPU manque de mémoire pendant l'entraînement, vous pouvez essayer de diminuer à la fois le pet_per_gpu_train_batch_size et le sc_per_gpu_unlabeled_batch_size tout en augmentant à la fois pet_gradient_accumulation_steps et sc_gradient_accumulation_steps .
Pour former et évaluer un modèle IPET pour l'une des tâches prises en charge, exécutez simplement la même commande que ci-dessus, mais remplacez --method pet par --method ipet . Il existe différents paramètres IPET supplémentaires que vous pouvez modifier; Tous sont préfixés avec --ipet_ .
Pour chaque génération $G , modèle $P et itération $I , cela crée un répertoire $OUTPUT_DIR/g$G/p$Pi$I qui est structuré comme pour l'animal régulier. Le modèle final (distillé) peut à nouveau être trouvé dans $OUTPUT_DIR/final/p0-i$I .
Si vous utilisez IPET avec des exemples de formation zéro, vous devez spécifier le nombre d'exemples pour chaque étiquette qui doit être choisi dans la première génération et vous devez modifier la stratégie de réduction pour signifier: --ipet_n_most_likely 100 --reduction mean .
Pour entraîner et évaluer un classificateur de séquence régulière de manière supervisée, exécutez simplement la même commande que ci-dessus, mais remplacez --method pet par --method sequence_classifier . Il existe différents paramètres supplémentaires pour le classificateur de séquence que vous pouvez modifier; Tous sont préfixés avec --sc_ .
Pour évaluer un modèle de langue pré-étendue avec les modèles et les verbaliseurs d'animaux de compagnie par défaut, mais sans réglage fin, supprimez l'argument --do_train et ADD --no_distillation afin qu'aucune distillation finale ne soit effectuée.
Si vous souhaitez utiliser l'amorçage, supprimez l'argument --do_train et ajoutez les arguments --priming --no_distillation afin que tous les exemples de formation soient utilisés pour l'amorçage et qu'aucune distillation finale n'est effectuée.
N'oubliez pas que vous devrez peut-être augmenter la longueur de séquence maximale à une valeur beaucoup plus grande, par exemple --pet_max_seq_length 5000 . Cela ne fonctionne qu'avec des modèles de langage qui prennent en charge ces longues séquences, par exemple xlnet. Pour l'utilisation de XLNET, vous pouvez spécifier --model_type xlnet --model_name_or_path xlnet-large-cased --wrapper_type plm .
Au lieu d'utiliser l'interface de ligne de commande, vous pouvez également utiliser directement l'API TEP, dont la plupart sont définies dans pet.modeling . En incluant import pet , vous pouvez accéder à des méthodes telles que train_pet , train_ipet et train_classifier . Consultez leur documentation pour plus d'informations.
Pour utiliser PET pour des tâches personnalisées, vous devez définir deux choses:
examples/custom_task_processor.py pour un exemple.examples/custom_task_pvp.py pour un exemple.Après avoir implémenté le dataProcesseur et le PVP, vous pouvez former un modèle TEP en utilisant la ligne de commande comme décrit ci-dessus. Ci-dessous, vous pouvez trouver des informations supplémentaires sur la façon de définir les deux composantes d'un PVP, des verbaliseurs et des modèles .
Les verbaliseurs sont utilisés pour cartographier les étiquettes de tâches en mots en langage naturel. Par exemple, dans une tâche de classification du sentiment binaire, vous pouvez cartographier l'étiquette positive ( +1 ) au mot good et l'étiquette négative ( -1 ) au mot bad . Les verbaliseurs sont réalisés via la méthode verbalize() d'un PVP. La façon la plus simple de définir un verbaliseur est d'utiliser un dictionnaire:
VERBALIZER = { "+1" : [ "good" ], "-1" : [ "bad" ]}
def verbalize ( self , label ) -> List [ str ]:
return self . VERBALIZER [ label ] Surtout, dans la version actuelle de TEP, les verbaliseurs sont par défaut limités aux jetons simples dans le vocabulaire LMS sous-jacent (pour utiliser plus d'un jeton, voir ci-dessous). Compte tenu du tokenizer d'un modèle de langue, vous pouvez facilement vérifier si un mot correspond à un seul jeton en vérifiant que len(tokenizer.tokenize(word)) == 1 .
Vous pouvez également définir plusieurs verbalisations pour une seule étiquette. Par exemple, si vous ne savez pas quels mots représentent le mieux les étiquettes dans une tâche de classification des sentiments binaires, vous pouvez définir votre verbaliseur comme suit:
VERBALIZER = { "+1" : [ "great" , "good" , "wonderful" , "perfect" ], "-1" : [ "bad" , "terrible" , "horrible" ]} Des modèles sont utilisés pour faire comprendre au modèle de la langue une tâche donnée; Ils doivent contenir exactement un jeton <MASK> qui doit être rempli à l'aide du verbin. Pour la classification du sentiment binaire basé sur le résumé d'une revue ( <A> ) et le corps ( <B> ), un modèle approprié peut être <A>. <B>. Overall, it was <MASK>. Les modèles sont réalisés via une méthode get_parts() d'un PVP, qui renvoie une paire de séquences de texte (où chaque séquence est représentée par une liste de chaînes):
def get_parts ( self , example : InputExample ):
return [ example . text_a , '.' , example . text_b , '.' ], [ 'Overall, it was ' , self . mask ]Si vous ne souhaitez pas utiliser une paire de séquences, vous pouvez simplement laisser la deuxième séquence vide:
def get_parts ( self , example : InputExample ):
return [ example . text_a , '.' , example . text_b , '. Overall, it was ' , self . mask ], [] Si vous souhaitez définir plusieurs modèles, utilisez simplement l'attribut PVP S pattern_id :
def get_parts ( self , example : InputExample ):
if self . pattern_id == 1 :
return [ example . text_a , '.' , example . text_b , '.' ], [ 'Overall, it was ' , self . mask ]
elif self . pattern_id == 2 :
return [ 'It was just ' , self . mask , '!' , example . text_a , '.' , example . text_b , '.' ], [] Lors de la formation du modèle à l'aide de la ligne de commande, spécifiez tous les modèles à utiliser (par exemple, --pattern_ids 1 2 ).
Surtout, si une séquence est plus longue que la longueur de séquence maximale spécifiée du LM sous-jacent, PET doit savoir quelles parties de l'entrée peuvent être raccourcies et lesquelles ne peuvent pas (par exemple, le jeton de masque doit toujours être là). Par conséquent, PVP fournit une méthode shortenable() pour indiquer qu'un morceau de texte peut être raccourci:
def get_parts ( self , example : InputExample ):
text_a = self . shortenable ( example . text_a )
text_b = self . shortenable ( example . text_b )
return [ text_a , '.' , text_b , '. Overall, it was ' , self . mask ], []Par défaut, l'implémentation actuelle de PET et IPET ne prend en charge qu'un ensemble fixe d'étiquettes partagées sur tous les exemples et verbaliseurs qui correspondent à un seul jeton. Cependant, pour certaines tâches, il peut être nécessaire d'utiliser des verbaliseurs qui correspondent à plusieurs jetons (comme décrit ici). Pour ce faire, vous avez simplement besoin des deux modifications suivantes:
Ajoutez les lignes suivantes dans DataProcesseur de votre tâche (voir examples/custom_task_processor.py ):
from pet . tasks import TASK_HELPERS
from pet . task_helpers import MultiMaskTaskHelper
TASK_HELPERS [ 'my_task' ] = MultiMaskTaskHelper où 'my_task' est le nom de votre tâche.
Dans votre PVP , assurez-vous que la méthode get_parts() insère toujours le nombre maximum de jetons de masque requis pour toute verbalisation. Par exemple, si votre verbalizer mappe +1 à "vraiment génial" et -1 à "terrible" et que si ceux-ci sont tokenisés comme ["really", "awe", "##some"] et ["terrible"] , respectivement, votre méthode get_parts() devrait toujours renvoyer une séquence qui contient exactement 3 jetons de masque.
Avec cette modification, vous pouvez désormais utiliser des verbaliseurs composés de jetons multiples:
VERBALIZER = { "+1" : [ "really good" ], "-1" : [ "just bad" ]}Cependant, il y a plusieurs limites à considérer:
MultiMaskTaskHelper , la taille maximale du lot pour l'évaluation est de 1.MultiMaskTaskHelper est une caractéristique expérimentale qui n'est pas complètement testée. En particulier, cette fonctionnalité n'a été testée que pour PET et non pour IPET. Si vous observez quelque chose d'étrange, veuillez soulever un problème. Pour plus de flexibilité, vous pouvez également écrire un TaskHelper personnalisé. En tant que point de départ, vous pouvez consulter les classes CopaTaskHelper , WscTaskHelper et RecordTaskHelper dans pet/task_helpers.py .
Si vous utilisez le code dans ce référentiel, veuillez citer les articles suivants:
@article{schick2020exploiting,
title={Exploiting Cloze Questions for Few-Shot Text Classification and Natural Language Inference},
author={Timo Schick and Hinrich Schütze},
journal={Computing Research Repository},
volume={arXiv:2001.07676},
url={http://arxiv.org/abs/2001.07676},
year={2020}
}
@article{schick2020small,
title={It's Not Just Size That Matters: Small Language Models Are Also Few-Shot Learners},
author={Timo Schick and Hinrich Schütze},
journal={Computing Research Repository},
volume={arXiv:2009.07118},
url={http://arxiv.org/abs/2009.07118},
year={2020}
}