🥎

【初心者向け】BERTのtokenizerについて理解する

2022/10/23に公開

BERTすごいですね。
 
BERTモデルは、2018年にGoogle社が開発し、自然言語処理の世界でブレークスルーをつくったと言われています。
BERTはGLUEという英語の言語理解を評価するタスクにおいて、当時の記録を一気に塗り替えました。また、Google検索においてもBERTを導入したことにより、飛躍的に精度が上がりました。
 

こんな素晴らしいBERTですが、初心者が一発で理解するのは少し大変な印象をもっています。
そこで、BERTを初めて扱う方に向けて、以下の書籍を参考にしながら、基本的なコードの書き方と、それぞれのコードが具体的にどのような処理を行っているのかを丁寧に解説していきたいと思います。
私自身もまだまだ初心者の域を出ませんが、BERTについて一緒に勉強できればなと思います。
https://www.ohmsha.co.jp/book/9784274227264/
 
なお、BERTの理論については深堀りしませんので、興味のある方は専門書や専門サイトをご覧いただければと思います。
 
今回は1回目として、BERTのtokenizerについて理解してみようと思います。
 

事前学習とファインチューニングについて

BERTは優れたポテンシャルを持つモデルですが、何もしなければポテンシャルの高いただの赤ん坊みたいなものです。ポテンシャルを引き出すために、大規模な文章コーパスを用いて、汎用的な言語のパターンを教えてあげる必要があります。これを事前学習と呼びます。
汎用的な力を持った事前学習モデルに、特定のタスクを更に学習させることで高い精度を引き出すことが可能です。この特定のタスクを学習させることをファインチューニングと呼びます。
BERTを扱う上で基本となるのが、この事前学習とファインチューニングになります。
ここでは、事前学習モデルとして、東北大学の作成した日本語モデルを使用していきます。
 

ライブラリのインストール

BERTはHuggingFace社が提供しているオープンソースのライブラリtransformersで実装されています。
日本語の辞書であるfugashi ipadicもインストールします。

!pip install transformers==4.20.0 fugashi ipadic

 

tokenizer(トークナイザ)とは

日本語でも英語でも、言語を使ったタスクを解く場合には、言語をモデルが扱えるように数値化する必要があります。
トークナイザとは、文章を語彙(トークン)に分割したうえで、BERTモデルに入力できる形に変換する処理と考えたら分かりやすいでしょう。
 
BERTの日本語用のトークナイザをインポートします
東北大学の事前学習モデルをトークナイザーの引数に指定し、インスタンス化します

from transformers import BertJapaneseTokenizer
model_name = 'cl-tohoku/bert-base-japanese-whole-word-masking'
tokenizer = BertJapaneseTokenizer.from_pretrained(model_name)

 

トークン化の流れ

BERTの日本語モデルでは、MeCabを用いて単語に分割し、WordPieceを用いて単語をトークンに分割します。
日本語モデルでは32,000のトークンがあります。
それぞれのトークンにはIDが振られていて、BERTに入力する際には、このIDが用いられます。
tokenizer.vocabで見ることができます。

 

トークン化の具体例

首相官邸サイトから、岸田首相の発言を適当に引っ張ってきて、textに格納しました。
こちらをトークン化していきたいと思います。

text ="私が目指すのは、新しい資本主義の実現です。
成長を目指すことは極めて重要であり、その実現に向けて全力で取り組みます。"

 

tokenizeメソッド

さきほどインスタンス化したtokenizerでtokenizeメソッドを実行します。
日本語の文章をトークンに分割します。

token = tokenizer.tokenize(text)
token

出力結果

['私','が','目指す','の','は','、', '新しい','資本','主義','の','実現','です','。',
 '成長','を','目指す','こと','は','極めて','重要','で','あり','、',
 'その','実現','に','向け','て','全力','で','取り組み','ます','。']

 

encodeメソッド

次にencodeメソッドを使ってみます。
こちらは日本語の文章をトークンに分割した上で、トークンのIDを付与したものになります。

input_ids = tokenizer.encode(text)
input_ids

出力結果
出力結果の最初の2は、トークンの先頭につく「CLS」になります。(上表参照)。
1325が「私」に対応します。

[2,1325,14,5059,5,9,6,1842,4330,1008,5,2519,2992,8,
2473,11,5059,45,9,4767,1279,12,130,6,
59,2519,7,1100,16,19614,12,9084,2610,8,3]

 

covert_ids_to_tokensメソッド

IDをトークンに戻します。

tokens = tokenizer.convert_ids_to_tokens(input_ids)
tokens

出力結果
最後の「SEP」は文章の末尾であることを示すトークンです。

['[CLS]','私','が','目指す','の','は','、','新しい','資本','主義','の','実現','です','。',
 '成長','を','目指す','こと','は','極めて','重要','で','あり','、',
 'その','実現','に','向け','て','全力','で','取り組み','ます','。','[SEP]']

 

tokenizerメソッド

BERTに入力できる形に一発で変換する処理としてtokenizerメソッドがあります。
いくつかの引数を与えることで、BERTに入力しやすい形に変換ができます。

引数名 内容
text 文章です。リスト形式で渡すことも可です。
max_length トークン列(系列長)を揃えるために、トークン列の最大の長さを決めます。
padding "max_length"を指定すると、その長さに足りないトークン列にはPADを埋めます。 "longest"を指定すると文章の中で最大のものに系列長を揃えてくれます。
truncation Trueに設定すると、文章をmax_lengthの長さにカットしてくれます
return_tensors "pt"に設定すると、Pytorchに入力可能なtensor型に変換します。
encoding = tokenizer(
    text, 
    max_length =35, 
    padding ="max_length", 
    truncation=True,
    return_tensors="pt"
)
encoding

 
出力結果
具体的なアウトプットしては、以下の3つがあります。

  1. input_ids:トークンのidです
  2. token_type_ids:2つの文章を入力する時に、それぞれの文章を区別します。
  3. attention_mask:トークンの場合1、トークンでない場合0を返します。
{
'input_ids': tensor(
[[2, 1325, 14, 5059, 5,  9,  6, 1842, 4330, 1008, 5, 2519, 2992, 8,  
2473, 11, 5059, 45, 9, 4767, 1279, 12, 130, 6, 
59, 2519, 7, 1100, 16, 19614, 12, 9084, 2610, 8, 3]]
),
'token_type_ids': tensor(
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]]
), 
'attention_mask': tensor(
[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1]]
)
}

さいごに

いかがでしたでしょうか。
次はBERTモデルを使ってトークンに対するベクトルを得る方法について解説していきます。

Discussion