Este repositório contém o código para explorar perguntas de cloze para classificação de texto com poucas fotos e inferência de linguagem natural e não é apenas o tamanho que importa: os modelos de idiomas pequenos também são poucos alunos. Os artigos introduzem treinamento em exploração de padrões (PET), um procedimento de treinamento semi-supervisionado que reformula exemplos de entrada como frases no estilo de cloze. Em ambientes de baixo resistência, o PET e o IPET superam significativamente o treinamento supervisionado regulares, várias linhas de base semi-supervisionadas e até o GPT-3, apesar de exigir 99,9% menos parâmetros. A variante iterativa do PET (IPET) treina várias gerações de modelos e pode até ser usada sem dados de treinamento.
| #Examples | Modo de treinamento | Yelp (completo) | Notícias da AG | Perguntas do Yahoo | Mnli |
|---|---|---|---|---|---|
| 0 | não supervisionado | 33.8 | 69.5 | 44.0 | 39.1 |
| Ipet | 56.7 | 87.5 | 70.7 | 53.6 | |
| 100 | supervisionado | 53.0 | 86.0 | 62.9 | 47.9 |
| BICHO DE ESTIMAÇÃO | 61.9 | 88.3 | 69.2 | 74.7 | |
| Ipet | 62.9 | 89.6 | 71.2 | 78.4 |
Nota : Para reproduzir exatamente os resultados acima, use V1.1.0 ( --branch v1.1.0 ).
? Configurar
Uso da CLI
Uso da API
? Treine seu próprio animal de estimação
Citação
Todos os requisitos para PET podem ser encontrados no requirements.txt . Você pode instalar todos os pacotes necessários com pip install -r requirements.txt .
Atualmente, a interface da linha de comando cli.py neste repositório suporta três modos de treinamento diferentes (PET, IPET, treinamento supervisionado), dois métodos de avaliação adicionais (não supervisionados e iniciantes) e 13 tarefas diferentes. Para avaliações do Yelp, as notícias da AG, o Yahoo Questions, MNLI e X-posnce, consulte o artigo original para obter mais detalhes. Para as 8 tarefas de supercúlus, consulte este artigo.
Para treinar e avaliar um modelo de estimação para uma das tarefas suportadas, basta executar o seguinte comando:
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
onde
$PATTERN_IDS Especifica os PVPs a serem usados. Por exemplo, se você deseja usar todos os padrões, especifique PATTERN_IDS 0 1 2 3 4 para as notícias da AG e perguntas do Yahoo ou PATTERN_IDS 0 1 2 3 para revisões do Yelp e MNLI.$DATA_DIR é o diretório que contém os arquivos de trem e teste (verifique tasks.py para ver como esses arquivos devem ser nomeados e formatados para cada tarefa).$MODEL_TYPE é o nome do modelo que está sendo usado, por exemplo, albert , bert ou roberta .$MODEL_NAME é o nome de um modelo pré-treinamento (por exemplo, roberta-large ou albert-xxlarge-v2 ) ou o caminho para um modelo pré-treinado.$TASK_NAME é o nome da tarefa para treinar e avaliar.$OUTPUT_DIR é o nome do diretório no qual o modelo treinado e os resultados da avaliação são salvos. Além disso, você pode especificar vários parâmetros de treinamento para o conjunto de modelos de PET correspondentes a PVPs individuais (prefixo --pet_ ) e para o modelo de classificação de sequência final (prefixo --sc_ ). Por exemplo, os parâmetros padrão usados para nossa avaliação de supercola são:
--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
Para cada padrão $P e repetição $I , executando o comando acima cria um diretório $OUTPUT_DIR/p$Pi$I que contém os seguintes arquivos:
pytorch_model.bin : o modelo Finetuned, possivelmente junto com alguns arquivos específicos do modelo (por exemplo, spiece.model , special_tokens_map.json )wrapper_config.json : a configuração do modelo que está sendo usadotrain_config.json : A configuração usada para treinamentoeval_config.json : a configuração usada para avaliaçãologits.txt : as previsões do modelo nos dados não marcadoseval_logits.txt : a previsão do modelo nos dados de avaliaçãoresults.json : Um arquivo JSON contendo resultados como a precisão final do modelopredictions.jsonl : um arquivo de previsão para o conjunto de avaliação no formato de superclua O modelo final (destilado) para cada repetição $I posso ser encontrado em $OUTPUT_DIR/final/p0-i$I , que contém os mesmos arquivos descritos acima.
Se o seu GPU ficar sem memória durante o treinamento, você poderá tentar diminuir o pet_per_gpu_train_batch_size e o sc_per_gpu_unlabeled_batch_size enquanto aumenta o pet_gradient_accumulation_steps e sc_gradient_accumulation_steps .
Para treinar e avaliar um modelo IPET para uma das tarefas suportadas, basta executar o mesmo comando acima, mas substitua --method pet pelo --method ipet . Existem vários parâmetros de IPET adicionais que você pode modificar; Todos eles são prefixados com --ipet_ .
Para cada geração $G , padrão $P e iteração $I , isso cria um diretório $OUTPUT_DIR/g$G/p$Pi$I , que é estruturado como para o animal de estimação comum. O modelo final (destilado) pode ser encontrado novamente em $OUTPUT_DIR/final/p0-i$I .
Se você usar o IPET com zero exemplos de treinamento, precisará especificar quantos exemplos para cada rótulo devem ser escolhidos na primeira geração e precisará alterar a estratégia de redução para significar: --ipet_n_most_likely 100 --reduction mean .
Para treinar e avaliar um classificador de sequência regular de maneira supervisionada, basta executar o mesmo comando acima, mas substitua --method pet por --method sequence_classifier . Existem vários parâmetros adicionais para o classificador de sequência que você pode modificar; Todos eles são prefixados com --sc_ .
Para avaliar um modelo de linguagem pré-teria com os padrões e verbalizadores de PET padrão, mas sem ajuste fino, remova o argumento --do_train e adicione --no_distillation para que nenhuma destilação final seja realizada.
Se você deseja usar a preparação, remova o argumento --do_train e adicione os argumentos --priming --no_distillation para que todos os exemplos de treinamento sejam usados para iniciar e nenhuma destilação final seja realizada.
Lembre -se de que você pode precisar aumentar o comprimento da sequência máxima para um valor muito maior, por exemplo --pet_max_seq_length 5000 . Isso funciona apenas com modelos de idiomas que suportam seqüências tão longas, por exemplo, XLNET. Para usar o XLNET, você pode especificar --model_type xlnet --model_name_or_path xlnet-large-cased --wrapper_type plm .
Em vez de usar a interface da linha de comando, você também pode usar diretamente a API PET, a maioria é definida no pet.modeling . Ao incluir import pet , você pode acessar métodos como train_pet , train_ipet e train_classifier . Confira a documentação deles para obter mais informações.
Para usar o PET para tarefas personalizadas, você precisa definir duas coisas:
examples/custom_task_processor.py Por exemplo.examples/custom_task_pvp.py para um exemplo.Depois de implementar o DataProcessor e o PVP, você pode treinar um modelo de PET usando a linha de comando conforme descrito acima. Abaixo, você pode encontrar informações adicionais sobre como definir os dois componentes de um PVP, verbalizadores e padrões .
Os verbalizadores são usados para mapear os rótulos das tarefas para as palavras em linguagem natural. Por exemplo, em uma tarefa de classificação de sentimentos binários, você pode mapear o rótulo positivo ( +1 ) para a palavra good e o rótulo negativo ( -1 ) para a palavra bad . Os verbalizadores são realizados através do método verbalize() de um PVP. A maneira mais simples de definir um verbalizador é usar um dicionário:
VERBALIZER = { "+1" : [ "good" ], "-1" : [ "bad" ]}
def verbalize ( self , label ) -> List [ str ]:
return self . VERBALIZER [ label ] É importante ressaltar que, na versão atual do PET, os verbalizadores são, por padrão, restritos a tokens únicos no vocabulário LMS subjacente (por usar mais de um token, veja abaixo). Dado o tokenizador de um modelo de idioma, você pode facilmente verificar se uma palavra corresponde a um único token verificando que len(tokenizer.tokenize(word)) == 1 .
Você também pode definir várias verbalizações para um único rótulo. Por exemplo, se você não tiver certeza de quais palavras representam melhor os rótulos em uma tarefa de classificação de sentimentos binários, poderá definir seu verbalizador da seguinte maneira:
VERBALIZER = { "+1" : [ "great" , "good" , "wonderful" , "perfect" ], "-1" : [ "bad" , "terrible" , "horrible" ]} Os padrões são usados para fazer com que o modelo de idioma entenda uma determinada tarefa; Eles devem conter exatamente um token <MASK> que deve ser preenchido usando o verbalizador. Para classificação de sentimentos binários com base no resumo de uma revisão ( <A> ) e no corpo ( <B> ), um padrão adequado pode ser <A>. <B>. Overall, it was <MASK>. Os padrões são realizados através do método get_parts() do PVP, que retorna um par de sequências de texto (onde cada sequência é representada por uma lista de strings):
def get_parts ( self , example : InputExample ):
return [ example . text_a , '.' , example . text_b , '.' ], [ 'Overall, it was ' , self . mask ]Se você não quiser usar um par de seqüências, você pode simplesmente deixar a segunda sequência vazia:
def get_parts ( self , example : InputExample ):
return [ example . text_a , '.' , example . text_b , '. Overall, it was ' , self . mask ], [] Se você deseja definir vários padrões, basta usar o atributo 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 , '.' ], [] Ao treinar o modelo usando a linha de comando, especifique todos os padrões a serem usados (por exemplo, --pattern_ids 1 2 ).
É importante ressaltar que, se uma sequência for mais longa que o comprimento máximo especificado da sequência do LM subjacente, o PET deve saber quais partes da entrada podem ser reduzidas e quais não podem (por exemplo, o token da máscara deve sempre estar lá). Portanto, PVP fornece um método shortenable() para indicar que um pedaço de texto pode ser reduzido:
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 ], []Por padrão, a implementação atual de PET e IPET suporta apenas um conjunto fixo de rótulos compartilhados em todos os exemplos e verbalizadores que correspondem a um único token. No entanto, para algumas tarefas, pode ser necessário usar verbalizadores que correspondem a vários tokens (conforme descrito aqui). Para fazer isso, você simplesmente precisa das duas modificações a seguir:
Adicione as seguintes linhas no DataProcessor da sua tarefa (consulte examples/custom_task_processor.py ):
from pet . tasks import TASK_HELPERS
from pet . task_helpers import MultiMaskTaskHelper
TASK_HELPERS [ 'my_task' ] = MultiMaskTaskHelper onde 'my_task' é o nome da sua tarefa.
No seu PVP , verifique se o método get_parts() sempre insere o número máximo de tokens de máscara necessários para qualquer verbalização. Por exemplo, se o seu verbalizador mapear +1 para "realmente incrível" e -1 a "terrível" e se forem tokenizados como ["really", "awe", "##some"] e ["terrible"] , respectivamente, seu método get_parts() sempre retornará uma sequência que contenha exatamente 3 tokens.
Com esta modificação, agora você pode usar os verbalizadores que consistem em vários tokens:
VERBALIZER = { "+1" : [ "really good" ], "-1" : [ "just bad" ]}No entanto, existem várias limitações a serem consideradas:
MultiMaskTaskHelper , o tamanho máximo do lote para avaliação é 1.MultiMaskTaskHelper é um recurso experimental que não é bem testado. Em particular, esse recurso só foi testado para PET e não para IPET. Se você observar algo estranho, por favor, levante um problema. Para obter mais flexibilidade, você também pode escrever um TaskHelper personalizado. Como ponto de partida, você pode conferir as aulas CopaTaskHelper , WscTaskHelper e RecordTaskHelper em pet/task_helpers.py .
Se você usar o código neste repositório, cite os seguintes papéis:
@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}
}