Welcome to Mashykom WebSite



BERT (Pytorch_transformers) を用いた日本語処理


 従来、 自然言語処理 における Deep Learning アルゴリズムと言えば、 LSTM や GRU といった RNN (Recurrent Neural Network) でした。ところが、2017年6月、 "Attention Is All You Need" という強いタイトルの論文が Google から発表され、機械翻訳のスコアを既存の RNN モデル等から大きく引き上げます。論文”Transformer: A Novel Neural Network Architecture for Language Understanding”において、RNN や CNN を使わず Attention のみ使用したニューラル機械翻訳 Transformer が提案された。

 BERT(Bidirectional Encoder Representations from Transformers)は、Transformerのアルゴリズムを活用した双方向的エンコード表現による言語処理のアプリで、2018年10月にGoogle AI Languageの研究者が論文で発表したものです。この論文において質疑応答(SQuAD)と自然言語推論(MNL1)、Microsoft Research Paraphrase Corpus (MRPC)などの様々な自然言語処理の幅広いタスクにおいて最先端の結果が公表されたことにより、言語処理の機械学習研究に大きな影響を与えました。

 いうまでもなく、BERTのカギとなる技術的イノベーションは、attentionモデルを採用したことでよく知られているTransformerの双方向的な訓練を適用したことにあります。BERTは、これ以前の自然言語処理モデルが熱心に試みていた文字列を左から右に見ていく、あるいは左から右への訓練とその逆のそれを組み合わせるのとは対照的です。論文で発表された結果は、双方向的に訓練された言語モデルが、単方向的に訓練された言語モデルに比べて文脈と文の流れから見た言語の意味をより深くつかめることを示している。文章分類、質問応答、固有表現抽出等の多様なタスクで公開当時の最高性能(SOTA: State of the Art)を達成しました。

 BERT の重要な貢献は、その「事前学習」を活用した転移学習が可能になったことにあります。BERT の学習は、大量のデータを用いる「事前学習」と比較的少量のデータを用いる「転移学習(ファインチューニング)」の二段階で構成されます。 転移学習とは、例えばImageNetの事例のような既知のタスクにおいて事前学習した後にファインチューニングを実行することです。ここで「事前学習」に用いる大量のデータは 、教師ラベルの付いていない普通の文章でよいというのが重要なポイントです。普通の文章でよければ、日本語版Wikipediaのダンプや(有料ではありますが)新聞のデータなど比較的容易に大量入手が可能です。こうしたラベルなしデータで「事前学習」を済ましてしまえば、その事前学習済みモデルをベースとして、比較的少量のラベル付きデータで「ファインチューニング」を行うことによって、多様なタスクに対応できることになります。

 BERTの内部アルゴリズムについてはここでは説明しませんので、Web上に幾つかの分かりやすい説明もありますので、例えば、BERT を用いた自然言語処理における転移学習https://learnopencv.com/bert-bidirectional-encoder-representations-from-transformers/ などの解説を参照ください。Pytorch コーディングの実装に関する参考書としては、『つくりながら学ぶ! PyTorchによる発展ディープラーニング』(小川雄太郎、マイナビ出版 、19年7月発行)があります。

 このページで取り上げるコードはGoogle Colabで実証できるように、準備しました。私のGithub Repoの Mecab_Juman_Ginza を用いた日本語処理をご利用ください。

Last updated: 2020.2.20 (first uploaded 2020.2.8)



BERTと日本語形態素解析


 BERTにはpretrained model が提供されていますが、日本語の事前学習済みのモデルは多くはありません。公式サイトの多言語モデルがありますが、使い勝手が悪いです。

Juman++を用いて作成された日本語の事前学習済みのモデルの代表例は、京都大学 黒岩・河原研究室 が公開しているBERT日本語Pretrainedモデル です。Mecab を用いた日本語の事前学習済みのモデルの代表例は、https://github.com/cl-tohoku/bert-japaneseです。その他のモデルについては、 自然言語処理で注目のBERTのなかで紹介されていますので、参照ください。

 BERTの日本語での学習済みモデルを利用するとき、Juman++で作成された事前学習済みのモデルを利用するケースでは、形態素解析器としてJuman++が使用されるケースが多いです。ここで、 Juman++のインストールと使用方法について簡単に説明します。

 Linuxでのインストールが基本なので、Juman++のインストール説明の多くはLinuxを前提としています。Macでは、その方法を採用したケースでは、エラーが出ます。Juman++のインストールは、brew を用いて


