見出し画像

Huggingface Tokenizers 入門 (2) - クイックツアー

以下の記事を参考に書いてます。

Quicktour — tokenizers documentation

前回

1. クイックツアー

Huggingface Tokenizers」の機能を簡単に見てみます。現在よく使われているトークナイザーの実装を提供します。事前学習済みトークナイザーをインスタンス化して使用できますが、学習方法を確認するため、最初から作成します。

2. トークナイザーを最初から作成

「Huggingface Tokenizers」の速度を説明するために、「wikitext-103」(516Mのテキスト)で新しいトークナイザーをわずか数秒で学習します。最初に、このデータセットをダウンロードして、次のコマンドで解凍してください。

wget https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-103-raw-v1.zip
unzip wikitext-103-raw-v1.zip

3. トークナイザーの学習

このツアーでは、「BPE」(Byte-Pair Encoding)のトークナイザーを構築して学習します。様々なタイプのトークナイザーの詳細については、このガイドを参照してください。ここでいう、トークナイザーの学習は、次の方法でマージルールを学習することを意味します。

(1) 学習コーパスにトークンとして存在する全ての文字から始める。
(2) 最も一般的なトークンのペアを特定し、それを1つのトークンにマージ。
(3) 語彙(トークンの数など)が必要なサイズに達するまで繰り返す。

ライブラリのメインはTokenizerクラスです。以下は、BPEモデルを使用してインスタンス化する方法です。

from tokenizers import Tokenizer
from tokenizers.models import BPE
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))

wikiテキストファイルでトークナイザーを学習するには、トレーナー(この場合はBpeTrainer)をインスタンス化する必要があります。

from tokenizers.trainers import BpeTrainer
trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])

vocab_sizemin_frequency(ここではデフォルト値の30,000と0のまま)などの学習パラメータを設定できますが、最も重要なのは後で使用する予定のspecial_tokensを指定することです(トレーニング中にはまったく使用されません)。これらは語彙に挿入されます。

【注意】 スペシャルトークンのリストを作成する順序は重要です。ここでは、[UNK]はID0、[CLS]はID1を取得します。

今すぐトークナイザーを学習できますが、最適ではありません。入力を単語に分割するプレトークナイザーがないと、複数の単語と重複するトークンを取得する可能性があります。たとえば、これら2つの単語は隣り合って表示されることが多いため、「it is」トークンを取得できます。プレトークナイザーを使用すると、プレトークン化機能によって返される単語よりも大きいトークンがないことが保証されます。ここでは、サブワードBPEトークナイザーを学習し、スペースで分割することで可能な限り最も簡単なプレトークナイザーを使用します。

from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()

以下で、使用したいファイルのリストを使用してtrain()を呼び出すことができます。

files = [f"data/wikitext-103-raw/wiki.{split}.raw" for split in ["test", "train", "valid"]]
tokenizer.train(files, trainer)

完全なwikiテキストデータセットでトークナイザーを学習するのに数秒しかかからないはずです。トークナイザーの全ての構成と語彙を含むファイルを保存するには、save()を使用するだけです。

tokenizer.save("data/tokenizer-wiki.json")

そして、from_file()を使用して、ファイルからトークナイザーをロードできます。

tokenizer = Tokenizer.from_file("data/tokenizer-wiki.json")

4. トークナイザーの使用

トークナイザーを学習したので、encode()を任意のテキストで使用します。

output = tokenizer.encode("Hello, y'all! How are you 😁 ?")

これによって、トークナイザーの完全なパイプラインがテキストに適用され、Encodingオブジェクトが返されます。このパイプラインの詳細と、パイプラインの一部を適用(またはカスタマイズ)する方法については、このページを参照してください。

このEncodingオブジェクトには、深層学習モデル(またはその他)に必要なすべての属性が含まれています。tokens属性には、トークン内のテキストのセグメンテーションが含まれています。

print(output.tokens)
# ["Hello", ",", "y", "'", "all", "!", "How", "are", "you", "[UNK]", "?"]​​

同様に、ids属性には、トークナイザーの語彙に含まれるこれらの各トークンのインデックスが含まれます。

print(output.ids)
# [27253, 16, 93, 11, 5097, 5, 7961, 5112, 6218, 0, 35]​

「Huggingface Tokenizers」の重要な機能は、完全なアライメントトラッキングが付属していることです。つまり、特定のトークンに対応する元のテキストをいつでも取得できます。これらは、Encodingオブジェクトのoffsets属性に格納されます。たとえば、リストのインデックス9にあるトークンである[UNK]トークンが表示された原因を調べたい場合は、インデックスでオフセットを要求できます。

print(output.offsets[9])
# (26, 27)​

以下は、元の文の絵文字に対応するインデックスです。

sentence = "Hello, y'all! How are you 😁 ?"
sentence[26:27]
# "😁"

