Criar uma arquitetura customizada
Uma AutoClass
automaticamente infere a arquitetura do modelo e baixa configurações e pesos pré-treinados. Geralmente, nós recomendamos usar uma AutoClass
para produzir um código independente de checkpoints. Mas usuários que querem mais contole sobre parâmetros específicos do modelo pode criar um modelo customizado 🤗 Transformers a partir de algumas classes bases. Isso pode ser particulamente útil para alguém que está interessado em estudar, treinar ou fazer experimentos com um modelo 🤗 Transformers. Nesse tutorial, será explicado como criar um modelo customizado sem uma AutoClass
. Aprenda como:
- Carregar e customizar a configuração de um modelo.
- Criar a arquitetura de um modelo.
- Criar um tokenizer rápido e devagar para textos.
- Criar extrator de features para tarefas envolvendo audio e imagem.
- Criar um processador para tarefas multimodais.
configuration
A configuration refere-se a atributos específicos de um modelo. Cada configuração de modelo tem atributos diferentes; por exemplo, todos modelo de PLN possuem os atributos hidden_size
, num_attention_heads
, num_hidden_layers
e vocab_size
em comum. Esse atributos especificam o numero de ‘attention heads’ ou ‘hidden layers’ para construir um modelo.
Dê uma olhada a mais em DistilBERT acessando DistilBertConfig
para observar esses atributos:
>>> from transformers import DistilBertConfig
>>> config = DistilBertConfig()
>>> print(config)
DistilBertConfig {
"activation": "gelu",
"attention_dropout": 0.1,
"dim": 768,
"dropout": 0.1,
"hidden_dim": 3072,
"initializer_range": 0.02,
"max_position_embeddings": 512,
"model_type": "distilbert",
"n_heads": 12,
"n_layers": 6,
"pad_token_id": 0,
"qa_dropout": 0.1,
"seq_classif_dropout": 0.2,
"sinusoidal_pos_embds": false,
"transformers_version": "4.16.2",
"vocab_size": 30522
}
DistilBertConfig
mostra todos os atributos padrões usados para construir um DistilBertModel
base. Todos atributos são customizáveis, o que cria espaço para experimentos. Por exemplo, você pode customizar um modelo padrão para:
- Tentar uma função de ativação diferente com o parâmetro
activation
. - Usar uma taxa de desistência maior para as probabilidades de ‘attention’ com o parâmetro
attention_dropout
.
>>> my_config = DistilBertConfig(activation="relu", attention_dropout=0.4)
>>> print(my_config)
DistilBertConfig {
"activation": "relu",
"attention_dropout": 0.4,
"dim": 768,
"dropout": 0.1,
"hidden_dim": 3072,
"initializer_range": 0.02,
"max_position_embeddings": 512,
"model_type": "distilbert",
"n_heads": 12,
"n_layers": 6,
"pad_token_id": 0,
"qa_dropout": 0.1,
"seq_classif_dropout": 0.2,
"sinusoidal_pos_embds": false,
"transformers_version": "4.16.2",
"vocab_size": 30522
}
Atributos de um modelo pré-treinado podem ser modificados na função from_pretrained()
:
>>> my_config = DistilBertConfig.from_pretrained("distilbert/distilbert-base-uncased", activation="relu", attention_dropout=0.4)
Uma vez que você está satisfeito com as configurações do seu modelo, você consegue salvar elas com save_pretrained()
. Seu arquivo de configurações está salvo como um arquivo JSON no diretório especificado:
>>> my_config.save_pretrained(save_directory="./your_model_save_path")
Para reusar o arquivo de configurações, carregue com from_pretrained()
:
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/my_config.json")
Você pode também salvar seu arquivo de configurações como um dicionário ou até mesmo com a diferença entre as seus atributos de configuração customizados e os atributos de configuração padrões! Olhe a documentação configuration para mais detalhes.
Modelo
O próximo passo é criar um model. O modelo - também vagamente referido como arquitetura - define o que cada camada está fazendo e quais operações estão acontecendo. Atributos como num_hidden_layers
das configurações são utilizados para definir a arquitetura. Todo modelo compartilha a classe base PreTrainedModel
e alguns métodos em comum como redimensionar o tamanho dos embeddings de entrada e podar as ‘self-attention heads’. Além disso, todos os modelos também são subclasses de torch.nn.Module
, tf.keras.Model
ou flax.linen.Module
. Isso significa que os modelos são compatíveis com cada respectivo uso de framework.
Carregar seus atributos de configuração customizados em um modelo:
>>> from transformers import DistilBertModel
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/my_config.json")
>>> model = DistilBertModel(my_config)
Isso cria um modelo com valores aleatórios ao invés de pré-treinar os pesos. Você não irá conseguir usar usar esse modelo para nada útil ainda, até você treinar ele. Treino é um processo caro e demorado. Geralmente é melhor utilizar um modelo pré-treinado para obter melhores resultados mais rápido, enquanto usa apenas uma fração dos recursos necessários para treinar.
Criar um modelo pré-treinado com from_pretrained()
:
>>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased")
Quando você carregar os pesos pré-treinados, a configuração padrão do modelo é automaticamente carregada se o modelo é provido pelo 🤗 Transformers. No entanto, você ainda consegue mudar - alguns ou todos - os atributos padrões de configuração do modelo com os seus próprio atributos, se você preferir:
>>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased", config=my_config)
Carregar os seus próprios atributos padrões de contiguração no modelo:
>>> from transformers import TFDistilBertModel
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/my_config.json")
>>> tf_model = TFDistilBertModel(my_config)
Isso cria um modelo com valores aleatórios ao invés de pré-treinar os pesos. Você não irá conseguir usar usar esse modelo para nada útil ainda, até você treinar ele. Treino é um processo caro e demorado. Geralmente é melhor utilizar um modelo pré-treinado para obter melhores resultados mais rápido, enquanto usa apenas uma fração dos recursos necessários para treinar.
Criar um modelo pré-treinado com from_pretrained()
:
>>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased")
Quando você carregar os pesos pré-treinados, a configuração padrão do modelo é automaticamente carregada se o modelo é provido pelo 🤗 Transformers. No entanto, você ainda consegue mudar - alguns ou todos - os atributos padrões de configuração do modelo com os seus próprio atributos, se você preferir:
>>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased", config=my_config)
Heads do modelo
Neste ponto, você tem um modelo básico do DistilBERT que gera os estados ocultos. Os estados ocultos são passados como entrada para a head do moelo para produzir a saída final. 🤗 Transformers fornece uma head de modelo diferente para cada tarefa desde que o modelo suporte essa tarefa (por exemplo, você não consegue utilizar o modelo DistilBERT para uma tarefa de ‘sequence-to-sequence’ como tradução).
Por exemplo, DistilBertForSequenceClassification
é um modelo DistilBERT base com uma head de classificação de sequência. A head de calssificação de sequência é uma camada linear no topo das saídas agrupadas.
>>> from transformers import DistilBertForSequenceClassification
>>> model = DistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
Reutilize facilmente esse ponto de parada para outra tarefe mudando para uma head de modelo diferente. Para uma tarefe de responder questões, você usaria a head do modelo DistilBertForQuestionAnswering
. A head de responder questões é similar com a de classificação de sequências exceto o fato de que ela é uma camada no topo dos estados das saídas ocultas.
>>> from transformers import DistilBertForQuestionAnswering
>>> model = DistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
Por exemplo, TFDistilBertForSequenceClassification
é um modelo DistilBERT base com uma head de classificação de sequência. A head de calssificação de sequência é uma camada linear no topo das saídas agrupadas.
>>> from transformers import TFDistilBertForSequenceClassification
>>> tf_model = TFDistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
Reutilize facilmente esse ponto de parada para outra tarefe mudando para uma head de modelo diferente. Para uma tarefe de responder questões, você usaria a head do modelo TFDistilBertForQuestionAnswering
. A head de responder questões é similar com a de classificação de sequências exceto o fato de que ela é uma camada no topo dos estados das saídas ocultas.
>>> from transformers import TFDistilBertForQuestionAnswering
>>> tf_model = TFDistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
Tokenizer
A útlima classe base que você precisa antes de usar um modelo para dados textuais é a tokenizer para converter textos originais para tensores. Existem dois tipos de tokenizers que você pode usar com 🤗 Transformers:
PreTrainedTokenizer
: uma implementação em Python de um tokenizer.PreTrainedTokenizerFast
: um tokenizer da nossa biblioteca 🤗 Tokenizer baseada em Rust. Esse tipo de tokenizer é significantemente mais rapido - especialmente durante tokenization de codificação - devido a implementação em Rust. O tokenizer rápido tambem oferece métodos adicionais como offset mapping que mapeia tokens para suar palavras ou caracteres originais.
Os dois tokenizers suporta métodos comuns como os de codificar e decodificar, adicionar novos tokens, e gerenciar tokens especiais.
Nem todo modelo suporta um ‘fast tokenizer’. De uma olhada aqui table pra checar se um modelo suporta ‘fast tokenizer’.
Se você treinou seu prórpio tokenizer, você pode criar um a partir do seu arquivo vocabulary:
>>> from transformers import DistilBertTokenizer
>>> my_tokenizer = DistilBertTokenizer(vocab_file="my_vocab_file.txt", do_lower_case=False, padding_side="left")
É importante lembrar que o vocabulário de um tokenizer customizado será diferente de um vocabulário gerado pelo tokenizer de um modelo pré treinado. Você precisa usar o vocabulário de um modelo pré treinado se você estiver usando um modelo pré treinado, caso contrário as entradas não farão sentido. Criando um tokenizer com um vocabulário de um modelo pré treinado com a classe DistilBertTokenizer
:
>>> from transformers import DistilBertTokenizer
>>> slow_tokenizer = DistilBertTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
Criando um ‘fast tokenizer’ com a classe DistilBertTokenizerFast
:
>>> from transformers import DistilBertTokenizerFast
>>> fast_tokenizer = DistilBertTokenizerFast.from_pretrained("distilbert/distilbert-base-uncased")
Pos padrão, AutoTokenizer
tentará carregar um ‘fast tokenizer’. Você pode disabilitar esse comportamento colocando use_fast=False
no from_pretrained
.
Extrator de features
Um extrator de features processa entradas de imagem ou áudio. Ele herda da classe base FeatureExtractionMixin
, e pode também herdar da classe ImageFeatureExtractionMixin
para processamento de features de imagem ou da classe SequenceFeatureExtractor
para processamento de entradas de áudio.
Dependendo do que você está trabalhando em um audio ou uma tarefa de visão, crie um estrator de features associado com o modelo que você está usando. Por exemplo, crie um ViTFeatureExtractor
padrão se você estiver usando ViT para classificação de imagens:
>>> from transformers import ViTFeatureExtractor
>>> vit_extractor = ViTFeatureExtractor()
>>> print(vit_extractor)
ViTFeatureExtractor {
"do_normalize": true,
"do_resize": true,
"feature_extractor_type": "ViTFeatureExtractor",
"image_mean": [
0.5,
0.5,
0.5
],
"image_std": [
0.5,
0.5,
0.5
],
"resample": 2,
"size": 224
}
Se você não estiver procurando por nenhuma customização, apenas use o método from_pretrained
para carregar parâmetros do modelo de extrator de features padrão.
Modifique qualquer parâmetro dentre os ViTFeatureExtractor
para criar seu extrator de features customizado.
>>> from transformers import ViTFeatureExtractor
>>> my_vit_extractor = ViTFeatureExtractor(resample="PIL.Image.BOX", do_normalize=False, image_mean=[0.3, 0.3, 0.3])
>>> print(my_vit_extractor)
ViTFeatureExtractor {
"do_normalize": false,
"do_resize": true,
"feature_extractor_type": "ViTFeatureExtractor",
"image_mean": [
0.3,
0.3,
0.3
],
"image_std": [
0.5,
0.5,
0.5
],
"resample": "PIL.Image.BOX",
"size": 224
}
Para entradas de áutio, você pode criar um Wav2Vec2FeatureExtractor
e customizar os parâmetros de uma forma similar:
>>> from transformers import Wav2Vec2FeatureExtractor
>>> w2v2_extractor = Wav2Vec2FeatureExtractor()
>>> print(w2v2_extractor)
Wav2Vec2FeatureExtractor {
"do_normalize": true,
"feature_extractor_type": "Wav2Vec2FeatureExtractor",
"feature_size": 1,
"padding_side": "right",
"padding_value": 0.0,
"return_attention_mask": false,
"sampling_rate": 16000
}
Processor
Para modelos que suportam tarefas multimodais, 🤗 Transformers oferece uma classe processadora que convenientemente cobre um extrator de features e tokenizer dentro de um único objeto. Por exemplo, vamos usar o Wav2Vec2Processor
para uma tarefa de reconhecimento de fala automática (ASR). ASR transcreve áudio para texto, então você irá precisar de um extrator de um features e um tokenizer.
Crie um extrator de features para lidar com as entradas de áudio.
>>> from transformers import Wav2Vec2FeatureExtractor
>>> feature_extractor = Wav2Vec2FeatureExtractor(padding_value=1.0, do_normalize=True)
Crie um tokenizer para lidar com a entrada de textos:
>>> from transformers import Wav2Vec2CTCTokenizer
>>> tokenizer = Wav2Vec2CTCTokenizer(vocab_file="my_vocab_file.txt")
Combine o extrator de features e o tokenizer no Wav2Vec2Processor
:
>>> from transformers import Wav2Vec2Processor
>>> processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer)
Com duas classes básicas - configuração e modelo - e um preprocessamento de classe adicional (tokenizer, extrator de features, ou processador), você pode criar qualquer modelo que suportado por 🤗 Transformers. Qualquer uma dessas classes base são configuráveis, te permitindo usar os atributos específicos que você queira. Você pode facilmente preparar um modelo para treinamento ou modificar um modelo pré-treinado com poucas mudanças.
< > Update on GitHub