# Classificação de texto

A classificação de texto é uma tarefa comum de PLN que atribui um rótulo ou classe a um texto. Algumas das maiores empresas executam a classificação de texto em produção para uma ampla variedade de aplicações práticas. Uma das formas mais populares de classificação de texto é a análise de sentimento, que atribui um rótulo como 🙂 positivo, 🙁 negativo ou 😐 neutro a uma sequência de texto.

Este guia mostrará como:

1. Ajuste o [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) no conjunto de dados [IMDb](https://huggingface.co/datasets/stanfordnlp/imdb) para determinar se uma crítica de filme é positiva ou negativa.
2. Use seu modelo ajustado para inferência.

Para ver todas as arquiteturas e checkpoints compatíveis com esta tarefa, recomendamos consultar a [página da tarefa](https://huggingface.co/tasks/text-classification).

Antes de começar, verifique se você tem todas as bibliotecas necessárias instaladas:

```bash
pip install transformers datasets evaluate accelerate
```

Recomendamos que você faça login na sua conta do Hugging Face para que possa enviar e compartilhar seu modelo com a comunidade. Quando solicitado, insira seu token para fazer login:

```py
>>> from huggingface_hub import notebook_login

>>> notebook_login()
```

## Carregar o conjunto de dados IMDb

Comece carregando o conjunto de dados IMDb a partir da biblioteca 🤗 Datasets:

```py
>>> from datasets import load_dataset

>>> imdb = load_dataset("stanfordnlp/imdb")
```

Em seguida, veja um exemplo:

```py
>>> imdb["test"][0]
{
    "label": 0,
    "text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, under-appreciated and misunderstood. I tried to like this, I really did, but it is to good TV sci-fi as Babylon 5 is to Star Trek (the original). Silly prosthetics, cheap cardboard sets, stilted dialogues, CG that doesn't match the background, and painfully one-dimensional characters cannot be overcome with a 'sci-fi' setting. (I'm sure there are those of you out there who think Babylon 5 is good sci-fi TV. It's not. It's clichéd and uninspiring.) While US viewers might like emotion and character development, sci-fi is a genre that does not take itself seriously (cf. Star Trek). It may treat important issues, yet not as a serious philosophy. It's really difficult to care about the characters here as they are not simply foolish, just missing a spark of life. Their actions and reactions are wooden and predictable, often painful to watch. The makers of Earth KNOW it's rubbish as they have to always say \"Gene Roddenberry's Earth...\" otherwise people would not continue watching. Roddenberry's ashes must be turning in their orbit as this dull, cheap, poorly edited (watching it without advert breaks really brings this home) trudging Trabant of a show lumbers into space. Spoiler. So, kill off a main character. And then bring him back as another actor. Jeeez! Dallas all over again.",
}
```

Este conjunto de dados possui dois campos:

- `text`: o texto da crítica do filme.
- `label`: um valor que é `0` para uma avaliação negativa ou `1` para uma avaliação positiva.

## Pré-processar

O próximo passo é carregar um tokenizer DistilBERT para pré-processar o campo `text`:

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
```

Crie uma função de pré-processamento para tokenizar `text` e truncar as sequências para que não excedam o comprimento máximo de entrada do DistilBERT:

```py
>>> def preprocess_function(examples):
...     return tokenizer(examples["text"], truncation=True)
```

Para aplicar a função de pré-processamento em todo o conjunto de dados, use a função [map](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset.map) do 🤗 Datasets. Você pode acelerar o `map` definindo `batched=True` para processar vários elementos do conjunto de dados de uma vez:

```py
tokenized_imdb = imdb.map(preprocess_function, batched=True)
```

Agora crie um lote de exemplos usando [DataCollatorWithPadding](/docs/transformers/main/pt/main_classes/data_collator#transformers.DataCollatorWithPadding). É mais eficiente *preencher dinamicamente* as frases até o comprimento mais longo em um lote durante a colação, em vez de preencher todo o conjunto de dados até o comprimento máximo.

```py
>>> from transformers import DataCollatorWithPadding

>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

## Avaliar

Incluir uma métrica durante o treinamento é frequentemente útil para avaliar o desempenho do seu modelo. Você pode carregar rapidamente um método de avaliação com a biblioteca 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). Para esta tarefa, carregue a métrica [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) (veja o [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) do 🤗 Evaluate para saber mais sobre como carregar e calcular uma métrica):

```py
>>> import evaluate

>>> accuracy = evaluate.load("accuracy")
```

Em seguida, crie uma função que passa suas previsões e rótulos para [compute](https://huggingface.co/docs/evaluate/main/en/package_reference/main_classes#evaluate.EvaluationModule.compute) para calcular a precisão:

```py
>>> import numpy as np

>>> def compute_metrics(eval_pred):
...     predictions, labels = eval_pred
...     predictions = np.argmax(predictions, axis=1)
...     return accuracy.compute(predictions=predictions, references=labels)
```

Sua função `compute_metrics` está pronta para uso e você voltará a ela ao configurar o treinamento.

## Treinar

Antes de iniciar o treinamento do seu modelo, crie um mapa dos ids esperados para seus rótulos com `id2label` e `label2id`:

```py
>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"}
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}
```

Se você não está familiarizado com o ajuste fino de um modelo usando o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer), dê uma olhada no tutorial básico [aqui](../training)!

Agora você está pronto para começar a treinar seu modelo! Carregue o DistilBERT com [AutoModelForSequenceClassification](/docs/transformers/main/pt/model_doc/auto#transformers.AutoModelForSequenceClassification) junto com o número de rótulos esperados e os mapeamentos de rótulos:

```py
>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer

>>> model = AutoModelForSequenceClassification.from_pretrained(
...     "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
... )
```

Neste ponto, restam apenas três etapas:

1. Defina os hiperparâmetros de treinamento em [TrainingArguments](/docs/transformers/main/pt/main_classes/trainer#transformers.TrainingArguments). O único parâmetro obrigatório é `output_dir`, que especifica onde salvar seu modelo. Você enviará este modelo para o Hub definindo `push_to_hub=True` (é necessário estar conectado ao Hugging Face para enviar seu modelo). No final de cada epoch, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) avaliará a precisão e salvará o checkpoint de treinamento.
2. Passe os argumentos de treinamento para o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) junto com o modelo, o conjunto de dados, o tokenizer, o data collator e a função `compute_metrics`.
3. Chame [train()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.train) para fazer o ajuste fino do seu modelo.

```py
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_model",
...     learning_rate=2e-5,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     num_train_epochs=2,
...     weight_decay=0.01,
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     load_best_model_at_end=True,
...     push_to_hub=True,
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=tokenized_imdb["train"],
...     eval_dataset=tokenized_imdb["test"],
...     processing_class=tokenizer,
...     data_collator=data_collator,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()
```

[Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) aplica padding dinâmico por padrão quando você passa `tokenizer` para ele. Nesse caso, você não precisa especificar um data collator explicitamente.

Quando o treinamento for concluído, compartilhe seu modelo no Hub com o método [push_to_hub()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.push_to_hub) para que todos possam usá-lo:

```py
>>> trainer.push_to_hub()
```

Para um exemplo mais detalhado de como fazer o ajuste fino de um modelo para classificação de texto, confira o [notebook do PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb) correspondente.

## Inferência

Ótimo, agora que você ajustou um modelo, pode usá-lo para inferência!

Obtenha algum texto no qual você deseja executar inferência:

```py
>>> text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."
```

A maneira mais simples de testar seu modelo ajustado para inferência é usá-lo em um [pipeline()](/docs/transformers/main/pt/main_classes/pipelines#transformers.pipeline). Instancie um `pipeline` para análise de sentimento com seu modelo e passe seu texto para ele:

```py
>>> from transformers import pipeline

>>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
>>> classifier(text)
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]
```

Você também pode replicar manualmente os resultados do `pipeline`, se desejar:

Tokenize o texto e retorne tensores do PyTorch:

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
>>> inputs = tokenizer(text, return_tensors="pt")
```

Passe suas entradas para o modelo e retorne os `logits`:

```py
>>> import torch
>>> from transformers import AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
>>> with torch.no_grad():
...     logits = model(**inputs).logits
```

Obtenha a classe com a maior probabilidade e use o mapeamento `id2label` do modelo para convertê-la em um rótulo de texto:

```py
>>> predicted_class_id = logits.argmax().item()
>>> model.config.id2label[predicted_class_id]
'POSITIVE'
```

