ホーム » HuggingFace Transformers » HuggingFace Transformers 4.17 : ガイド : 下流タスク用の再調整 – トークン分類

HuggingFace Transformers 4.17 : ガイド : 下流タスク用の再調整 – トークン分類

HuggingFace Transformers 4.17 : ガイド : 下流タスク用の再調整 – トークン分類 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 04/27/2022 (v4.17.0)

* 本ページは、HuggingFace Transformers の以下のドキュメントを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

クラスキャット 人工知能 研究開発支援サービス

クラスキャット は人工知能・テレワークに関する各種サービスを提供しています。お気軽にご相談ください :

◆ 人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。スケジュール
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

  • 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
  • sales-info@classcat.com  ;  Web: www.classcat.com  ;   ClassCatJP

 

HuggingFace Transformers : ガイド : 下流タスク用の再調整 – トークン分類

トークン分類はセンテンスの個々のトークンにラベルを割当てます。最も一般的なトークン分類タスクの一つは固有表現認識 (NER) です。NER はセンテンスの各エンティティに対して、人、位置や組織のようなラベルを見つけようとします。

このガイドは、新しいエンティティを検出するために WNUT 17 データセットで DistilBERT を再調整する方法を示します。

Note : トークン分類と関連するモデル、データセットとメトリクスの他の形式についての詳細はトークン分類 タスクのページ を見てください。

 

WNUT 17 データセットのロード

Datasets ライブラリから WNUT 17 データセットをロードします :

from datasets import load_dataset

wnut = load_dataset("wnut_17")

そしてサンプルを見てみましょう :

wnut["train"][0]
{'id': '0',
 'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0],
 'tokens': ['@paulwalk', 'It', "'s", 'the', 'view', 'from', 'where', 'I', "'m", 'living', 'for', 'two', 'weeks', '.', 'Empire', 'State', 'Building', '=', 'ESB', '.', 'Pretty', 'bad', 'storm', 'here', 'last', 'evening', '.']
}

ner_tags の各数値はエンティティを表します。詳細は数値をラベル名に変換します :

label_list = wnut["train"].features[f"ner_tags"].feature.names
label_list
[
    "O",
    "B-corporation",
    "I-corporation",
    "B-creative-work",
    "I-creative-work",
    "B-group",
    "I-group",
    "B-location",
    "I-location",
    "B-person",
    "I-person",
    "B-product",
    "I-product",
]

ner_tag は企業、場所や人のようなエンティティを表します。各 ner_tag を prefix する文字はエンティティのトークン位置を示します :

  • B- はエンティティの始まりを示します。

  • I- はトークンが同じエンティティ内に含まれていることを示します (e.g., State トークンは Empire State Building のようなエンティティの一部です)。

  • 0 はトークンがどのエンティティにも対応していないことを示します。

 

前処理

トークンを処理するために DistilBERT トークナイザーをロードします :

from transformers import AutoTokenizer

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

入力は既に単語に分割されていますので、単語をサブワードにトークン化するには is_split_into_words=True を設定します :

tokenized_input = tokenizer(example["tokens"], is_split_into_words=True)
tokens = tokenizer.convert_ids_to_tokens(tokenized_input["input_ids"])
tokens
['[CLS]', '@', 'paul', '##walk', 'it', "'", 's', 'the', 'view', 'from', 'where', 'i', "'", 'm', 'living', 'for', 'two', 'weeks', '.', 'empire', 'state', 'building', '=', 'es', '##b', '.', 'pretty', 'bad', 'storm', 'here', 'last', 'evening', '.', '[SEP]']

特殊トークン [CLS] と [SEP] の追加とサブワード・トークン化は入力とラベルの間の不一致を生み出します。単一ラベルに対応する単一の単語は 2 つのサブワードに分割されるかもしれません。トークンとラベルを以下により再調整 (= realign) する必要があります :

  1. word_ids メソッドで総てのトークンを対応する単語にマップする。

  2. 特殊トークン [CLS] と [SEP] にラベル -100 を割当てて PyTorch 損失関数がそれらを無視するようにする。

  3. 与えられた単語の最初のトークンだけにラベル付けします。同じ単語の他のサブトークンには -100 を割当てます。

