たくあんメモ

だいたいプログラム開発のメモです

mecab-koで簡易的な韓日機械翻訳を作る

本件は ひとり開発 Advent Calendar 2019 - Qiita 7日目にエントリーしています。  

はじめに

私は海外野球のニュース記事を読みたいがために、自分用の機械翻訳を作ってます。
現在は韓国語のみで、あくまで野球ニュース用です。
f:id:gayou:20191207110840g:plain

まあ精度はよくないですが、野球用語や独特の表現を訳すところにフォーカスしており、
後述しますがmecab-koという韓国語用の形態素解析ツールを利用しています。
https://bitbucket.org/eunjeon/mecab-ko/

2月にとりあえず作って以降、定期的に辞書をいじっては訳を改善、、
また辞書をいじったり、追加したりして訳を改善している最中です。
正直言って、ルールベースはやるもんじゃないなと思いました


経緯

私は海外野球の情報(特に順位表や試合速報・結果)をよく見ていて、
主に以下のサイトをよく見ます。

サイト 国/地域 言語 URL
MLB アメリ 英語 https://www.mlb.com/
CPBL 台湾 中国語(繁体字 http://www.cpbl.com.tw/
KBO 韓国 韓国語 https://www.koreabaseball.com/
WBSC 国際大会 英語など6ヶ国語 https://www.wbsc.org/

ブログやtwitterなどで日本語で情報発信してくれている方もいて大変助かってますが、
なるべく一次情報を情報収集したい願望があります。

Google翻訳などのWEBサービスは野球に特化しているわけではないので、
ちょいちょい野球用語や独特の言い回しの訳が変なときがあって、
どうしても????ってなるときがあるんですよね。

たとえば以下、(自分で作った翻訳プログラムの運用中に書いたツイートしたものですが)

野球の試合中、しかも9回裏に試合の勝敗が決まる重要な場面でギターを出す人はいないです。
ここは「先発パク・ジヌの力投と9回裏ソン・シホンのサヨナラ打が出て~」と訳すのが的確です。

振り逃げホイル、、、なんて聞いたことないので、NAVERでダイジェスト映像を見たところ、
捕逸”(捕手がボールをキャッチし損ねて後ろに逸らすこと)でした。

※ダイジェスト映像はこちら(サムネに写っている選手は、元ソフトバンクイ・デホsports.news.naver.com

とまあ他にもありますが、”捕逸”のように一般的でない用語や表現はどのジャンルにもあると思います。

そんなこんなで、海外野球のニュース記事を日本語で読みたいがために、
野球ニュース用の機械翻訳を作ろうと思いたったのでした。


目標

自分で作るにあたって、ゆるっとした目標を立てました。

  • 野球独特の用語や表現はちゃんと訳したい
  • てにをは が多少おかしいのは気にしない
  • 野球ニュース以外の文章は正しく訳せなくていい

要はがんばりすぎないことです。はい。
こればっかりやってて家のこと何もしなかったら、うちの奥さんも黙ってはいないでしょう。


検討

韓国語を選択した理由

なんとなくですが一番難易度が低そうな予感がしたからです。

  • 英語は、、、読めないこともない(すみません嘘です)
  • 中国語は、、、漢字なので雰囲気で読んでる(読めてないです)
  • ハングルは、、、さっぱりわからない(自分の語学レベルでは暗号にしか見えない)
  • 英語と中国語の訳には言葉の並び替えが必要だ(どうしたらいいんだろう)
  • そういえば韓国語と日本語は語順が同じなので、並び替え処理とか書かなくてもなんかできそう
  • 形態素解析すれば、あとはそれを順に日本語に置換していくだけでできそう! *1

という風に考えてました。

で、どうやって作るのか

基本的には何の知識もないのでいろいろ調べたんですが、
以下の方法であれば自分でもできそうだと思いました。

  1. テキストをmeba-koで形態素解析する
  2. 形態素の品詞と訳語を順にくっつけていく
    • ※動詞を過去形や否定文にするなど、いくつか訳語調整
  3. 文章完成!

近年の主流はニューラルネットワークのようですが、
まずは上に書いたような簡単なルールで作ることにしました。 *2


詳細

mecab-ko

mecab-koはmecabを韓国語用にカスタマイズが入ったものです。
(本家mecabだと意図した分割ができなかったです)
辞書はmecab-ko-dicを使っています。
https://bitbucket.org/eunjeon/mecab-ko/src/master/README.md
https://bitbucket.org/eunjeon/mecab-ko-dic/src/master/README.md

mecab-koのインストール方法は、以前Qiitaに書いたことがあります。
qiita.com

事前準備

形態素解析の辞書(mecab-ko-dic)に各形態素の訳語を付加します。
辞書に訳語を持たせておくと、形態素解析と一緒に日本語訳の情報もくっついてきます。

訳語の収集にはGoogleスプレッドシートのgoogletranslate関数を使わせてもらいました。

元の辞書は品詞別の44ファイルに全部で81万word収録されているので、
スプレッドシートも1シートにおさまらないどころか、1ファイルに入りきれないので何ファイルかに分割する必要があるし、
あとgoogletranslate関数の戻りをひたすら待ちます(全word分実行し終わるのに待ち時間長め)。

スプレッドシートでひたすら単語の訳を収集 f:id:gayou:20191206002808p:plain

ただしスクショにあるように収集した訳語はよく分からないのが多く、、
訳語を集めるのには向いてなかったかもです。

形態素解析〜訳文生成

コマンド実行でやるならmecabコマンドです。

$ cat [テキスト] | mecab

私の場合は、

  • ブラウザでテキストを入力
  • AjaxでWEBサーバにテキストを送信
  • WEBサーバでテキストを受け取ったら、mecabへ渡して形態素解析
  • mecabの戻り値を取得し、行ごとにごにょにょ処理

なんてことをしてます。

たとえば以下の文章を形態素解析にかけると

두산 베어스가 1차전에서 짜릿한 끝내기 승리를 거뒀다.

以下のような結果が返ってきます。

두산    NNP,*,T,두산,*,*,*,*,斗山,トゥサン
베어스   NNP,인명,F,베어스,*,*,*,*,ベアーズ
가 JKS,*,F,가,*,*,*,*,が
1   SN,*,*,*,*,*,*,*
차 NNBC,*,F,차,*,*,*,*,次,回
전 NNG,*,T,전,*,*,*,*,戦,{multiple}
에서  JKB,*,F,에서,*,*,*,*,で,から,{multiple}
짜릿  XR,*,T,짜릿,*,*,*,*,ぴりっと,鮮やか
한 XSA+ETM,*,T,한,Inflect,XSA,ETM,하/XSA/*+ᆫ/ETM/*,した,な,{multiple}
끝내기 승리    NNG,*,T,끝내기 승리,*,*,*,*,サヨナラ勝利
를 JKO,*,T,를,*,*,*,*,を
거뒀  VV+EP,*,T,거뒀,Inflect,VV,EP,거두/VV/*+었/EP/*,おさめ
다 EF,*,F,다,*,*,*,*,た
.   SF,*,*,*,*,*,*,*,.,1794,3560,3518,SF,*,*,*,*,*,*,*,。
EOS

辞書にあらかじめ日本語訳の列を追加していたので、
形態素から日本語訳を取得することができます。

あとはこの日本語訳を順につなげていくだけです。
といっても↑の例は簡単なケースですが、動詞の変化系(〜した、〜できた、〜できなかった、〜して、〜しない、〜せずに などなど)の場合は愚直にロジックを書いて変形させてます(めんどくさいので他になんかいいやり方ないかなと、、)。

他にも同音異義語もあるので、これは今は前後の形態素の品詞などで判断して訳語を決めているものもあります。 *3  

運用:訳文の調整

ルールのロジックはいろいろ書いてますが基本的には辞書が重要だと考えてます。

たとえば、最初に例としてあげた以下のような文章。

形態素解析では「끝내」と「기타」の2つに分割されていますが、
ここでは「끝내기」(最後の、サヨナラ)と「타」(打)の2つに分割されて欲しいのです。
※いちおうmecab-ko-dicには「끝내기」「타」の2つの単語は定義されていますが

辞書で定義されているコスト値を調整することで意図したところで分割されるようにするのもよいのですが、 今回は「끝내기타(サヨナラ打)」を一語として新たに辞書に登録しました。

「끝내」という単語にはいろいろ意味を持っており、
”ついに”、”最後”、”終わる”、”素晴らしい”、”最高”、”サヨナラ”などの意味があるようです。
また「기타」という単語は、一般的には”その他”、”ギター”の意味のようです。
どうやら”犠打”は一般的ではなさそうです。
で、このケースの場合はもちろん「素晴らしいギター」ではなく、
最後の犠打→(試合を終える犠打)→サヨナラ犠打 という表現が適切です。
ただし「끝내」「기타」の訳を変えるのではなく、
「끝내기타(サヨナラ犠打)」を一語として新たに辞書に登録することで野球らしい訳になるようにしました。
※2020/10/22 サヨナラ犠打ではなかったので辞書を修正しました。  

他にも野球用語や、外国人選手名なども新しく辞書登録しています。 ※一部辞書抜粋

블론세이브,,,,NNG,*,F,블론세이브,*,*,*,*,(ブラウンセーブ),セーブ失敗
끝내기타,,,,NNG,*,F,끝내기타,*,*,*,*,サヨナラ犠打
굿바이 안타,,,,NNG,*,F,굿바이 안타,*,*,*,*,サヨナラ安打
끝내기쇼,,,,NNG,*,F,끝내기쇼,*,*,*,*,サヨナラ勝利

現在は300語ほど辞書に追加したり、既存の訳を修正したりもします。

単語の意味を調べるときは以下の2サイトを便利に使わせてもらってます。 www.kpedia.jp https://ja.dict.naver.com/main.nhnja.dict.naver.com

やればやるほどだんだんとルールが増えていっているので、
そのうち整合性が取れなくなりそうです。
というわけで、ルールベースはやるもんじゃないなと思いました


システム構成

基本的に自分が使いたいもの、慣れているものを使っています。

サーバ環境

サーバはGCPを利用しています。

基本的に月額費用ゼロです。*4
メモリが少ない(630MB)ですがmecab-koや後述のwebサーバを動かすには十分です。

アプリケーション

Nginx Unitは設定が簡単で素敵です。 www.nginx.com

今後

他言語への対応

韓国語のメンテはほどほどにして、中国語か英語に取り組みたいです。

ルールベースは正直しんどいので、統計的な手法を取り入れてみたいのですが、野球翻訳に向いてる?対訳データがない *5 ので、、、やっぱりルールベースなかあ、と。

また、ツールもいろいろあるのでどれを使うかは悩みます。
個人的には注目しているツールはJieba、Enju、StanfordCoreNLPです。

サーバはOracle Cloudへ移行したい

構文解析ツールを使おうとするとメモリが足りないので、
Oracle Cloudへの移行を検討中です。 Always Freeなインスタンス(メモリ1GB)は2つまで作れます。 www.oracle.com

それにしても無料枠があるなんていい時代になりました。
ケチなおっさんなんだと思われても仕方ないですが別にいいです。
きっちり使いこなしたいと思います。

開発言語はPythonJava

ライブラリが比較的そろっているPythonJavaで作れたらなと考えてます。
Goも気になります。

余談ですが、Nginx Unitはパスごとにどの言語で動かすかの設定が割と楽です。

今は試しにですが、

って設定をしています。以下がunit.jsonの設定内容。

{
    "listeners": {
        "*:8000": {
            "pass": "routes"
        }
    },
    "routes": [
        {
            "match": {
                "uri": "/api/ko/*"
            },
            "action": {
                "pass": "applications/translate-ko"
            }
        },
        {
            "match": {
                "uri": "/api/zh/*"
            },
             "action": {
                "pass": "applications/translate-zh"
            }
        }
    ],

    "applications": {
        "translate-ko": {
            "type": "php",
            "processes": 1,
            "root": "[path]",
            "index": "index.php"
        },
        "translate-zh": {
            "type": "python 3.6",
            "processes": 1,
            "path": "[path]",
            "module": "wsgi"
        }
    }
}

まだまだ雑な設定ですが、別途php-fpmとかuwsgiを準備、設定する必要がなくて便利です。

最後に

私がやっている個人開発は、
自分の困っていることを解決するための手段だったり、
新しいソフトウェア・ライブラリを試すためだったりします。

今回アドベントカレンダーにエントリしている都合、
他の方の個人開発の記事を見ていますが、
みんなそれぞれやっていることが違って楽しいですね。  

Qiita ひとり開発 Advent Calendar 2019は7日目はこれで終わりです。
明日8日目は u1and0さんの「開発環境の紹介 (VM->Docker with tmux, vim)」です。

qiita.com

*1:実際やってみるとそんなに単純にはいかないです

*2:一度、Tensorflowでseq2seqという手法でやろうとして、全然理解が追いつかなくて諦めました

*3:韓国語に詳しいわけではないので、正しいやり方ではないと思います

*4:10月にオーストラリアへの転送量で1円課金されたことあります

*5:WBSCのニュースが多国語配信なので集める手はありますが、見た感じ各国語それぞれ多少リライトが入っていることがあるので、データの整備には手間がかかりそう