$ brew install jumanpp

とした方が確実です。Mecab と同じく、/usr/local/Cellar/にインストールされます。同時に、Boostモジュールもそこにインストールされます。Jumanppのサイズは 約1.9 ギガ と非常に大きいです。Boost も680メガあります。日本語用形態素解析器 Mecab の辞書ipadic-neologdを含めたサイズは約900メガなので、Jumanppが必要とするストレージ・サイズは2倍以上の大きさになります。GiNZAが使用するSudachiの辞書のサイズは約220メガです。

 インストールされたことを確認するために、


$ jumanpp -v

と打ちます。「JUMAN++ 1.02 」と帰ってきます。command line でjumanppを実行すると、


$ echo 銀座七丁目はお洒落だ | jumanpp

銀座 ぎんざ 銀座 名詞 6 地名 4 * 0 * 0 "代表表記:銀座/ぎんざ 地名:日本:東京都:地区"
七 七 七 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量"
丁目 ちょうめ 丁目 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:丁目/ちょうめ 準内容語"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
お お お 接頭辞 13 ナ形容詞接頭辞 4 * 0 * 0 "代表表記:御/お"
洒落だ しゃれだ 洒落だ 形容詞 3 * 0 ナノ形容詞 22 基本形 2 "代表表記:洒落だ/しゃれだ 動詞派生:洒落る/しゃれる"
EOS

となります。

 Python でjumanpp を使用するためには、pyknp のインストールが必要です。pyknpのインストールはpipで簡単にできます。


$ pip install pyknp

Jupyter Notebook を起動して、以下のように入力すると、


 from pyknp import Juman
 jumanpp = Juman()
 result = jumanpp.analysis("恵比寿にあるあのイタリアンにはよく行く。美味しいんだ。")
 for mrph in result.mrph_list(): # 各形態素にアクセス
     print(mrph.midasi, mrph.yomi, mrph.genkei, mrph.hinsi, mrph.bunrui, mrph.katuyou1, mrph.katuyou2, mrph.imis, mrph.repname)

解析結果が表示されます。


恵比寿 えびす 恵比寿 名詞 固有名詞 * * 代表表記:恵比須/えびす 恵比須/えびす
に に に 助詞 格助詞 * * NIL 
ある ある ある 動詞 * 子音動詞ラ行 基本形 代表表記:有る/ある 補文ト 反義:形容詞:無い/ない 有る/ある
あの あの あの 指示詞 連体詞形態指示詞 * * NIL 
イタリアン いたりあん イタリアン 名詞 普通名詞 * * 代表表記:イタリアン/いたりあん カテゴリ:人工物-食べ物;抽象物 ドメイン:料理・食事 イタリアン/いたりあん
に に に 助詞 格助詞 * * NIL 
は は は 助詞 副助詞 * * NIL 
よく よく よい 形容詞 * イ形容詞アウオ段 基本連用形 代表表記:良い/よい 反義:形容詞:悪い/わるい 良い/よい
行く いく 行く 動詞 * 子音動詞カ行促音便形 基本形 代表表記:行く/いく 付属動詞候補(タ系) ドメイン:交通 反義:動詞:帰る/かえる 行く/いく
。 。 。 特殊 句点 * * NIL 
美味しい おいしい 美味しい 形容詞 * イ形容詞イ段 基本形 代表表記:美味しい/おいしい ドメイン:料理・食事 反義:形容詞:まずい/まずい 美味しい/おいしい
んだ んだ んだ 助動詞 * ナ形容詞 基本形 NIL 
。 。 。 特殊 句点 * * NIL 

 Jumanppのインストールには2ギガ以上のストレージが必要なので、Google Colabを活用する方法もあります。Google Colab を用いて、Jumanpp を使う方法について説明します。以下のように、Colabのセルに入力します。インストールには20分以上の時間がかかります。


!wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc2/jumanpp-2.0.0-rc2.tar.xz
!tar xfv jumanpp-2.0.0-rc2.tar.xz  
%cd jumanpp-2.0.0-rc2
!mkdir bld
%cd bld
!cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
!make install -j2

