HuggingFace Tokenizers 0.10 : トークン化パイプライン (python) (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 05/30/2021 (Python v0.10.2)
* 本ページは、HuggingFace Tokenizers の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
HuggingFace Tokenizers : トークン化パイプライン (python)
encode() や encode_batch() を呼び出すとき、入力テキストは次のパイプラインを通過します :
これらのステップの各々の間に加えて、幾つかのトークン id をデコードすることを望むときに何が起きるか、そして
Tokenizer ライブラリが貴方のニーズに応じてそれらのステップの各々をどのようにカスタマイズするかを見ます。もし貴方がそれらのステップに既に馴染みがあり幾つかのコードを見ることにより学習することを望むのであれば、BERT from scratch example にジャンプしてください。
Tokenizer を必要とする例については、Quicktour で訓練されたトークナイザーを利用します、これは次でロードできます :
from tokenizers import Tokenizer
tokenizer = Tokenizer.from_file("data/tokenizer-wiki.json")
正規化
正規化は、簡単に言えば、raw 文字列をランダムさを減らすあるいは「クリーン」にするために適用する演算のセットです。一般的な演算は空白を strip し、アクセント付き文字を除去したり、あるいは総てのテキストを小文字化することを含みます。Unicode 正規化 に馴染みがある場合、それは殆どのトークナイザーで適用される非常に一般的な正規化演算でもあります。
各正規化演算は Tokenizers ライブラリでは Normalizer により表され、そして Sequence を使用して幾つかのそれらを連結できます。例としてここに NFD Unicode 正規化を適用してアクセントを除去する normalizer があります :
from tokenizers import normalizers
from tokenizers.normalizers import NFD, StripAccents
normalizer = normalizers.Sequence([NFD(), StripAccents()])
それを任意の文字列に適用することにより normalizer を手動でテストすることができます。
normalizer.normalize_str("Héllò hôw are ü?")
# "Hello how are u?"
Tokenizer を構築するとき、対応する属性を変更するだけで normalizer をカスタマイズできます。
tokenizer.normalizer = normalizer
もちろん、トークナイザーが正規化を適用する方法を変更する場合、多分それを後でスクラッチから再訓練するべきです。
事前トークン化
事前トークン化はテキストを (トークンが訓練の最後になるであろう) 上界を与える小さなオブジェクトに分割する高位です。これを考える良い方法は事前トークン化はテキストを「単語」に分割して、最終的なトークンはそれらの単語の一部となります。
入力を事前トークン化する簡単な方法は空白と句読点上で分割することです、これは Whitespace pre-tokenizer により成されます :
from tokenizers.pre_tokenizers import Whitespace
pre_tokenizer = Whitespace()
pre_tokenizer.pre_tokenize_str("Hello! How are you? I'm fine, thank you.")
# [("Hello", (0, 5)), ("!", (5, 6)), ("How", (7, 10)), ("are", (11, 14)), ("you", (15, 18)),
# ("?", (18, 19)), ("I", (20, 21)), ("'", (21, 22)), ('m', (22, 23)), ("fine", (24, 28)),
# (",", (28, 29)), ("thank", (30, 35)), ("you", (36, 39)), (".", (39, 40))]
出力はタプルのリストで、各タプルは一つの単語と元のセンテンス内のその範囲を含みます (これは Encoding の最終的な offsets を決定するために使用されます)。句読点上の分割はこのサンプルの “I’m” のような縮約を分割することに注意してください。
任意の PreTokenizer を一緒に組み合わせることができます。例えば、ここに空白、句読点と数字上で分割し、個々の数字で数字を区切る事前トークナイザーがあります。
from tokenizers import pre_tokenizers
from tokenizers.pre_tokenizers import Digits
pre_tokenizer = pre_tokenizers.Sequence([Whitespace(), Digits(individual_digits=True)])
pre_tokenizer.pre_tokenize_str("Call 911!")
# [("Call", (0, 4)), ("9", (5, 6)), ("1", (6, 7)), ("1", (7, 8)), ("!", (8, 9))]
Quicktour で見たように、対応する属性を変更することだけで Tokenizer の事前トークナイザーをカスタマイズできます。
tokenizer.pre_tokenizer = pre_tokenizer
もちろん、事前トークナイザーの方法を変更する場合、多分トークナイザーを後でスクラッチから再訓練するべきです。
モデル
ひとたび入力テキストが正規化されて事前トークン化されれば、Tokenizer は事前トークンにモデルを適用します。これはコーパス上の訓練を必要とするパイプラインの一部です (あるいは事前訓練されたトークナイザーを利用している場合はそれは訓練されています)。
モデルの役割はそれが学習したルールを使用して「単語」をトークンに分割することです、それはまたそれらのトークンをモデルの語彙の対応する ID にマップする責任も負います。
モデルは Tokenizer を初期化するときに一緒に渡されますので、この部分をどのようにカスタマイズするかを貴方は既に知っています。現在、 Tokenizers ライブラリは以下をサポートします :
各モデルとその動作の詳細については、ここ を確認できます。
後処理
後処理は潜在的な特殊トークンを追加するような、任意の追加の変換を (それが返される前に) Encoding に遂行するためのトークン化パイプラインの最後のステップです。
クイックツアーで見たように、Tokenizer の後処理を対応する属性を設定することでカスタマイズできます。例えば、入力を 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]", 1), ("[SEP]", 2)],
)
事前トークナイザーや normalizer と対照的に、後処理を変更した後でトークナイザーを再訓練する必要はないことに注意してください。
まとめ: スクラッチから BERT トークナイザー
BERT トークナイザーを構築するためにこれら総てのピースをまとめましょう。最初に、BERT は WordPiece に依拠しますので、このモデルで新しい Tokenizer をインスタンス化します :
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
bert_tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
そして BERT はアクセントを除去して小文字化することによりテキストを前処理することを知っています。unicode normalizer も使用します :
from tokenizers import normalizers
from tokenizers.normalizers import Lowercase, NFD, StripAccents
bert_tokenizer.normalizer = normalizers.Sequence([NFD(), Lowercase(), StripAccents()])
事前トークナイザーは空白と句読点上で分割するだけです :
from tokenizers.pre_tokenizers import Whitespace
bert_tokenizer.pre_tokenizer = Whitespace()
そして後処理は前のセクションで見たテンプレートを使用します :
from tokenizers.processors import TemplateProcessing
bert_tokenizer.post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[
("[CLS]", 1),
("[SEP]", 2),
],
)
このトークナイザーを使用してその上でクイックツアーでのように wikitext 上で訓練できます :
from tokenizers.trainers import WordPieceTrainer
trainer = WordPieceTrainer(
vocab_size=30522, special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]
)
files = [f"data/wikitext-103-raw/wiki.{split}.raw" for split in ["test", "train", "valid"]]
bert_tokenizer.train(files, trainer)
bert_tokenizer.save("data/bert-wiki.json")
デコード
入力テキストのエンコードに加えて、トークナイザーはまたデコードのための API も持ちます、これはモデルにより生成された ID をテキストに戻します。これはメソッド decode() (一つの予測されたテキストのため) と decode_batch() (予測のバッチのため) により成されます。
デコーダは最初に (トークナイザーの語彙を使用して) ID をトークンに変換し戻し、総ての特殊トークンを除去してから、それらのトークンを空白で結合します :
output = tokenizer.encode("Hello, y'all! How are you 😁 ?")
print(output.ids)
# [1, 27253, 16, 93, 11, 5097, 5, 7961, 5112, 6218, 0, 35, 2]
tokenizer.decode([1, 27253, 16, 93, 11, 5097, 5, 7961, 5112, 6218, 0, 35, 2])
# "Hello , y ' all ! How are you ?"
(WordPiece の “##” のような) 特定の「単語」のサブトークンを表すために特殊文字を追加したモデルを使用した場合、それらを正しく扱うためにデコーダをカスタマイズする必要があります。例えば前の bert_tokenizer を取る場合、デフォルトのデコーダは次を与えます :
output = bert_tokenizer.encode("Welcome to the 🤗 Tokenizers library.")
print(output.tokens)
# ["[CLS]", "welcome", "to", "the", "[UNK]", "tok", "##eni", "##zer", "##s", "library", ".", "[SEP]"]
bert_tokenizer.decode(output.ids)
# "welcome to the tok ##eni ##zer ##s library ."
しかしそれを適切なデコーダに替えることにより、次を得ます :
from tokenizers import decoders
bert_tokenizer.decoder = decoders.WordPiece()
bert_tokenizer.decode(output.ids)
# "welcome to the tokenizers library."
以上