1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

T5Tokenizerのis_split_into_wordsが日本語だと役に立たない

Posted at

あらすじ

固有表現抽出(NER)などのタスクの際に、tokenizerへの入力としてstr型のテキストではなく、予め単語区切りされたlist型を入力したくなる機会があると思います。私はDAE(Denoise Auto-Encoder)を学習させようと思ったときに、入力単語列に対して単語削除や並び替えを行ったため、list形式でencodeしたいと考えました。

Sentencepiece tokenizerの問題

huggingface transformersのtokenizerには、こうした状況のために、call関数などにis_split_into_words
という引数が用意してあります。
説明を見てみると、

・is_split_into_words (bool, optional, defaults to False) — Whether or not the input is already pre-tokenized (e.g., split into words). If set to True, the tokenizer assumes the input is already split into words (for instance, by splitting it on whitespace) which it will tokenize. This is useful for NER or token classification.

とあり、空白区切りなどの分割が成されていることを理解してencodeしてくれそうです。

ところが、日本語のT5モデルではis_split_into_words = Trueにしても意図したencodeをしてくれません。
以下は、sonoisaさんの事前学習済みモデルを用いた例になります。

tokenizer: T5Tokenizer = T5Tokenizer.from_pretrained("sonoisa/t5-base-japanese-v1.1", legacy=False)
text: str = "今日は良い天気ですね。"
split_text: str = " ".join(tokenizer.tokenize(text))
>>split_text: ▁ 今日は 良い 天気 ですね 。
input_ids = tokenizer(split_text, is_split_into_words=True).input_ids
>>input_ids: [261, 10017, 261, 2198, 261, 14255, 261, 3849, 261, 260, 1]

encodeしたinput_idsに度々261というidが生じ、明らかにトークン数 < id数になっています。これは半角スペースのトークンで、空白区切りしていることを考慮してくれていないことが分かります。

tokenizerにはlist[str]を入力することもできるので、今度はそれを試してみたいと思います。

text: str = "今日は良い天気ですね。"
split_tokens: list[str] = tokenizer.tokenize(text)
>>split_tokens: ['▁', '今日は', '良い', '天気', 'ですね', '。']
input_ids = tokenizer(split_tokens, is_split_into_words=True).input_ids
>>input_ids: [261, 10017, 261, 2198, 261, 14255, 261, 3849, 261, 260, 1]

はい、さっきと同じ結果になりました。おそらく英語など元々半角スペースで区切られている言語では上手く動作するのだと思いますが、日本語ではスペースも単語としてエンコードされてしまいます。

解決策

strlist[str]でエンコードすると上記の問題が生じてしまうので、ids(list[int])として与えることで回避したいと思います。
しかし、tokenizerのcall関数はlist[int]を入力として受け付けてくれません。

text: str = "今日は良い天気ですね。"
ids: list[int] = tokenizer.encode(text)
>>ids: [261, 10017, 2198, 14255, 3849, 260, 1]
input_ids = tokenizer(ids, is_split_into_words=True).input_ids
>>ValueError: text input must of type `str` (single example), `List[str]` (batch or single pretokenized example) or `List[List[str]]` (batch of pretokenized examples).

一方で、batch_encode_plus関数は入力としてlist[list[int]]を受け付けてくれます。
なので、以下のようにすることでT5のinputを生成することができます。

text: str = "今日は良い天気ですね。"
ids: list[list[int]] = [tokenizer.encode(text, add_special_tokens=False)]
>>ids: [[261, 10017, 2198, 14255, 3849, 260]]
inputs: BatchEncoding = tokenizer.batch_encode_plus(ids, is_split_into_words=True)
# NERの場合
labels: LongTensor = LongTensor([[0, 0, 1, 1, 0, 0, 0]])
inputs["labels"] = labels
>>inputs
{'input_ids': [[261, 10017, 2198, 14255, 3849, 260, 1]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1]], 'labels': tensor([[0, 0, 1, 1, 0, 0, 0]])}

環境

transformers==4.31.0

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?