# テキスト分類

テキスト分類は、テキストにラベルまたはクラスを割り当てる一般的なNLPタスクです。大手企業の多くは、幅広い実用的なアプリケーションにおいて、テキスト分類を本番環境で運用しています。テキスト分類の最も人気のある形式の一つが感情分析で、これはテキストのシーケンスに🙂ポジティブ、🙁ネガティブ、😐ニュートラルなどのラベルを割り当てます。

このガイドでは、次の方法について説明します：

1. [IMDb](https://huggingface.co/datasets/stanfordnlp/imdb)データセットで[DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased)をファインチューニングし、映画レビューが肯定的か否定的かを判定します。
2. ファインチューニングしたモデルを推論に使用します。

このタスクと互換性のあるすべてのアーキテクチャとチェックポイントを確認するには、[タスクページ](https://huggingface.co/tasks/text-classification)を参照することをお勧めします。

開始前に、必要なライブラリがすべてインストールされていることを確認してください。

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

Hugging Face アカウントにログインして、モデルをアップロードし、コミュニティと共有できるようにすることを推奨します。プロンプトが表示されたら、ログイン用のトークンを入力してください:

```py
>>> from huggingface_hub import notebook_login

>>> notebook_login()
```

## IMDb データセットを読み込む

🤗 Datasets ライブラリから IMDb データセットを読み込むことから始めます:

```py
>>> from datasets import load_dataset

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

次に、例を見てみましょう。

```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.",
}
```

このデータセットには2つのフィールドがあります:

- `text`: 映画のレビューテキスト。
- `label`: ネガティブなレビューの場合は`0`、ポジティブなレビューの場合は`1`の値。

## 前処理

次のステップは、`text`フィールドの前処理のためにDistilBERTのトークナイザーを読み込むことです。

```py
>>> from transformers import AutoTokenizer

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

`text`をトークナイズし、シーケンスをDistilBERTの最大入力長を超えないように切り詰める前処理関数を作成します:

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

データセット全体に前処理関数を適用するには、🤗 Datasets の [map](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset.map) 関数を使用します。`batched=True` を設定することで、データセットの複数の要素を一度に処理し、`map` を高速化できます:

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

次に、[DataCollatorWithPadding](/docs/transformers/main/ja/main_classes/data_collator#transformers.DataCollatorWithPadding)を使用してサンプルのバッチを作成します。データセット全体を最大長にパディングするのではなく、コラレーション時にバッチ内の最も長い長さに合わせて*動的にパディング*する方が効率的です。

```py
>>> from transformers import DataCollatorWithPadding

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

## 評価

学習中にメトリクスを含めることは、モデルの性能を評価する上でしばしば役立ちます。🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) ライブラリを使用すると、評価メソッドをすばやく読み込むことができます。このタスクでは、[accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) メトリクスを読み込みます（メトリクスの読み込みと計算方法の詳細については、🤗 Evaluate の [クイックツアー](https://huggingface.co/docs/evaluate/a_quick_tour) を参照してください）：

```py
>>> import evaluate

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

次に、予測値とラベルを[compute](https://huggingface.co/docs/evaluate/main/en/package_reference/main_classes#evaluate.EvaluationModule.compute)に渡して正解率を計算する関数を作成します。

```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)
```

`compute_metrics`関数はこれで準備が整いました。学習を設定する際に、この関数に戻ります。

## 学習

モデルの学習を開始する前に、`id2label`と`label2id`を使用して、期待されるIDとラベルの対応表を作成します。

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

[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer)によるモデルのファインチューニングに慣れていない場合は、[こちら](../training)の基本的なチュートリアルをご覧ください!

いよいよモデルの学習を開始できます![AutoModelForSequenceClassification](/docs/transformers/main/ja/model_doc/auto#transformers.AutoModelForSequenceClassification) を使用して DistilBERT を読み込み、期待されるラベル数とラベルのマッピングを指定します:

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

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

この時点で、残りのステップは3つだけです:

1. [TrainingArguments](/docs/transformers/main/ja/main_classes/trainer#transformers.TrainingArguments) で学習ハイパーパラメータを定義します。必須のパラメータは `output_dir` だけで、モデルの保存先を指定します。`push_to_hub=True` を設定することで、このモデルを Hub にプッシュできます（モデルをアップロードするには Hugging Face にサインインしている必要があります）。各エポックの終了時、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) は精度を評価し、学習チェックポイントを保存します。
2. モデル、データセット、トークナイザー、データコラテーター、`compute_metrics` 関数とともに、学習引数を [Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) に渡します。
3. [train()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.train)を呼び出して、モデルをファインチューニングします。

```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()
```

`tokenizer`を[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer)に渡すと、デフォルトで動的パディングが適用されます。この場合、データコラテーターを明示的に指定する必要はありません。

トレーニングが完了したら、[push_to_hub()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.push_to_hub) メソッドでモデルを Hub に共有し、誰でもそのモデルを利用できるようにしてください。

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

テキスト分類用のモデルをファインチューニングする方法について、より詳細な例を確認するには、対応する[PyTorchノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)をご覧ください。

## 推論

素晴らしい、モデルのファインチューニングが完了したので、推論に使用できます！

推論を実行したいテキストを取得します:

```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."
```

ファインチューニングしたモデルを推論で試す最も簡単な方法は、[pipeline()](/docs/transformers/main/ja/main_classes/pipelines#transformers.pipeline)でそれを使用することです。モデルを指定して感情分析用の`pipeline`をインスタンス化し、テキストを渡します:

```py
>>> from transformers import pipeline

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

必要に応じて、`pipeline`の結果を手動で再現することもできます:

テキストをトークン化し、PyTorch テンソルを返します:

```py
>>> from transformers import AutoTokenizer

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

入力をモデルに渡し、`logits`を返します:

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

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

最も高い確率を持つクラスを取得し、モデルの`id2label`マッピングを使用してテキストラベルに変換します:

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