5. ポストプロセッサ

トークナイザーに[CLS][SEP]などのスペシャルトークンを自動的に追加したい場合があります。 これを行うには、ポストプロセッサを使用します。 TemplateProcessingは最も一般的に使用されており、スペシャルトークンとそのIDとともに、単一の文と文のペアを処理するためのテンプレートを指定する必要があります。

トークナイザーを作成するときに、スペシャルトークンのリストの1番目と2番目に[CLS][SEP]を設定したので、これがそれらのIDである必要があります。 再確認するには、token_to_id()を使用できます。

tokenizer.token_to_id("[SEP]")
# 2​

ポストプロセッサを設定して、従来のBERT入力を提供する方法は次のとおりです。

from tokenizers.processors import TemplateProcessing
tokenizer.post_processor = TemplateProcessing(
    single="[CLS] $A [SEP]",
    pair="[CLS] $A [SEP] $B:1 [SEP]:1",
    special_tokens=[
        ("[CLS]", tokenizer.token_to_id("[CLS]")),
        ("[SEP]", tokenizer.token_to_id("[SEP]")),
    ],
)

このコードスニペットについて詳しく見ていきます。まず、単一の文のテンプレートを指定します。これらは"[CLS] $A [SEP]"の形式である必要があります。$Aは文を表します。

次に、文のペアのテンプレートを指定します。このテンプレートは、"[CLS] $A [SEP] $B [SEP]"の形式である必要があります。ここで、$Aは最初の文を表し、$Bは2番目の文を表します。 テンプレートに追加された:1は、入力の各部分に必要なタイプIDを表します。デフォルトではすべて0になり(これが$A:0がない理由です)、ここでは、2番目の文のトークンと最後の[SEP]トークンに対して1に設定します。

最後に、使用した特別なトークンとそのIDをトークナイザーの語彙で指定します。これが正しく機能することを確認するために、前と同じ文をエンコードしてみます。

output = tokenizer.encode("Hello, y'all! How are you 😁 ?")
print(output.tokens)
# ["[CLS]", "Hello", ",", "y", "'", "all", "!", "How", "are", "you", "[UNK]", "?", "[SEP]"]

一対の文の結果を確認するには、2つの文をencode()に渡すだけです。

output = tokenizer.encode("Hello, y'all!", "How are you 😁 ?")
print(output.tokens)
# ["[CLS]", "Hello", ",", "y", "'", "all", "!", "[SEP]", "How", "are", "you", "[UNK]", "?", "[SEP]"]

次に、各トークンに起因するタイプIDが正しいことを確認できます。

print(output.type_ids)
# [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]

トークナイザーをsave()で保存すると、ポストプロセッサも一緒に保存されます。

6. 複数の文をバッチでエンコード

「Huggingface Tokenizers」で速度を得るには、encode_batch()を使用してテキストをバッチで処理するのが最善です。

output = tokenizer.encode_batch(["Hello, y'all!", "How are you 😁 ?"])

出力は、前に見たようなEncodingオブジェクトのリストです。 メモリに収まる限り、好きなだけテキストを一緒に処理できます。

文のペアのバッチを処理するには、encode_batch()に2つのリストを渡します。文Aのリストと文Bのリストです。

output = tokenizer.encode_batch(
    [["Hello, y'all!", "How are you 😁 ?"], ["Hello to you too!", "I'm fine, thank you!"]]
)

複数の文をエンコードする場合、enable_padding()を使用して、pad_tokenとそのID(token_to_id()でパディングトークンのIDを再確認できます)を使用して、出力を存在する最長の文に自動的にパディングできます。

tokenizer.enable_padding(pad_id=3, pad_token="[PAD]")

全てのサンプルをその特定の数にパディングする場合は、パディングの方向(デフォルトは右)または指定された長さを設定できます。

output = tokenizer.encode_batch(["Hello, y'all!", "How are you 😁 ?"])
print(output[1].tokens)
# ["[CLS]", "How", "are", "you", "[UNK]", "?", "[SEP]", "[PAD]"]

この場合、トークナイザーによって生成されるアテンションマスクは、パディングを考慮に入れます。

print(output[1].attention_mask)
# [1, 1, 1, 1, 1, 1, 1, 0]

7.  事前学習済みのトークナイザーの使用

事前学習済みトークナイザーをで直接使用することもできます。 たとえば、古典的な事前学習済みのBERTトークナイザーを入手する方法は次のとおりです。

from tokenizers import BertWordPieceTokenizer
tokenizer = BertWordPieceTokenizer("bert-base-uncased-vocab.txt", lowercase=True)

bert-base-uncased-vocab.txtファイルをダウンロードしておいてください。

wget https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt
【注意】 事前学習済みトークナイザーのサポートが次のリリースで改善される予定です。



この記事が気に入ったらサポートをしてみませんか?