はじめに
う〜ん、おいし〜😋1 、nikkieです🐟
Python製OSSのソースコードを読むのが好きで、そこで得られた知見(新しく知った書き方や設計例)を実装の参考にします。
自然言語処理の前処理について参考にしたく、huggingface/tokenizersのソースコード(厳密には型定義のスタブ)を読みました。
今回は読んで考えたことをメモレベルでアウトプットします。
目次
- はじめに
- 目次
- huggingface/tokenizers
- Normalizersのソースコードリーディング
- すべてのnormalizerのベースクラスNormalizer
- Normalizerクラスを継承した具体的なnormalizerたち
- いくつかの正規化処理をまとめるnormalizer:Sequence
- BertNormalizer
- Pythonで実装を試してみた
- 終わりに
huggingface/tokenizers
ライブラリtransformersで有名なHugging Face社ですが、他にもdatasets、evaluate、tokenizersなどを公開しています。
tokenizersはTransformer系モデルのトークナイザを提供します2。
tokenizersライブラリの非常にニッチな領域にフォーカスします。
文字列をnormalizeする処理群です。
Normalizersのソースコードリーディング
tokenizers自体はRustで実装されています(pip installするのはPythonバインディングの認識)。
Rustの実装は満足に読めないのですが、リポジトリに置かれたpyiファイルを見るだけでも、設計について気付きがありました。
pyiファイルについてはスタブ(型の定義だけ記載したファイル)という理解です3。
すべてのnormalizerのベースクラスNormalizer
以下の2つのメソッドが定義されています。
normalizeメソッド:NormalizedStringオブジェクトをインプレースにnormalizeするnormalize_strメソッド:strオブジェクトをnormalizeしたstrオブジェクトを返す
Normalizerクラスを継承した具体的なnormalizerたち
Lowercase
小文字にするnormalizerです。
NFKC
正規形NFKCでUnicode正規化するnormalizerです。
unicodedata.normalize4相当の処理と思われます5。
他にもまだまだ(列挙)
以下のような具体的なnormalizerがあります:
ReplaceStripStripAccentsNFCNFDNFKDNmtPrecompiled
Normalizerクラスを継承することで各種正規化処理はインターフェースが揃っています。
いくつかの正規化処理をまとめるnormalizer:Sequence
小文字化+NFKCでUnicode正規化のように、複数のnormalizerをまとめて適用したいケースもあります。
そんなときに重宝するのがSequence!
Allows concatenating multiple other Normalizer as a Sequence.
All the normalizers run in sequence in the given order
(nikkie訳)Sequence以外のnormalizer複数を結合することを可能にします。
与えられた順番でnormalizerが適用されます。
Sequenceの初期化では、まとめたいnormalizerのリストを渡します。
中では、順番に適用する実装となっているのでしょう。
Sequence自体はNormalizerクラスを継承していますから、normalizeメソッドとnormalize_strメソッドを持ちます。
インターフェースが揃った各種正規化処理、これらを部品のように組み合わせて、複数をまとめたnormalizerをSequenceで実現していると理解しました。
Sequence自体も、部品としている正規化処理とインターフェースが揃っています(Sequenceオブジェクトを渡して新しいSequenceとしてインスタンス化もできるかもしれませんね)。
BertNormalizer
Sequenceを使う具体例と考えられるのがBertNormalizer。
初期化時に以下の引数(いずれもbool)を指定します。
clean_texthandle_chinese_charsstrip_accentslowercase
これらのフラグの値に応じて、Sequenceインスタンスを初期化して、それをBertNormalizerに持たせる形で実装できそうですよね。
例えばstrip_accentsとlowercaseがともにTrueならば、Sequence([StripAcccents(), Lowercase()])を持たせるということです。
Pythonで実装を試してみた
気づいたことを試してみました。
終わりに
huggingface/tokenizersのnormalizersについてstubファイルを元に設計を考えました。
参考になったのは2点です:
- 処理の部品化:具体的なnormalize処理を表す個々のクラス、そしてそれらをまとめられる
Sequence - 統一されたインターフェース:どのnormalizerもベースクラス
Normalizerを継承しており、normalize・normalize_strメソッドを持つ
直近のミノ駆動本_読書pyで「ポリシーパターン」を知ったのですが、個々のnormalizerの部品化には通底するものを感じます。
思考がまとまったら(もしくは整理する目的で)今後アウトプットしてみたいなと思います。
-
この冬、白い砂のアクアトープが全部見られる!
10:00のあたりです🐟。ここのくくるの表情、ほんとよい〜↩昨日は #白い砂のアクアトープ YouTube無料配信企画初日、
— 『白い砂のアクアトープ』TVアニメ公式 (@aquatope_anime) 2022年12月4日
第1話「熱帯魚、逃げた」
第2話「濡れるのも仕事のうち」
ご覧いただきましてありがとうございました🐬
12月17日の#5.6が配信されるタイミングで配信終了となりますので、
それまでにぜひご覧ください👀https://t.co/sMCafnFxNC - 今回はこれ以上は立ち入らないのですが、BERTの事前訓練をColabで動かしてみました(『Transformerによる自然言語処理』3章写経) - nikkie-ftnextの日記などで扱いました↩
- ↩
- https://docs.python.org/ja/3/library/unicodedata.html#unicodedata.normalize↩
- CはcomposeのC(DはdecomposeのD)とUnicode正規化も最近学びがあったのですが、そのアウトプットはまたの機会に…↩