ここに、トークンとラベルを再調整して、シークエンスが DistilBERT の最大入力長よりも長くならないように切り詰める関数を作成する方法があります :

def tokenize_and_align_labels(examples):
    tokenized_inputs = tokenizer(examples["tokens"], truncation=True, is_split_into_words=True)

    labels = []
    for i, label in enumerate(examples[f"ner_tags"]):
        word_ids = tokenized_inputs.word_ids(batch_index=i)  # Map tokens to their respective word.
        previous_word_idx = None
        label_ids = []
        for word_idx in word_ids:  # Set the special tokens to -100.
            if word_idx is None:
                label_ids.append(-100)
            elif word_idx != previous_word_idx:  # Only label the first token of a given word.
                label_ids.append(label[word_idx])
            else:
                label_ids.append(-100)
            previous_word_idx = word_idx
        labels.append(label_ids)

    tokenized_inputs["labels"] = labels
    return tokenized_inputs

データセット全体に対してラベルをトークン化してアラインするために Datasets map 関数を使用します。データセットの複数の要素を一度に処理する batched=True を設定することにより map 関数を高速化できます :

tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)

サンプルのバッチを作成するために DataCollatorForTokenClassification を使用します。それはまたバッチ内の最長要素の長さにテキストとラベルを動的にパディングしますので、それらは均一な長さです。padding=True を設定することでトークナイザーの関数でテキストをパディングすることも可能ですが、動的パディングはより効率的です。

PyTorch
from transformers import DataCollatorForTokenClassification

data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
TensorFlow
from transformers import DataCollatorForTokenClassification

data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer, return_tensors="tf")

 

Trainer で再調整

想定されるラベルの数と共に AutoModelForTokenClassification で DistilBERT をロードします :

from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer

model = AutoModelForTokenClassification.from_pretrained("distilbert-base-uncased", num_labels=2)

この時点で、3 つのステップだけが残っています :

  1. TrainingArguments で訓練ハイパーパラメータを定義します。

  2. 訓練引数をモデル、データセット、トークナイザー、そしてデータ collator と共に Trainer に渡します。

  3. モデルを再調整するために train() を呼び出します。
training_args = TrainingArguments(
    output_dir="./results",
    evaluation_strategy="epoch",
    learning_rate=2e-5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    num_train_epochs=3,
    weight_decay=0.01,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_wnut["train"],
    eval_dataset=tokenized_wnut["test"],
    tokenizer=tokenizer,
    data_collator=data_collator,
)

trainer.train()

 

TensorFlow による再調整

TensorFlow でモデルを再調整することは、幾つかの違いはありますが、同様に簡単です。

データセットを to_tf_dataset で tf.data.Dataset 形式に変換します。columns で入力とラベルを、データセット順序をシャッフルするか否か、バッチサイズ、そしてデータ collator を指定します :

tf_train_set = tokenized_wnut["train"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "labels"],
    shuffle=True,
    batch_size=16,
    collate_fn=data_collator,
)

tf_validation_set = tokenized_wnut["validation"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "labels"],
    shuffle=False,
    batch_size=16,
    collate_fn=data_collator,
)

optimizer 関数, 学習率スケジュール, そして幾つかの訓練ハイパーパラメータをセットアップします :

from transformers import create_optimizer

batch_size = 16
num_train_epochs = 3
num_train_steps = (len(tokenized_wnut["train"]) // batch_size) * num_train_epochs
optimizer, lr_schedule = create_optimizer(
    init_lr=2e-5,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
    num_warmup_steps=0,
)

想定されるラベル数と共に TFAutoModelForTokenClassification で DistilBERT をロードします :

from transformers import TFAutoModelForTokenClassification

model = TFAutoModelForTokenClassification.from_pretrained("distilbert-base-uncased", num_labels=2)

compile で訓練のためにモデルを configure します :

import tensorflow as tf

model.compile(optimizer=optimizer)

モデルを再調整するために fit を呼び出します :

model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=3)

Note : トークン分類のためにモデルを再調整する方法の詳細なサンプルについては、対応する PyTorch ノートブックTensorFlow ノートブック を見てください。

 

以上



ClassCat® Chatbot

人工知能開発支援
クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com

カテゴリー