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_sizeやmin_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
【注意】 事前学習済みトークナイザーのサポートが次のリリースで改善される予定です。
この記事が気に入ったらサポートをしてみませんか?