SHIROBAKO大好き人間のブログ

SHIROBAKOが好きなエンジニアによる技術ブログ

略語ジェネレータを作ってみた

TensorFlowに慣れるための練習として略語の自動生成器を作ってみました。

ここでは、その大まかな仕組みを書いていきます。

仕組みとかいいからとりあえず試したいという方はこちらへどうぞ→略語ジェネレータ

(※Herokuの無料プランでデプロイしたので最初のアクセスは時間がかかります)

大まかな仕組み

今回は

「略語にしたい単語を1文字ずつ入力→その文字を略語に使うか使わないかを出力」

という処理を行うモデルを作成することにしました。

モデルの訓練手法は、過去に入力した文字が略語に影響すると考え、時系列のデータを扱えるRNN(Recurrent Neural Network)を選択しました。

大まかな処理の流れは以下のようになってます。

  1. MeCabを用いて入力された語をカタカナに変換
  2. 変換したカタカナを1文字ずつ入力ベクトルに変換
  3. RNNに入力

1. MeCabを用いて入力された語をカタカナに変換

1文字ずつ入力するモデルを作ること自体は問題ないのですが、それを訓練しようとすると上手く行きません。

なぜなら、漢字を含めると日本語の文字の種類は多すぎるからです。

そこで、モデルを少し簡単にしてカタカナのみでモデルの訓練を行うことにしました。

そのために、RNNに入力をする前処理としてMeCabを用いて入力された語句を全てカタカナに変換します。

MeCabは本来は日本語の形態素解析器で、日本語の文の各語句に自動で品詞をつけてくれるソフトウェアです。

解析を行う際に、各語句の品詞だけでなく読み仮名も取得してくれるので、今回はこれを利用して入力語句をカタカナに変換します。



ちなみに、漢字からカタカナへ変換することが目的として作られたKAKASIというソフトウェアもあるそうです。

別にこちらを用いても良かったのですが、MeCabMECAPIというWeb APIを実装してくれた方がおり、そちらを使ったほうが手間が少なさそうだったのでMeCabを採用しました。

2. 変換したカタカナを入力ベクトルに変換

MeCabで入力語句をカタカナに変換したら、今度はそれをRNNに入力するために数値ベクトルに変換します。

文字をベクトルに変換する場合、真っ先に思いつくのはone hot vectorといわれるものです。

これは、ベクトルの各次元がその文字かどうかを表すようなベクトルです。

例えば「ア」という入力に対してベクトル(1, 0, 0, ...)を対応させ、「ウ」という入力に対してベクトル(0, 0, 1, ...)を対応させます。

もちろんこの方法でも問題は無いのですが、今回は違うベクトルを用いてみました。



日常で使われている略語って語呂が良いものが多いですよね?

語呂が良いということは、略語は音を意識して作られている可能性が高いということです。

なので、音の要素をベクトルとして表せば、略語の生成も上手く行くのではと考えました。

具体的には、入力されたカタカナの子音と母音に基づいてベクトルを作ります。

例えば「ウ」が入力され場合を考えます。

まずは子音です。

子音ベクトルをア行の文字が入力された時は第1要素を1に、カ行の文字が入力された時は第2要素を1に、・・・というようなベクトルとします。

「ウ」の場合の子音ベクトルは(1, 0, 0, ...)となります。

次に母音は、ア段の文字が入力された時は第1要素を1に、イ段の文字の時は第2要素を1に、・・・というようなベクトルを考えます。

「ウ」の場合の母音ベクトルは(0, 0, 1, 0, 0)となります。

最後に、この子音ベクトルと母音ベクトルを結合して、それをRNNを入力します。

言葉だけだと伝わるか不安なので、コードも載せておきます。

コード中のconsonant_vecが子音ベクトルで、vowel_vecが母音ベクトルのことです。

#coding:utf-8

import codecs

def convert_str_to_vec(input_str):
    output_vec = []
    kana_lists = [\
            [u"ア", u"イ", u"ウ", u"エ", u"オ"],\
            [u"ァ", u"ィ", u"ゥ", u"ェ", u"ォ"],\
            [u"カ", u"キ", u"ク", u"ケ", u"コ"],\
            [u"ガ", u"ギ", u"グ", u"ゲ", u"ゴ"],\
            [u"サ", u"シ", u"ス", u"セ", u"ソ"],\
            [u"ザ", u"ジ", u"ズ", u"ゼ", u"ゾ"],\
            [u"タ", u"チ", u"ツ", u"テ", u"ト"],\
            [u"ダ", u"ヂ", u"ヅ", u"デ", u"ド"],\
            [u"ナ", u"ニ", u"ヌ", u"ネ", u"ノ"],\
            [u"ハ", u"ヒ", u"フ", u"ヘ", u"ホ"],\
            [u"バ", u"ビ", u"ブ", u"ベ", u"ボ"],\
            [u"パ", u"ピ", u"プ", u"ペ", u"ポ"],\
            [u"マ", u"ミ", u"ム", u"メ", u"モ"],\
            [u"ヤ", u"", u"ユ", u"", u"ヨ"],\
            [u"ャ", u"", u"ュ", u"", u"ョ"],\
            [u"ラ", u"リ", u"ル", u"レ", u"ロ"],\
            [u"ワ", u"ヰ", u"", u"ヱ", u"ヲ"]]

    for char in input_str:
        consonant_vec = [0] * 20
        vowel_vec = [0] * 5
        if char == u"ン":
            consonant_vec[17] = 1
        elif char == u"ー":
            consonant_vec[18] = 1
        elif char == u"ッ":
            consonant_vec[19] = 1
        elif char == u"ヴ":
            consonant_vec[10] = 1
            vowel_vec[2] = 1
        else:
            for i, kana_list in enumerate(kana_lists):
                if char in kana_list:
                    index = kana_list.index(char)
                    consonant_vec[i] = 1
                    vowel_vec[index] = 1
                    break

        output_vec.append(consonant_vec + vowel_vec)

    return output_vec

3. RNNに入力

2.で変換したベクトルをRNNに入力して1か0かを出力します。

1だったら略語として使われ、0だったら切り捨てられるといった感じです。

ここまで来れば、あとはTensorFlowのコードを書くだけですね。

TensorFlowのコードはあちこちで紹介されてますし、今回のコードには特にややこしいロジックも無いのでここでは紹介しません。

一応GitHubには上げたので、興味がある方がいたらどうぞ。

データ

訓練に用いるデータは、ネット上から集めた348の略語を用いました。

もっと多くても良いとは思うのですが、略語に関して体系的にまとまってるページが無く、意外と集めるのが大変だったので少なめです。

精度

上記のデータを使って10-fold cross validationを行ったところ、正解率は87.2%でした。

・・・・・・うーん、微妙ですね。

せめて90%は行ってほしかった。

ちなみに、one hot vectorを用いて同じことをしたところ、正解率は84.8%でした。

one hot vectorよりも子音ベクトル+母音ベクトルの方が正解率が高いので、使うベクトルに工夫を凝らした意味は一応あったみたいです。

まとめ

という訳で、以上のような仕組みで作った略語ジェネレータがこちらです→略語ジェネレータ

精度があまり高くないので、ネタの1つとして使ってください。

普段使っている単語や音楽の曲名を入れると面白いですよ!