日本語版RoBERTaを使う(Juman++のインストール方法)
BERTの後継モデルであるRoBERTaの日本語版が早稲田大学河原研究室より公開されています。
- RoBERTa-Base(系列長:128)
- RoBERTa-Learge(系列長:128)
- RoBERTa-Learge(系列長:512)
京都大学黒橋・褚・村脇研究室や早稲田大学河原研究室の公開する事前学習済みモデルはよく使われるipadic系のmecabではなく、juman辞書を用いたjuman++にて前処理が行われておりhuggingface社の提供するtokenizer APIでは前処理が行えません。
本記事ではjuman++のインストールを含めて、先述の事前学習済みモデルが利用できるようになるまでの手順を説明します。
juman++について
ソースコードはこちらに公開されていますので詳しくは、こちらのリポジトリを参照してください。
juman++のインストール
macOS(intel版)の場合
まず、ビルドツールのダウンロードを行います。
brew install cmake wget zlib
次にソースをダウンロードして手元環境でビルド&installします。
cmakeの実行時に-DCMAKE_INSTALL_PREFIX="インストール先"
とフラグを設定することでインストール先を自由に設定できます。
wget "https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz"
tar xvJf jumanpp-2.0.0-rc3.tar.xz
cd jumanpp-2.0.0-rc3
mkdir bld && cd bld
cmake .. -DCMAKE_BUILD_TYPE=Release
sudo make install -j $(getconf _NPROCESSORS_ONLN)
以上でjuman++のインストールは完了します。
jumanpp -v
# Juman++ Version: 2.0.0-rc3
M1 Macの場合
wget "https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz"
tar xvJf jumanpp-2.0.0-rc3.tar.xz
cd jumanpp-2.0.0-rc3
mkdir bld && cd bld
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/Users/ユーザー名/nlp/opt/jumanpp
このままmakeコマンドを実行しビルドを行うとエラーが発生するのでソースコードを書き換える。libs/backward.hpp
の2267,2268行付近を以下のように改変する。
// #elif defined(__aarch64__)
// error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.pc);
#elif defined(__aarch64__)
#if defined(__APPLE__)
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext->__ss.__pc);
#else
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc);
#endif
また, libs/catch.hpp
を最新にする。
curl -LO https://github.com/catchorg/Catch2/releases/download/v2.13.8/catch.hpp
mv catch.hpp ../libs/
改変後makeを実行しビルドを行う
make -j $(getconf _NPROCESSORS_ONLN)
make install
Linux(debian系)の場合
必要なパッケージを一通りインストールします。
sudo apt update -q
sudo apt install -qy cmake g++ make wget xz-utils
ソースをダウンロードします。
wget "https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz"
tar xvf jumanpp-2.0.0-rc3.tar.xz
ソースをビルドしてインストールします。
cd jumanpp-2.0.0-rc3
mkdir bld && cd bld
curl -LO https://github.com/catchorg/Catch2/releases/download/v2.13.8/catch.hpp
mv catch.hpp ../libs/
cmake .. -DCMAKE_BUILD_TYPE=Release
sudo make install -j "$(nproc)"
sudo make install
簡単な使い方
標準入力に解析したい文字列を流し込むことで形態素解析が行えます。
echo "形態素解析器を使ってみる。" | jumanpp
# 形態 けいたい 形態 名詞 6 普通名詞 1 * 0 * 0 "代表表記:形態/けいたい カテゴリ:形・模様"
# 素 そ 素 名詞 6 普通名詞 1 * 0 * 0 "代表表記:素/そ カテゴリ:抽象物 漢字読み:音"
# 解析 かいせき 解析 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:解析/かいせき ドメイン:教育・学習;科学・技術 カテゴリ:抽象物"
# 器 き 器 名詞 6 普通名詞 1 * 0 * 0 "代表表記:器/き カテゴリ:人工物-その他 漢字読み:音"
# を を を 助詞 9 格助詞 1 * 0 * 0 NIL
# 使って つかって 使う 動詞 2 * 0 子音動詞ワ行 12 タ系連用テ形 14 "代表表記:使う/つかう"
# みる みる みる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本形 2 "代表表記:みる/みる"
# 。 。 。 特殊 1 句点 1 * 0 * 0 NIL
# EOS
深層学習用途では単語分割ができれば良いので、その際は--segment
オプションをつけてください。
echo "形態素解析器を使ってみる。" | jumanpp --segment
# 形態 素 解析 器 を 使って みる 。
ファイルごと処理をする場合は
jumanpp --segment -o "出力ファイル" "入力ファイル"
と実行することで処理ができます。さらに詳しくは先述のリポジトリや、-h
オプションを使って確認してください。
解析速度に関する比較
有名なMeCabと比べると精度には勝る一方で解析速度は劣ります。NLP100本ノックの「吾輩は猫である」を解析する速度をベンチマークとして解析速度の計測を行なってみます。
wget https://nlp100.github.io/data/neko.txt
wc -l neko.txt
# 9964 neko.txt
time mecab -Owakati neko.txt > /dev/null
# mecab -Owakati neko.txt > /dev/null 0.07s user 0.01s system 97% cpu 0.075 total
time jumanpp --segment neko.txt > /dev/null
# jumanpp --segment neko.txt > /dev/null 1.73s user 0.10s system 68% cpu 2.656 total
mecabの方が60倍早い結果となりましたが、jumanppの場合呼び出しのオーバーヘッドが大きいので大きなテキストを解析する場合は10倍程度の速度差になります。l
依存ライブラリのインストール
transformersはもちろんいくつかのライブラリをインストールしていないとエラーが出ます。
pip install torch
pip install git+https://github.com/huggingface/transformers
pip install sentencepiece
pip install protobuff
これで準備が整いました。
試してみる
"日本語の自然言語処理は難しい 。"という文字列を解析してみましょう。
echo "日本語の自然言語処理は難しい。" | jumanpp --segment
# 日本 語 の 自然 言語 処理 は 難しい 。
"難しい"というトークンを[MASK]に置き変えて、先ほど紹介した早大robertaでトークンの予測をしてみます。まずは利用するライブラリや事前学習済みモデルの読み込みを行います。
import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM
tokenizer = AutoTokenizer.from_pretrained("nlp-waseda/roberta-base-japanese")
model = AutoModelForMaskedLM.from_pretrained("nlp-waseda/roberta-base-japanese")
次にmaskトークンの予測です。Huggingface社の提供するPipelines APIを使えばもっと簡単に実現できますが、今回はスクラッチで処理を記述します。
# maskされたトークン位置を取得する
def get_masked_index(encoding):
for idx, id in enumerate(encoding.input_ids.squeeze(0)):
if id == tokenizer.mask_token_id:
return idx
# 入力系列の処理
sentence = '日本 語 の 自然 言語 処理 は [MASK] 。'
encoding = tokenizer(sentence, return_tensors='pt')
# 予測
pred = model(**encoding)
# 後処理(取得した予測分布から、maskトークンの上位k件の予測結果を取得)
masked_idx = get_masked_index(encoding)
target_probs = pred.logits.squeeze(0)[masked_idx]
# 上位k件の予測結果をのindexを取得
top_k = torch.topk(target_probs, k=5).indices
for id in top_k:
print(sentence.replace("[MASK]", f"'{tokenizer.decode(id)}'"))
# 日本 語 の 自然 言語 処理 は '得意' 。
# 日本 語 の 自然 言語 処理 は 'できる' 。
# 日本 語 の 自然 言語 処理 は '専門' 。
# 日本 語 の 自然 言語 処理 は 'ない' 。
# 日本 語 の 自然 言語 処理 は '苦手' 。
早大robertaによると日本語の自然言語処理は"得意"だそうです。
juman++で前処理がされていることで些か癖があると言える早大robertaですが、日本語wikipediaと、CC-100の日本語部分で学習されており既存の事前学習済みモデルより巨大なコーパスを用いて学習されている点が強みかと思います。
なお、このモデルは試験的な公開ということで学習時の最大系列長が128になっています(大抵は512)ので各タスクにfine-tuningをする際などは注意が必要です。
終わりに
また早大河原研究室では日本語版のGLUEベンチマーク(JGLUE)が作成されており近いうちにそのベンチマーク結果も公開されるとのことです。
日本語の自然言語処理のさらなる発展を期待しましょう。
Discussion