# 動作確認(pyknpから)
!pip install pyknp
from pyknp import Juman
jumanpp = Juman()
result = jumanpp.analysis("恵比寿にあるあのイタリアンにはよく行く。美味しいんだ。")
for mrph in result.mrph_list():
    print(mrph.midasi, mrph.yomi, mrph.genkei, mrph.hinsi)

以上の動作確認が正常に稼動すれば、Google Colab でJumanppを使用する準備ができました。Colab のコードはJumanppのColabでの使用にあります。


Transformers + Jumanppによる単語推論


 上でも触れた通り、日本語の形態素解析にJuman++ を使用するケースでは、BERTの応用でよく使用されているのは京都大学の黒橋・河原研究室で公開されている学習済みモデルです。モデルの紹介ページでは次のように説明されています。

  • 入力テキスト: 日本語Wikipedia全て (約1,800万文)
  • 入力テキストにJuman++ (v2.0.0-rc2)で形態素解析を行い、さらにBPEを適用しsubwordに分割
  • BERT_{BASE}と同じ設定 (12-layer, 768-hidden, 12-heads)
  • 30 epoch (1GPUで1epochに約1日かかるのでpretrainingに約30日)
  • 語彙数: 32,000 (形態素、subwordを含む)
  • max_seq_length: 128
  •  BERT日本語Pretrainedモデルのうち、pytorch版BERT (pytorch-pretrained-bert)を利用するケースでは、以下のモデルをダウンロードします。

    Whole Word Masking版: Japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformers.zip ダウンロードしたファイルを解凍して、ディレクトリ/NLP/の下に配置してください。

     まず初めに、Transformers (Pytorch 版 Bert )をインストールする必要があります。(PyTorch もインストールされている必要があります。)インストールの説明はこのサイトにあります。

    
    $ pip install transformers
    
    

     正常にダウンロードされたことをチェックするために、以下のコマンドを打ちます。

    
    $ python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('we love you'))"
    
    

     正常にダウンロードされていれば、

    
    [{'label': 'POSITIVE', 'score': 0.9998704791069031}]
    

     と表示されます。

     transformers (pytorch_transformers)を用いて文章中の単語推論を取り上げてみます。最初に、上記のWikipediaからの学習済みモデルを用います。以下のようにモデルを読み込みます。

    
    import torch
    from transformers import BertTokenizer, BertModel,BertConfig,BertForMaskedLM
    
    config = BertConfig.from_json_file('/path to/NLP/Japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformers/config.json')
    
    model = BertForMaskedLM.from_pretrained('/path to/NLP/Japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformers/pytorch_model.bin',config=config)
    
    

     次に、jumanppを使って、文書をトークン化します。

    
    from pyknp import Juman
    jumanpp = Juman()
    
    text = "宇宙塵は星から生まれ、宇宙に飛んでいきます。これら小さな塵は最終的にはくっつきあって新たな恒星となったり、惑星や月、隕石になったりします。"
    result = jumanpp.analysis(text)
    tokenized_text = [mrph.midasi for mrph in result.mrph_list()]
    print(tokenized_text)
    
    ---
    ['宇宙', '塵', 'は', '星', 'から', '生まれ', '、', '宇宙', 'に', '飛んで', 'いき', 'ます', '。', 'これ', 'ら', '小さな', '塵', 'は', '最終', '的に', 'は', 'くっつき', 'あって', '新たな', '恒星', 'と', 'なったり', '、', '惑星', 'や', '月', '、', '隕石', 'に', 'なったり', 'し', 'ます', '。']
    
    

     文章中にある「恒星」にマスクをかけて、この単語を推論させてみましょう。そのために、以下のような処理が必要です。

    
    tokenized_text.insert(0, '[CLS]')
    tokenized_text.append('[SEP]')
    masked_index = 25
    tokenized_text[masked_index] = '[MASK]'
    print(tokenized_text)
    
    ---
    ['[CLS]', '宇宙', '塵', 'は', '星', 'から', '生まれ', '、', '宇宙', 'に', '飛んで', 'いき', 'ます', '。', 'これ', 'ら', '小さな', '塵', 'は', '最終', '的に', 'は', 'くっつき', 'あって', '新たな', '[MASK]', 'と', 'なったり', '、', '惑星', 'や', '月', '、', '隕石', 'に', 'なったり', 'し', 'ます', '。', '[SEP]']
    
    

     この結果を、BertTokenizer() に読み込みます。

    
    tokenizer = BertTokenizer("/path to/NLP/Japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformers/vocab.txt",
                              do_lower_case=False, do_basic_tokenize=False)
    
    indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
    tokens_tensor = torch.tensor([indexed_tokens])
    print(tokens_tensor)
    
    

     推論させてみます。

    
    with torch.no_grad():
        outputs = model(tokens_tensor)
        predictions = outputs[0]
    
    _, predicted_indexes = torch.topk(predictions[0, masked_index], k=5)
    predicted_tokens = tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
    print(predicted_tokens)
    
    ---
    ['星', '天体', '恒星', '惑星', '地球']
    

     マスクされた場所に入るべき単語が以上のように検出されました。いかがでしょうか。このコードはこのGoogle Colabで実行できます。ただし、必要な学習済み日本語モデル japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformersのフォルダーを/My Drive/data/にアップロードしてください。

     以下に、Transformers(pytorch_transformers)の使用方法についての説明を 公式ページからコピーしました。

    
    # Transformers を用いた API
    # 使用可能なモデル( Model class、 Tokenizer class、 Pretrained weights shortcut)のリスト
    MODELS = [(BertModel,       BertTokenizer,       'bert-base-uncased'),
              (OpenAIGPTModel,  OpenAIGPTTokenizer,  'openai-gpt'),
              (GPT2Model,       GPT2Tokenizer,       'gpt2'),
              (CTRLModel,       CTRLTokenizer,       'ctrl'),
              (TransfoXLModel,  TransfoXLTokenizer,  'transfo-xl-wt103'),
              (XLNetModel,      XLNetTokenizer,      'xlnet-base-cased'),
              (XLMModel,        XLMTokenizer,        'xlm-mlm-enfr-1024'),
              (DistilBertModel, DistilBertTokenizer, 'distilbert-base-cased'),
              (RobertaModel,    RobertaTokenizer,    'roberta-base'),
              (XLMRobertaModel, XLMRobertaTokenizer, 'xlm-roberta-base'),
             ]
    
    # 各モデルに対して、model_class, tokenizer_class, pretrained_weights の使用法:
        # Load pretrained model/tokenizer
        tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
        model = model_class.from_pretrained(pretrained_weights)
    
        # Encode text
        input_ids = torch.tensor([tokenizer.encode("ここにトークン化するテキストを置く", add_special_tokens=True)])  
    
        with torch.no_grad():
            last_hidden_states = model(input_ids)[0]  # Models outputs are now tuples
    
    # ファインチューニングやテキストマイニングのためのモデル・モジュール:
    BERT_MODEL_CLASSES = [BertModel, BertForPreTraining, BertForMaskedLM, BertForNextSentencePrediction,
     BertForSequenceClassification, BertForTokenClassification, BertForQuestionAnswering]
    
    # 各モデルは pretrained weights を読み込んで使用
    pretrained_weights = 'bert-base-uncased'
    tokenizer = BertTokenizer.from_pretrained(pretrained_weights) #日本語ではこのTokenizerの変更が必要
    model = model_class.from_pretrained(pretrained_weights)
    
    

     Pytorch-Pretrained-bert およびPytorch_Transformersの最新バージョンは この PyTorch のサイトにあるGithub のTransformers となっています(2021年2月8日現在)。


    Transformers + Mecab を用いた単語推論


     上述の Transformers の使用方法の説明から分かるとおり、transformers で学習済みモデルを読み込むためには、
     from_pretrained() メソッド
    を使用します。以下のように使います。

    
    model = BERT_MODEL_CLASS.from_pretrained(PRE_TRAINED_MODEL_NAME_OR_PATH, cache_dir=None, from_tf=False, state_dict=None, *input, **kwargs)
    
    

     ここで、BERT_MODEL_CLASS とは、pre-trained weightsを読み込むための、BertTokenizer 、BertModel, BertForMaskedLM、OpenAIGPTTokenizer classesなどを意味します。具体的なコードの仕様を説明します。このコードは、Google Colabにアップしておきましたので、そこで実行できます。最初に、BertTokenizer を呼び出します。

    
    import torch
    from transformers import BertTokenizer, BertModel, BertForMaskedLM
    
    # OPTIONAL:  logなどを出したいとき
    import logging
    logging.basicConfig(level=logging.INFO)
    
    #  pre-trained model tokenizer (vocabulary):日本語のときは、日本語に対するtokenizerが必要
    tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
    
    # 入力をトークン化する
    text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
    tokenized_text = tokenizer.tokenize(text)
    
    # `BertForMaskedLM`を使用するときは、推論したいトークンにMask をかける:ここでは8番目のトークン
    masked_index = 8
    tokenized_text[masked_index] = '[MASK]'
    assert tokenized_text == ['[CLS]', 'who', 'was', 'jim', 'henson', '?', '[SEP]', 'jim', '[MASK]', 'was', 'a', 'puppet', '##eer', '[SEP]']
    
    # トークンを vocabulary indices に変換
    indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
    
    # 上記の各sentence のインデックスを 1st and 2nd(sentences)にする
    segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
    
    # 入力されたテキストを PyTorch tensors 表現に変換する
    tokens_tensor = torch.tensor([indexed_tokens])
    segments_tensors = torch.tensor([segments_ids])
    
    

     この後に、ネットワークのtorch size を確認したい時には以下のように打つ。

    # Load pre-trained model (weights)
    model = BertModel.from_pretrained('bert-base-uncased')
    
    # Predict hidden states features for each layer
    with torch.no_grad():
        outputs = model(tokens_tensor, token_type_ids=segments_tensors)
        encoded_layers = outputs[0]
    
    # We have encoded our input sequence in a FloatTensor of shape (batch size, sequence length, model hidden dimension)
    
    print ('encoded layers =', encoded_layers.shape)
    
    ---------
    
    encoded layers = torch.Size([1, 14, 768]) # 表示される内容
    
    

     あるいは、単語を推論するときは

    # Load pre-trained model (weights):日本語のときは、日本語での学習済みのもの
    model = BertForMaskedLM.from_pretrained('bert-base-uncased')
    model.eval()
    
    # Predict all tokens
    with torch.no_grad():
        outputs = model(tokens_tensor, token_type_ids=segments_tensors)
        predictions = outputs[0]
    
    # confirm we were able to predict 'henson'
    predicted_index = torch.argmax(predictions[0, masked_index]).item()
    predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
    
    print('Predicted Token =' ,  predicted_token)
    
    ---
    
    Predicted Token = henson # 結果が表示される
    
    

     と実行できます。英文の文章を日本語に置き換えれば同様に使用できます。ただし、日本語の形態素解析器が必要です。詳しい説明は、transformers の公式サイトを参照ください。これまで公開されている日本語学習済BERTを利用するためには色々やることが多くて面倒でしたが、最近、BertJapaneseTokenizer が transformers に組み込まれました。これを使えばかなり簡単に利用できるようになりました。このtokenizer は Mecab を用いています。

     日本語形態素解析器としてMecab を用いた学習済みモデルの紹介をします。transformers からアクセスできる日本語むけTokenizer、Bert-japaneseのGithub repoはhttps://github.com/cl-tohoku/bert-japaneseです。学習済みのBERT-base models (12-layer, 768-hidden, 12-heads, 110M parameters)のうち、MeCab + WordPiece tokenizationを行ったものがBERT-base_mecab-ipadic-bpe-32k.tar.xz (2.1GB)です。MeCab + WordPiece tokenizationを用いて、Whole Word Masking 学習したモデルが、BERT-base_mecab-ipadic-bpe-32k_whole-word-mask.tar.xz (2.1GB)です。これは、東北大学 乾・鈴木研究室が作成・公開したモデルです。

     このGithubで提供されている bert-japaneseを用いた単語推論のプログラムの例は以下の Google Colabで実行できます。内容を簡単に説明します。

    
    import torch
    from transformers.tokenization_bert_japanese import BertJapaneseTokenizer
    from transformers.modeling_bert import BertForMaskedLM
    
    

     学習済みモデルを読み込みます。tokenizer と model のインスタンスを作成します。

    
    tokenizer = BertJapaneseTokenizer.from_pretrained('bert-base-japanese-whole-word-masking')
    
    
    
    model = BertForMaskedLM.from_pretrained('bert-base-japanese-whole-word-masking')
    
    

     以上で学習済みモデルが読み込まれます。これらの tokenizer と model を用いて、目的の処理をします。

    
    input_ids = tokenizer.encode(f'''
        東京都港区の大学で{tokenizer.mask_token}の研究をしています。
    ''', return_tensors='pt')
    
    print(input_ids)
    
    
    
    print(tokenizer.convert_ids_to_tokens(input_ids[0].tolist()))
    
    ---
    
    ['[CLS]', '東京', '都', '港', '区', 'の', '大学', 'で', '[MASK]', 'の', '研究', 'を', 'し', 'て', 'い', 'ます', '。', '[SEP]']
    
    
    
    masked_index = torch.where(input_ids == tokenizer.mask_token_id)[1].tolist()[0]
    print(masked_index)
    
    
    result = model(input_ids)
    pred_ids = result[0][:, masked_index].topk(5).indices.tolist()[0]
    for pred_id in pred_ids:
        output_ids = input_ids.tolist()[0]
        output_ids[masked_index] = pred_id
        print(tokenizer.decode(output_ids))
    
    ---
    
    [CLS] 東京 都 港 区 の 大学 で 映画 の 研究 を し て い ます 。 [SEP]
    [CLS] 東京 都 港 区 の 大学 で 哲学 の 研究 を し て い ます 。 [SEP]
    [CLS] 東京 都 港 区 の 大学 で 医学 の 研究 を し て い ます 。 [SEP]
    [CLS] 東京 都 港 区 の 大学 で 数学 の 研究 を し て い ます 。 [SEP]
    [CLS] 東京 都 港 区 の 大学 で [UNK] の 研究 を し て い ます 。 [SEP]
    
    

     という結果が表示されます。[UNK]は unknown の省略形です。単語の推論に提供されるデータが少ないので、このような結果になりました。


    gensim + torchtext を用いた単語の埋め込みベクトルとコサイン類似度


     word2vec は、コーパスの単語間の共起統計情報のデータセットをもとに次元削減技術を適用することで「単語の埋め込み(embedding)」を実現します。このような自然言語のベクトル化手法を用いたword2vecは、単語間の関連性を、対応するベクトル間演算(足し引き)で表現できるようにします。例えば、

    king - man + woman = queen
    Paris - France + Japan = Tokyo

    が成り立つように単語の埋め込みベクトルを決定するものです。

     word2vecはこのように、語彙数より少ない次元embedding数のベクトル化手法を採用しています。その特徴は、単語間の関連性をベクトル表現に反映しているところですが、その手法には、CBOW(Continuous Bag-of-Words Model)とContinuous Skip-gram Model(以下、skip-gramと表記)の2種類があります。この両者ともに、埋め込みベクトルの作成するための学習に3層(一つの隠れ層を持つ)ニューラルネットワークを使います。

     MeCabとGensimを用いた単語の埋め込みベクトル化を取り上げます。東北大学の乾・岡崎研究室が公開している日本語のword2vec 学習済みモデルを使います。

     以下のサイトから学習済みモデルをダウンロードします。これを解凍して、フォルダ「data」内にフォルダ「entity_vector」とその中の「entity_vector.model.bin」というファイルを配置します

     以下のコードは「つくりながら学ぶ! PyTorchによる発展ディープラーニング」(小川雄太郎、マイナビ出版 、19/07/29) 」から引用しました。Mecab 、gensim 、fasttext 、pytorch はインストールされていることは前提です。なお、以下に説明するコードは、Google Colabで実行できます。

    
    # 単語分割にはMecab+NEologdを使用
    import MeCab
    
    m_t = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')
    
    def tokenizer_mecab(text):
        text = m_t.parse(text)  # これでスペースで単語が区切られる
        ret = text.strip().split()  # スペース部分で区切ったリストに変換
        return ret
    
    # 前処理として正規化をする関数を定義
    import re
    
    def preprocessing_text(text):
        # 改行、半角スペース、全角スペースを削除
        text = re.sub('\r', '', text)
        text = re.sub('\n', '', text)
        text = re.sub(' ', '', text)
        text = re.sub(' ', '', text)
    
        # 数字文字の一律「0」化
        text = re.sub(r'[0-9 0-9]', '0', text)  # 数字
    
        return text
    
    
    # 前処理とMecabの単語分割を合わせた関数を定義する
    
    
    def tokenizer_with_preprocessing(text):
        text = preprocessing_text(text)  # 前処理の正規化
        ret = tokenizer_mecab(text)  # Mecabの単語分割
    
        return ret
    
    
    import torchtext
    
    # tsvやcsvデータを読み込んだときに、読み込んだ内容に対して行う処理を定義します
    # TEXTとLABELの両方を用意します
    
    max_length = 25 #一つの文章の単語数は25以下
    TEXT = torchtext.data.Field(sequential=True, tokenize=tokenizer_with_preprocessing,
                                use_vocab=True, lower=True, include_lengths=True, batch_first=True, fix_length=max_length)
    LABEL = torchtext.data.Field(sequential=False, use_vocab=False)
    
    
    # フォルダ「data」から各tsvファイルを読み込みます
    train_ds, val_ds, test_ds = torchtext.data.TabularDataset.splits(
        path='./data/', train='train.tsv',
        validation='val.tsv', test='test_tsv', format='tsv',
        fields=[('Text', TEXT), ('Label', LABEL)])
    
    

     train_ds 、val_ds 、test_ds の作成の仕方は、こうしてやるのだと理解してください。なお、これらに対応して、tsvファイルが/data/内に配置されています。tsvファイルは3種類、train.tsv、val.tsv 、test.tsvが必要です。中身は全て同じでも結構です。このtsv ファイルの中身は、王、女王、王子、姫、機械学習の言葉が入っていれば、tsv形式の適当な文章でいいです。日本語の事前学習したモデルは、そのままではtorchtextで読み込めないので、gensimライブラリを使用して、読み込みます

    from gensim.models import KeyedVectors
    
    # 一度gensimライブラリで読み込んで、word2vecのformatで保存する
    model = KeyedVectors.load_word2vec_format(
        './entity_vector/entity_vector.model.bin', binary=True)
    
    model.wv.save_word2vec_format('./japanese_word2vec_vectors.vec')
    
    

     torchtextで単語ベクトルとして読み込みます。

    
    from torchtext.vocab import Vectors
    
    japanese_word2vec_vectors = Vectors(
        name='./japanese_word2vec_vectors.vec')
    
    # 単語ベクトルの中身を確認します
    print("1単語を表現する次元数:", japanese_word2vec_vectors.dim)
    print("単語数:", len(japanese_word2vec_vectors.itos))
    
    ---
    # 以下の結果となります
    1単語を表現する次元数: 200
    単語数: 1015474
    
    

     ベクトル化したバージョンのボキャブラリーを作成します。

    
    TEXT.build_vocab(train_ds, vectors=japanese_word2vec_vectors, min_freq=1)
    
    # ボキャブラリーのベクトルを確認します
    print(TEXT.vocab.vectors.shape)  # 49個の単語が200次元のベクトルで表現されている
    
    
    

     ボキャブラリーの単語の順番を確認します

    
    TEXT.vocab.stoi
    
    

      姫 - 女性 + 男性 のベクトルがどれと似ているのか確認してみます。単語の順番で[55]、[53]、[65]は女性、姫、男性となっています。

    
    import torch.nn.functional as F
    
    # 姫 - 女性 + 男性
    tensor_calc = TEXT.vocab.vectors[55] - \
        TEXT.vocab.vectors[53] + TEXT.vocab.vectors[65]
    
    # コサイン類似度を計算
    # dim=0 は0次元目で計算してくださいという指定
    print("女王", F.cosine_similarity(tensor_calc, TEXT.vocab.vectors[54], dim=0))
    print("王", F.cosine_similarity(tensor_calc, TEXT.vocab.vectors[63], dim=0))
    print("王子", F.cosine_similarity(tensor_calc, TEXT.vocab.vectors[64], dim=0))
    print("機械学習", F.cosine_similarity(tensor_calc, TEXT.vocab.vectors[61], dim=0))
    
    
    

     結果は

    
    女王 tensor(0.3840)
    王 tensor(0.3669)
    王子 tensor(0.5489)
    機械学習 tensor(-0.1404)
    

     となります。王子が最も近いということになりました。word2vecより進歩したベクトル化手法であるfastTextによる単語のベクトル表現を使用しても、同じ結果となります。その場合、以下のサイトから vector_neologd.zipをダウンロードします。


    <-- 続く   -->

    日本語処理のページに移る

    このページの先頭に戻る