Pré-processamento de dados Pré-processamento de dados
Nos transformadores, a principal ferramenta para processamento de dados é o text tokenizer tokenizer
. Podemos usar o tipo de tokenizador de texto correspondente ao modelo ou podemos usar a AutoTokenizer
classificação automática diretamente.
Um tokenizador de texto primeiro divide o texto em palavras, sinais de pontuação, etc. Esses elementos de divisão são chamados de token
. Em seguida, ele será token
convertido em um número para que possa ser convertido em um tensor para treinamento tensor
. CLS
Além disso, alguns tokenizadores de texto específicos também adicionarão algumas tags especiais exigidas pelo modelo, como , em BERT SEP
.
Observação:
se você quiser usar um modelo pré-treinado, precisará usar o tokenizador de texto correspondente do modelo. Como o tokenizador de texto correspondente transforma o texto da mesma forma que seu modelo foi treinado, o vocabulário correspondente também é o mesmo. Se o tokenizador de texto estiver errado, ele terá um grande impacto na previsão ou ajuste fino do modelo. Por exemplo, o índice original da palavra "I" é 1, e o índice do "I" em outro tokenizador de texto é 100, o que faz com que os dados recebidos pelo modelo sejam completamente diferentes do que você pensa.
Para baixar automaticamente o tokenizador de texto usado ao treinar ou ajustar o modelo, você pode usar from_pretrained()
o método:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
uso básico
pré-processando
Os tokenizadores de texto em transformadores têm muitos métodos, mas há apenas um método para pré-processamento, ou seja __call__
: você apenas alimenta o texto diretamente no objeto tokenizador de texto. do seguinte modo:
encoded_input = tokenizer("Hello, I'm a single sentence!")
print(encoded_input)
输出:
{
'input_ids': [101, 8667, 117, 146, 112, 182, 170, 1423, 5650, 106, 102],
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
Este método retorna um dicionário. input_ids
é token
o índice de cada um no texto de entrada. attention_mask
O uso de e será discutido posteriormente token_type_ids
.
decodificação
Além de codificar o texto, os tokenizadores de texto também podem decodificar índices:
print(tokenizer.decode(encoded_input["input_ids"]))
输出:
[CLS] Hello, I'm a single sentence! [SEP]
Podemos ver que o tagger de texto adicionou automaticamente as tags especiais exigidas pelo BERT durante o pré-processamento.
gtp2-medium
Nem todos os modelos requerem marcação especial, se não usarmos bert-base-cased
, podemos obter o mesmo resultado do texto original ao decodificar.
Ao decodificar, também podemos adicionar parâmetros ao método add_special_tokens=False
para remover tags especiais (algumas versões são skip_special_tokens=True
).
dados múltiplos
Se você deseja processar vários textos de uma só vez, pode combiná-los em uma matriz, dentro e fora do tokenizador de texto de uma só vez, da seguinte maneira:
batch_sentences = ["Hello I'm a single sentence",
"And another sentence",
"And the very very last one"]
encoded_inputs = tokenizer(batch_sentences)
print(encoded_inputs)
输出:
{
'input_ids': [[101, 8667, 146, 112, 182, 170, 1423, 5650, 102],
[101, 1262, 1330, 5650, 102],
[101, 1262, 1103, 1304, 1304, 1314, 1141, 102]],
'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1]]}
Preencher, truncar, retornar tipos específicos
Ao processar várias declarações de uma só vez, também podemos ter os seguintes requisitos:
- preencha cada frase com o comprimento máximo do lote
- Truncar cada frase para o comprimento máximo que o modelo pode aceitar
tensor
dados do tipo de retorno
Você pode atingir todos os requisitos com as seguintes operações:
batch = tokenizer(batch_sentences, max_length=7, padding=True, truncation=True, return_tensors="pt", )
print(batch)
结果:
{
'input_ids': tensor([
[ 101, 8667, 146, 112, 182, 170, 102],
[ 101, 1262, 1330, 5650, 102, 0, 0],
[ 101, 1262, 1103, 1304, 1304, 1314, 102]]),
'token_type_ids': tensor([
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]]),
'attention_mask': tensor([
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 1]])}
pytorch.tensor
Desta vez, um dicionário de strings para tipos é retornado . Agora podemos ver o uso com base nos resultados retornados attention_mask
: ele dirá ao modelo quais token
devem ser prestados atenção e quais não devem ser ignorados, porque alguns não têm sentido para o preenchimento token
.
Observe que o código acima emitirá um aviso quando executado se for usado um modelo que não tenha um comprimento máximo associado a ele. Isso é bom e pode ser ignorado, ou parâmetros podem ser adicionados verbose=False
para evitar que o tokenizador de texto lance essas exceções.
processamento de pares de frases
Às vezes pode ser necessário inserir um par de frases no modelo. Por exemplo, precisamos julgar se duas frases são semelhantes; ou estamos usando um modelo de resposta a perguntas e precisamos inserir texto e perguntas no modelo. Para BERT
o modelo, os pares de sentenças precisam ser transformados na seguinte forma:[CLS] Sequence A [SEP] Sequence B [SEP]
Ao usar Transformers para processar pares de sentenças, precisamos passar as duas sentenças para o tokenizador de texto como variáveis diferentes (observe que ele não está integrado em uma lista como antes, mas em duas variáveis separadas). Em seguida, obteremos um dicionário correspondente, como no exemplo a seguir:
encoded_input = tokenizer("How old are you?", "I'm 6 years old")
print(encoded_input)
print(tokenizer.decode(encoded_input["input_ids"]))
for i in encoded_input["input_ids"]:
print(tokenizer.decode(i))
结果:
{
'input_ids': [101, 1731, 1385, 1132, 1128, 136, 102, 146, 112, 182, 127, 1201, 1385, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
[CLS] How old are you? [SEP] I'm 6 years old [SEP]
[ C L S ]
H o w
o l d
a r e
y o u
?
[ S E P ]
I
'
m
6
y e a r s
o l d
[ S E P ]
A partir dos resultados podemos ver token_type_ids
o efeito: eles informam ao modelo qual parte da entrada pertence à primeira sentença e qual parte pertence à segunda sentença. Observe que nem todos os modelos exigem isso token_tyoe_ids
. Por padrão, os tokenizadores de texto retornarão apenas a entrada desejada em relação ao modelo. Você pode passar alguns parâmetros como return_token_type_ids
ou return_length
para alterar a saída do tokenizador de texto.
encoded_input = tokenizer("How old are you?", "I'm 6 years old",
return_token_type_ids=False,
return_length=True,
)
print(encoded_input)
输出:
{
'input_ids': [101, 1731, 1385, 1132, 1128, 136, 102, 146, 112, 182, 127, 1201, 1385, 102], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'length': 14}
Além disso, se você deseja processar várias instruções de uma só vez, pode passar duas listas de texto separadamente. do seguinte modo:
batch_sentences = ["Hello I'm a single sentence",
"And another sentence",
"And the very very last one"]
batch_of_second_sentences = ["I'm a sentence that goes with the first sentence",
"And I should be encoded with the second sentence",
"And I go with the very last one"]
encoded_inputs = tokenizer(batch_sentences, batch_of_second_sentences)
print(encoded_inputs)
结果:
{
'input_ids': [[101, 8667, 146, 112, 182, 170, 1423, 5650, 102, 146, 112, 182, 170, 5650, 1115, 2947, 1114, 1103, 1148, 5650, 102],
[101, 1262, 1330, 5650, 102, 1262, 146, 1431, 1129, 12544, 1114, 1103, 1248, 5650, 102],
[101, 1262, 1103, 1304, 1304, 1314, 1141, 102, 1262, 146, 1301, 1114, 1103, 1304, 1314, 1141, 102]],
'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
input_ids
Podemos verificar nossa entrada percorrendo a lista decodificada , como segue:
for ids in encoded_inputs["input_ids"]:
print(tokenizer.decode(ids))
结果:
[CLS] Hello I'm a single sentence [SEP] I'm a sentence that goes with the first sentence [SEP]
[CLS] And another sentence [SEP] And I should be encoded with the second sentence [SEP]
[CLS] And the very very last one [SEP] And I go with the very last one [SEP]
E você ainda pode inserir alguns parâmetros para preencher ou interceptar o texto, ou convertê-lo para um tipo específico na hora da codificação, como segue:
batch = tokenizer(batch_sentences, batch_of_second_sentences, padding=True, truncation=True, return_tensors="pt")
algo sobre preenchimento e truncamento
As instruções aplicáveis na maioria dos casos foram apresentadas acima. Mas o Transformers também fornece mais métodos, que giram em torno de três parâmetros padding
, truncation
, max_length
para expandir.
padding
Usado para controlar o preenchimento. Pode ser do tipo booleano ou do tipo string, conforme abaixo:True
ou”longest”
para preencher todas as sentenças até o comprimento máximo na lista de sequências, ou não fazer nada se você fornecer apenas uma sentença.“max_length”
É utilizado para preencher a sequência até o comprimento do parâmetro , caso nãomax_length
seja informado nenhummax_length
parâmetro ( )max_length=None
, será preenchido até o comprimento máximo que o modelo pode aceitar. E também funciona quando você fornece apenas uma frase.False
ou”do_not_pad”
para definir como sem preenchimento. E este é o valor padrão do parâmetro.
truncation
Usado para controlar o truncamento. Pode ser booleano ou string.True
Ou“only_first”
a sentença é truncada para o comprimento do parâmetro, se nenhum parâmetro ( )max_length
for fornecido , a sentença é truncada para o comprimento máximo aceitável para o modelo. Se os dados fornecidos forem um par de sentenças ou um lote de pares de sentenças, somente a primeira sentença será truncada.max_length
max_length=None
“only_sceond”
Trunque a frase paramax_length
o comprimento do parâmetro, se nenhummax_length
parâmetro (max_length=None
) for fornecido, ela será truncada para o comprimento máximo que o modelo pode aceitar. Quando os dados de entrada são um par de frases, apenas o segundo dado será truncado.False
Ou”do_not_truncate”
indicar que a sentença não deve ser interceptada. E este é o valor padrão do parâmetro.
max_length
Usado para controlar o comprimento do preenchimento ou truncamento. Pode ser整数
ouNone
, o padrão é o grau máximo que o modelo pode aceitar. Se o modelo não tiver um comprimento de entrada máximo específico, ele será truncado ou preenchido paramax_length
.
Alguns resumos de uso
Se no exemplo a seguir, a entrada for um par de frases, você pode truncation=True
substituir ** por STRATEGY
, as opções são as seguintes:['only_first', 'only_second', 'longest_first']
**.
- não trunque
- Não preenchido:
**tokenizer(batch_sentences)**
- pad até o comprimento máximo do lote atual:
**tokenizer(batch_sentences, padding=True)**
ou**tokenizer(batch_sentences, padding=’longest’)**
- Almofada até o comprimento máximo aceitável do modelo:
**tokenizer(batch_sentences, padding='max_length')**
- Preenchimento para um comprimento específico:
**tokenizer(batch_sentences, padding='max_length', max_length=42)**
- Não preenchido:
- Truncar para o comprimento máximo da entrada do modelo
- Sem preenchimento:
tokenizer(batch_sentences, truncation=True)
outokenizer(batch_sentences, padding=True, truncation=STRATEGY)
**** - pad até o comprimento máximo do lote atual:
tokenizer(batch_sentences, padding=True, truncation=True)
outokenizer(batch_sentences, padding=True, truncation=STRATEGY)
- Preenchimento até o comprimento máximo aceitável do modelo:
tokenizer(batch_sentences, padding='max_length', truncation=True)
outokenizer(batch_sentences, padding='max_length', truncation=STRATEGY)
- Preencher até um comprimento específico: não pode ser feito porque a adição de
max_length
parâmetros não pode preencher e truncar a entrada máxima.
- Sem preenchimento:
- truncar para um comprimento específico
- sem preenchimento: ou
tokenizer(batch_sentences, truncation=True, max_length=42)
tokenizer(batch_sentences, truncation=STRATEGY, max_length=42)
- Pad até o comprimento máximo do lote atual: ou
tokenizer(batch_sentences, padding=True, truncation=True, max_length=42)
tokenizer(batch_sentences, padding=True, truncation=STRATEGY, max_length=42)
- Preenchimento até o comprimento máximo aceitável do modelo: não é possível
- almofada para um comprimento específico: ou
tokenizer(batch_sentences, padding='max_length', truncation=True, max_length=42)
tokenizer(batch_sentences, padding='max_length', truncation=STRATEGY, max_length=42)
- sem preenchimento: ou
entrada pré-rotulada
Os tokenizadores também podem aceitar entrada pré-tokenizada. Isso é importante em tarefas de reconhecimento de entidade nomeada e marcação de parte da fala.
Deve-se notar que a entrada pré-rotulada não é uma entrada indexada, mas apenas divide as palavras,
Para usar a entrada pré-marcada, basta definir o parâmetro como is_split_into_words=True
. Os exemplos são os seguintes:
encoded_input = tokenizer(["Hello", "I'm", "a", "single", "sentence"], is_split_into_words=True)
print(encoded_input)
结果:
{
'input_ids': [101, 8667, 146, 112, 182, 170, 1423, 5650, 102],
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
Nota: A entrada pré-identificada também adicionará tags especiais relacionadas ao modelo, a menos que o parâmetro de atributo seja add_special_tokens=False
.
Digite várias frases
As frases múltiplas de entrada pré-token são exatamente as mesmas de antes, você pode codificar várias frases como esta:
batch_sentences = [["Hello", "I'm", "a", "single", "sentence"],
["And", "another", "sentence"],
["And", "the", "very", "very", "last", "one"]]
encoded_inputs = tokenizer(batch_sentences, is_split_into_words=True)
par de frases de entrada
Os pares de frases também podem ser inseridos assim:
batch_of_second_sentences = [["I'm", "a", "sentence", "that", "goes", "with", "the", "first", "sentence"],
["And", "I", "should", "be", "encoded", "with", "the", "second", "sentence"],
["And", "I", "go", "with", "the", "very", "last", "one"]]
encoded_inputs = tokenizer(batch_sentences, batch_of_second_sentences, is_split_into_words=True)
preenchimento e truncamento
Também é possível preencher e truncar como antes:
batch = tokenizer(batch_sentences,
batch_of_second_sentences,
is_split_into_words=True,
padding=True,
truncation=True,
return_tensors="pt")