LoginSignup
30
13

More than 3 years have passed since last update.

低頻度語をぶっ壊す~How to subword-nmt~

Last updated at Posted at 2019-07-29

LSTMとかの深層学習モデルで自然言語を扱うとき、
語彙数が増えると計算量やGPUメモリサイズが爆発的に増えてしまうことが多い。

予め低頻度語をBPEサブワード化することで語彙サイズを減らそうというエントリー。

サブワード化ってなんだ。

あまり出現しない単語を、文字や部分文字(サブワード)に分割しようということ。
これにより、語彙サイズが圧縮できる。
極端な話、英単語を文字に分割すれば語彙数は英語アルファベットの52種(大文字+小文字)に圧縮可能。

BPEって何だ。

BPE(Byte Pair Encoding)は元々圧縮に使われていた技術。
共通な2バイトを新しい1バイトに置き換えることで圧縮していく。
例えば、aabbaacaaAに置き換えると、AbbAcと圧縮できる。

この処理を語彙圧縮に適用したのが、
Neural Machine Translation of Rare Words with Subword Units

事前にコーパスの語彙に対してBPEを適用することで、サブワードを学習する。

subword-nmtのインストール

subword-nmtを使えば、簡単にBPEを使用したサブワードの学習とサブワード化ができる。
Pythonで書かれているのでpipでインストールする。

pip install subword-nmt

データ準備と前処理

サブワードの学習にはコーパスが必要。
今回は、吾輩は猫であるを用意した。

wagahai.txtの一部
 吾輩わがはいは猫である。名前はまだ無い。
 どこで生れたかとんと見当けんとうがつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。

日本語からサブワードを学習する場合は、文章はあらかじめ単語単位に分割されている必要がある。
今回はMeCabを使って、分かち書きしたwakati_wagahai.txtを用意した。

mecab -b 100000 -Owakati wagahai.txt -o wakati_wagahai.txt
wakati_wagahai.txtの一部
  吾輩 わがはい は 猫 で ある 。 名前 は まだ 無い 。 
  どこ で 生れ た か とんと 見当 けん とう が つか ぬ 。 何 でも 薄暗い じめじめ し た 所 で ニャーニャー 泣い て いた事 だけ は 記憶 し て いる 。 吾輩 は ここ で 始め て 人間 という もの を 見 た 。 

いざサブワードの学習

以下のコマンドでwakati_wagahai.txtからサブワードを学習する。

subword-nmt learn-bpe -s 3000 < wakati_wagahai.txt > codes.txt

-sは共通文字置き換え回数を指定している。
小さいほどサブワードは文字単位になる。(0だと完全に文字になるはず。)

codes.txtの中身はこんな感じ。

codes.txtの一部
吾 輩</w>
ま す</w>
さ ん</w>
じ ゃ</w>
な っ</w>
こ れ</w>
と こ
で も</w>

吾 輩</w>は、単語内に輩</w>が出現したら我輩</w>に結合するよ。という意味。
さっきのBPEの例で行くとaaAにするよ。と同意。
(</w>は元の単語の末尾であることを表してます。 )

サブワード化する。

学習したcodes.txtを用いて以下のコマンドでwakati_wagahai.txtをサブワード化してみる。

subword-nmt apply-bpe -c codes.txt < wakati_wagahai.txt > subword_wagahai.txt

subword_wagahai.txtはこんな感じ。

subword_wagahai.txtの一部
  吾輩 わが@@ はい は 猫 で ある 。 名前 は まだ 無い 。 
  どこ で 生れ た か とんと 見当 けん とう が つか ぬ 。 何 でも 薄@@ 暗い じ@@ め@@ じめ し た 所 で ニャ@@ ー@@ ニャ@@ ー 泣い て いた@@ 事 だけ は 記憶 し て いる 。 吾輩 は ここ で 始め て 人間 という もの を 見 た 。

わが@@はいと元々1単語であったことを示している。

低頻度語は解体できたのか

以下の簡単なPythonスクリプトで語彙数を確認してみる。

import sys
for arg in sys.argv[1:]:
    print("Input : {}".format(arg))
    with open(arg, "r") as f:
        text = f.read()
    tokens = text.split()
    print("Vocab : {}".format(len(set(tokens))))
$ python3 counter.py wakati_wagahai.txt subword_wagahai.txt 
Input : wakati_wagahai.txt
Vocab : 15717
Input : subword_wagahai.txt
Vocab : 7515

無事語彙数が15717から7515に減ったことがわかる。

30
13
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
30
13