2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UTH-BERTにおけるhuggingfaceのトークナイザ設定

Posted at

はじめに

東大が公開しているUTH-BERTは診療録を用いて事前学習しており、医療テキストの様々なタスクを解くにはとても優秀な事前学習モデルです。
また基本となるBERTモデルで学習していることもあり、日本語医療テキストのベースラインとして重宝させて頂いています。

動機

元ソースのtensorflowに基づく方法はうまいことトークナイズしてくれる(あたりまえ)。
一方で、色々な事前学習モデルで検討したいので、pytorchのhuggingfaceのtransformersライブラリを利用したスクリプトに統一したい。
とはいえ、他の記事を参考にしてtransformersでモデルを読み込んで利用しようとすると、元ソースの様にトークナイズできない。

元ソース

Original text

2002 年夏より重い物の持ち上げが困難になり,階段の昇りが遅くなるなど四肢の筋力低下が緩徐に進行した.2005 年 2 月頃より鼻声となりろれつが回りにくくなった.また,食事中にむせるようになり,同年 12 月に当院に精査入院した。

After pre-processing

2002年夏より重い物の持ち上げが困難になり、階段の昇りが遅くなるなど四肢の筋力低下が緩徐に進行した.2005年2月頃より鼻声となりろれつが回りにくくなった.また、食事中にむせるようになり、同年12月に当院に精査入院した。

After tokenization

['2002年', '夏', 'より', '重い', '物', 'の', '持ち上げ', 'が', '困難', 'に', 'なり', '、', '階段', 'の', '[UNK]', 'が', '遅く', 'なる', 'など', '四肢', 'の', '筋力低下', 'が', '緩徐', 'に', '進行', 'し', 'た', '.', '2005年', '2', '月頃', 'より', '鼻', '##声', 'と', 'なり', 'ろ', '##れ', '##つ', 'が', '回り', '##にく', '##く', 'なっ', 'た', '.', 'また', '、', '食事', '中', 'に', 'むせる', 'よう', 'に', 'なり', '、', '同年', '12月', 'に', '当', '院', 'に', '精査', '入院', 'し', 'た', '。']

とりあえず動いてしまう単純なコード

model_checkpoint = "./UTH_BERT_BASE_512_MC_BPE_WWM_V25000"

tokenizer = BertJapaneseTokenizer.from_pretrained(model_checkpoint)

BertJapaneseTokenizerにvocab.txtとconfig.jsonが入ったフォルダのパスを指定のみ

2002年,##夏,##よ,##り,##重,##い,##物,##の,##持ち,##上げ,##が,##困難,##になり,、,階段,##の,##昇,##り,##が,##遅,##く,##なる,##な,##ど,##四肢,##の,##筋力低下,##が,##緩,##徐,##に,##進行,##した,.,2005年,##2,##月,##頃,##よ,##り,##鼻,##声,##と,##なり,##ろ,##れ,##つ,##が,##回,##り,##にく,##く,##な,##っ,##た,.,また,、,食事,##中,##に,##むせる,##よ,##う,##になり,、,同年,##12,##月,##に,##当,##院,##に,##精,##査,##入院,##した,。

前処理は公式どおりにしたもののサブワード多すぎだし、NEologdと万病辞書を使っていない。

他の記事を参考にして修正

model_checkpoint = "./UTH_BERT_BASE_512_MC_BPE_WWM_V25000"

tokenizer = BertJapaneseTokenizer.from_pretrained(
    model_checkpoint,
    word_tokenizer_type="mecab",
    mecab_kwargs={
        "mecab_dic": None,
        "mecab_option": "-u /hogehoge/fugafuga/MANBYO_201907_Dic-utf8.dic -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd",
    }
)

形態素解析をMeCabに指定し、デフォのipadicじゃなくてNEologdとユーザー辞書に万病辞書を指定。
辞書指定は絶対パスとし、NEologdはUbuntuに入れるとここに入ってた。

[UNK],夏,より,重い,物,の,持ち上げ,が,困難,に,なり,、,階段,の,[UNK],が,遅く,なる,など,四肢,の,筋力低下,が,緩徐,に,進行,し,た,[UNK],[UNK],[UNK],頃,より,鼻,##声,と,なり,ろ,##れ,##つ,が,回り,##にく,##く,なっ,た,[UNK],また,、,食事,中,に,むせる,よう,に,なり,、,同年,[UNK],に,当,院,に,精査,入院,し,た,。

あれま、数字関連が未知語に...
万病辞書を指定しないと筋力低下筋力,低下に分割されてしまうが、NEologdは指定の有無で結果は変わらず。

修正

調べてみても先人達の記録が見つからないので、transformersのソースコードを読んで辿る事に...

  1. BertJapaneseTokenizerは、word_tokenizer_type="mecab"によってtransformers.MecabTokenizerで形態素解析している
  2. transformers.MecabTokenizertokenizeで何やらNFKC正規化とlowerで小文字化を制御している様子
  3. __init__normalize_text=Trueとなっている。NFKC正規化はしてもらわなくていいので原因はこいつか。
MecabTokenizerから抜粋
def tokenize(self, text, never_split=None, **kwargs):
    """Tokenizes a piece of text."""
    if self.normalize_text:
        text = unicodedata.normalize("NFKC", text)

    never_split = self.never_split + (never_split if never_split is not None else [])
    tokens = []

    for word in self.mecab(text):
        token = word.surface

        if self.do_lower_case and token not in never_split:
            token = token.lower()

        tokens.append(token)

    return tokens

BertJapaneseTokenizerからMecabTokenizerの引数normalize_textFalseを渡したいので、mecab_kwargsに追記したらよさそうなので、以下に修正。
ついでに、モデルの最大トークン数が事前情報にないのでmodel_max_length=512で指定

model_checkpoint = "./UTH_BERT_BASE_512_MC_BPE_WWM_V25000"

tokenizer = BertJapaneseTokenizer.from_pretrained(
    model_checkpoint,
    word_tokenizer_type="mecab",
    mecab_kwargs={
        "mecab_dic": None,
        "normalize_text": False,
        "mecab_option": "-u /hogehoge/fugafuga/MANBYO_201907_Dic-utf8.dic -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd",
    },
    model_max_length=512
)

公式の例どおりにトークナイズできました。

2002年,夏,より,重い,物,の,持ち上げ,が,困難,に,なり,、,階段,の,[UNK],が,遅く,なる,など,四肢,の,筋力低下,が,緩徐,に,進行,し,た,.,2005年,2,月頃,より,鼻,##声,と,なり,ろ,##れ,##つ,が,回り,##にく,##く,なっ,た,.,また,、,食事,中,に,むせる,よう,に,なり,、,同年,12月,に,当,院,に,精査,入院,し,た,。

厳密には、人名だったら@@Nに置換とか、本家どおりではないです。

BertJapaneseTokenizerじゃなくて統合化されたAutoTokenizerに対応させる

AutoTokenizerは様々なモデルに対して自動的に振り分けてくれて便利だが、UTH-BERTのパス指定だとBertJapaneseTokenizerに渡してくれないので想定通りに動かない。
問題はconfig.jsonの設定が不足していること。

config.jsonの修正

{
  "attention_probs_dropout_prob": 0.1,
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 768,
  "initializer_range": 0.02,
  "intermediate_size": 3072,
  "max_position_embeddings": 512,
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  "type_vocab_size": 2,
  "vocab_size": 25000,
  "model_type": "bert",
  "tokenizer_class": "BertJapaneseTokenizer"
}

要は、"model_type": "bert""tokenizer_class": "BertJapaneseTokenizer"を追記するだけ。

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?