Author Archives: staka

ニューラル機械翻訳モデルと対訳データの品質

ニューラル機械翻訳モデルやDeepLearningに限らずだがデータ品質とデータ量の関係は良く話題になる。品質の良い少量のデータでモデル構築を行うべきなのか、多少品質が悪くとも大量のデータを用いるべきなのかという議論である。

本記事ではニューラル機械翻訳モデル(Marin-NMTによるTransformer)を対象としてデータ品質を向上させた約1000万対訳ペアのデータと品質向上前(最低限のクレンジングを実施)の約1400万対訳ペアのデータで構築したモデル[1]を比較した。

その結果、品質向上後データではBLEU=28.6、品質向上前データではBLEU=27.5とBLEUで約1.1pointの品質向上の効果が示された。これは乱数で出るような影響ではなく本件で実施した品質向上処理には意味があるものと思われる。

以下、詳細を記載する。

基本的なクリーニングロジック

FuguMTでは様々なデータセット(日英の対訳データ)を用いてモデル構築を行っている。用いているデータセットの品質には大きな差があるため基本的に下記のデータクリーニングを行っている[1]。

  • 日本語文、英語文それぞれをUniversal Sentence Encoder[1]で分散表現に変換、コサイン距離が一定以内のものを採用
  • 日本語文をMeCab[2]で形態素に分割、日本語文の形態素の数と英単語の数の比が一定範囲内のものを採用
  • 日本語文が日本語文字セットの文字で構成されているかを確認(UnicodeのHiragana lettersを含むかなど一定のルールで対応)、英語文も同様に構成文字が妥当かを確認。
  • 対訳ペアが数字を含む場合、双方に同じ数字があるかを確認。無い場合は「数字を表す単語(例:one, two, …)」「月を表す単語(例:Jan~Dec)など数字に変換可能な単語を含んでいるか」と「0の数を変化させる表現(例:hundredやmillionなど)」があるかを確認、加えて、それが正しい対応になっているかを確認[5]

上記処理によって多くの対訳ペアがフィルタリングされる。公開されている対訳データによっては有効な対訳ペアが半分程度になることもある。

wikimatrixなど機械的に対訳アライメントを行ったデータに対しては最後の数字対応によるフィルタリングが特に有効である。(逆に言うとこのようなデータセットは数字が対応していない対訳ペアを多く含んでいる。)機械翻訳モデルでも数値対応は課題になることが多い。数値を含めての自動対訳アライメントは簡単ではないのであろうと思う。一方で数値を対象としたルールベースによるフィルタリングはそれほど困難ではない。このようなデータを用いる場合はぜひ行ったほうが良い処理である。

現在公開されているFuguMTモデルCC Alignedデータを加える際も同様の処理を行った。今回、さらに厳しい基準を用いた場合にどのような変化があったかをメモがてら記載する。

CCAlignedデータ追加時に行った処理

CCAlignedデータの追加にあたり、基本的なクリーニングロジックに加えて3つの処理を追加した。これはCC Alignedのデータを目検したところSPAM的なデータ[6]が多く含まれており品質があまり良くなったためである。残念ながら前述のクリーニングロジックでは品質が低い機械翻訳をフィルタリングすることが難しかった。

  • LaBSE[7]を用いてベクトル化した対訳文ペアのコサイン距離を計算し、一定範囲に入っているか
  • fasttextのLanguage identification[8]の結果がそれぞれの言語(日本語、英語)で判定されているか
  • 記載内容+取得元URLに対してSPAM的なデータではないかを2値分類モデルで判断

最後の処理は一定数のデータをハンドラベリングしたのちにSPAM判定モデルを構築し実施した[9]。SPAM判定ではURL情報が非常に有効であった。(当たり前ではあるが)URLによろしくない単語を含んでいる場合はほぼSPAMサイトであった。

データセットにURL情報がないなど適用不可能な場合を除き、既存データにも追加クリーニングを実施した。

品質向上前は全部で14,023,805対訳ペアのデータ数であったが、クリーニングの結果10,903,035対訳ペアに減少した。

モデル構築と精度評価結果

今までと同様、Marian-NMT (transformer) sentencepiece を用いてニューラル機械翻訳モデルの構築を行った。使用した機材はAWS p3.2xlarge インスタンスである。学習はearly stopping有りで行い、最善の学習を行った結果を用いて評価を行った。学習時間はおおむね同等でありデータ数が少なくなった影響は見られなかった。

機械翻訳モデルの精度評価には学習データに含まれない4,145対訳ペア[10]を用いた。対訳ペアの半数はデータセットの分割により、残りの半数はドメイン外のデータを用いて作成している。評価のメトリクスにはBLEUを用いた。

結果、品質向上後データではBLEU=28.6、品質向上前データではBLEU=27.5と約1.1ポイントBLEUが向上した。

所感

BLEUで+1.1 pointは経験的に[11]乱数の揺れで出る値では無いので、データ品質向上の効果はあったものと思われる。

基本的なクリーニングロジックでも相応の処理を行っていると思っていて、その効果がある事は確認している。そのため追加処理で300万対訳ペアを削ってもBLEUが上がるのは正直驚きであった。削られたデータにも有用そうなものはあるのでデータ品質とデータ量のバランスを良い感じにする取り組みは今後も続ける必要がありそうな気がしている。

作成したモデルの品質確認は現状でも続けている。現実のデータである程度性能確認ができたところでモデルを公開しようと思っている。現状では前回公開したモデルよりも若干性能が向上しているように思う。データ量を660万ペアから1000万対訳ペアに拡張した効果は出ているようである。

脚注

[1] モデル構築手法はこれまでのものと同じでMarian-NMT + sentencepieceを用いている。比較はそれぞれのデータセットに含まれない4,145文で行った。
[2] 問題のある対訳ペアが少ないtatoebaのみ例外的にクリーニングは行っていない。それ以外のデータセットについては対訳データとされていてもクリーニングの対象としている。(実際問題のある対訳ペアを含んでいる)
[3] https://tfhub.dev/google/universal-sentence-encoder/4
[4] https://taku910.github.io/mecab/
[5] 基本的にルールで対応している。
[6] ここでは品質の低い機械翻訳モデルによって機械的作成されたサイトのこと
[7] https://tfhub.dev/google/LaBSE/2
[8] https://fasttext.cc/docs/en/language-identification.html
[9] クリーニング用モデルを作ってデータ品質を高めることは近年の大規模モデル(T5やGPT-3など)でも普通に行われている。
[10] それぞれの英語文に対して、一律小文字に変換、記号(+空白)を除いてキー情報を作成、学習データとテストデータでキー情報が一致するものが無い事を確認している。
[11] 本来は正しく評価したいところだがAWS費用が高額なので十分な検証が難しい。できることならABCIとか使いたい。

Arxiv論文の翻訳サイト

前回公開した機械翻訳モデルのアプリケーションとして、arXivに投稿された人工知能関連の論文のメタデータ(タイトル・アブストラクト)とCreative Commonsライセンス(CC 0, CC BY, CC BY SA)の本文を日本語に翻訳するサイトを作成した。

Fugu-MT: arxivの論文翻訳

トップページでは投稿日別に最新3日の要約を表示している。メタデータ・本文の翻訳は日付別の参照から確認できる。全文翻訳がある場合はそのリンクを貼っている。

アブストラクトを要約・翻訳して一覧化も行っている。

Fugu-MT: arxivの論文翻訳(概要)

スマホなどで最新の論文をざっくり確認したい場合は便利だと思う。arXivのメタデータはCC 0なので要約や翻訳が可能である。

技術的な話

サイトの構成

このサイトはarXivのAPIを用いて人工知能分野の最新論文を取得、Fugu Machine Transratorを用いて日本語に翻訳している。PDF本文を翻訳するエンジンはリンク先のgithubにあるものを若干カスタマイズして使っている。

静的なWEBサイトで構成するため[1]に、翻訳結果などは基本的にHTML化して保存している。PDF情報もBASE64で埋め込んでいて、HTMLファイルをダウンロードすればどの環境でも翻訳文の閲覧が可能である。

CSSやJSはCDN経由としているので、「wgetでダウンロード」「ブラウザでリンク先を名前を付けて保存」などCSSやJSをローカルに保存する動きをしない方がうまく動く[2]。

2週間程度動かしてみてArxivに投稿された論文をライセンス別に集計すると大体1/3くらいは全文翻訳可能なライセンスとなっていた。最近Openなライセンスの論文が増えている印象で非常にありがたい。

作成したサイトでは30ページを超える論文は翻訳対象外としている[1]。30ページを超える論文の和訳が欲しい・Arxiv以外のサイトで翻訳可能な論文の和訳が欲しいなどの場合はFugu Machine Transratorでこのサイトと同じようなことができる(若干不具合があるので、今月中には修正予定)。

arXivへのアクセスはかなりゆっくりやっていて、API Limitやrobots.txtで決められた待機時間より2倍以上長めのwaitを入れているので更新は遅めかもしれない[3]。

要約処理

アブストラクトの要約にはPEGASUS: Pre-training with Extracted Gap-sentences for Abstractive Summarization論文)を用いている。PEGASUSはAbstractive Text Summarizationタスクで優秀なモデル(CNN / Daily MailでPapers with Code 3位[4])として知られている。論文のアブストラクトをさらに要約するにはExtractiveな手法ではイマイチであり、Abstractiveな要約手法を採用した。結果、まずまず良い感じに要約できているように思う。

所感など

arXivの日本語翻訳を行っているサイトはいくつかあり、また、arXiv Vanity を使ってブラウザの翻訳機能経由で日本語翻訳を行うことを紹介しているものもあった。arXiv VanityはPDFではなくそのソースであるTeXをベースにHTML化しているようで品質が高い[5]。正直、実用的にはこのような方法で十分だと思うが、自作ニューラル機械翻訳モデルの性能評価の意味を込めてサイトを作成してみた。

結果、アブストラクトについては大手翻訳サイトと比べても十分に比較可能なレベルで翻訳ができているように思う[6]。論文本体はPDFのテキスト化、英語文のsentence tokenizeに課題を抱えているためそこまで高精度ではないが「流し読みに便利」程度のレベルにはなっている。

Abstractiveな要約いわゆる抽象型と呼ばれる要約手法はExtractiveな要約(抽出型要約)に比べて安定した性能を出しにくいことが多いが、今回は翻訳を通しても文の破綻が少なくまずまずの性能が出せている。(要約部分も翻訳部分も意訳に近い動きをしているため、内容が変わることも少なからずあるが・・・[7])

前回TODOに挙げていた事を無視してarXivの翻訳サイトを作ってしまったが、良い経験にはなった[8]。英語のNLPでできる事は非常に多いのでFuguMTを便利に使ってもらえたら嬉しい[9]。

一応、1400万対訳ペアでのモデリング、1400万対訳→1000万対訳ペアへのフィルタリング(高品質化)なんかもやってはいるので、ぼちぼち翻訳エンジンの強化も再始動したいと思う最近。NLP周りの英語での成果を使うためにはEN→JAだけでなくJA→ENも必要なのでそのモデルも作ろうかなーとも思っている[10]。

脚注

[1] VPSのスペックによるもの・・・。
[2] ブラウザがJSやCSSをダウンロードし、リンクを書き換えるとうまく動作しないことがある。
[3] APIのデータは日本時間午前8時頃に更新されるがアクセス過多になっていることが多い。アクセス過多の時のwaitもかなり長めにとっているので新規論文リストを取得&論文のメタデータを取得完了するのは日本時間11時頃になっていると思う。(大体、次の日には和訳できてる、くらいのイメージ)
[4] 2021/2/14現在。リンク先にはExtractiveな要約が入っていない、PwCのLeader boardに載っていない結果もある、などの理由で実際の順位は不明。とはいえ、SOTAと比べて大幅に性能が低いわけではない。(正解が正解か怪しい世界でROUGEという微妙な指標を用いてベンチマークした結果よりも、要約したいドメインでの目検証の方が重要・・・。本件でも実は様々な手法を試している。)
[5] Robots.txt的にTeXファイルの取得はDisallowな気もしつつ、どう実装しているかは謎。
[6] 論文ドメインでのfine tuning無しの素の結果なので結構優秀ではなかろうかと自画自賛。ただ、語彙の点で負けている感はある。ニューラル機械翻訳モデルのパラメータチューニング&(やや反則だが)論文ドメインでのfine tuningを行えば大手翻訳サイトの性能を越えられるんじゃないかと思わなくはない。(がAWS費用がつらい)
[7] 要約文が破綻していても翻訳側で救っている場合もあった。要約結果があまりに変な文だと翻訳側が壊れる(同じ単語を繰り返す)みたいな事も起きる。
[8] 現実のデータと格闘しないと分からないことは多い。
[9] 日本語版のpre trainedモデルがたくさん公開されるとかNLPは日本語版がSOTAみたいな時代が来ると嬉しいが、現実は厳しい気がしている。マルチリンガル方面は流行なので、それで解決される可能性も感じているが・・・。
[10] GPU買っちゃおうかなーとも。対訳データを1円/wordくらいで買ってくれるとこないかな、、、

フリーのニューラル機械翻訳モデルFuguMT

英文を日本語訳するニューラル機械翻訳モデルをCC BY-SA 4.0で公開した。以前の記事で紹介した手法を用い昨年11月に構築したモデルである

  • FuguMT ver.2020.11.1 (約440MB)のダウンロード
  • shasum: 0cf8a1fc540b4c7b4388b75b71858c0eb32e392a
  • ライセンス: CC BY-SA 4.0  (readmeにも書いた通り、作者(Satoshi Takahashi)は本モデルを使用して発生したあらゆる結果について一切の責任を負いません 。引用等を行う場合はこのBlogのURLを記載するか、リンクを貼ってください。)

性能はそこそこ(後述)。構築手法は本格的(Marian-NMT[1]を用いた Transformer + Sentence Piece[2])である。

研究用途での試用を前提としており、当然ながら動作や出力に関して一切の責任を負えない(重要なので2度目) [3] がCreative Commonsに従って利用可能なモデルは珍しいと思う。

周辺のコードを含めてgithubにuploadしたので、利用する場合はgithubのfugumtリポジトリを参照いただきたい。githubのコードは基本的にテストサイトと同様だがシンプルに使用可能な構成にしている[3]。

翻訳を行う場合は著作権に注意。最近はCC Zeroなど自由なライセンスで公開される論文等も増えてきているとはいえ、通常、著作物を自由に翻訳することはできない。

モデルの詳細

githubに記載の通り FuguMT ver.2020.11.1 は様々なデータセットを組み合わせて作成している。使用したデータ量は約660万対訳ペア(日本語:690MB 英語:610MB、約1億words)である。 AWS p3.2xlarge 上で Marian-NMT + SentencePieceを用い約30時間の学習を行った。

公開するモデルは「model.npz」と「model_uncased.npz」の2つで、前者は英文をそのまま日本語訳するモデル、後者は英文を小文字に統一(sentence pieceの–normalization_rule_name = nmt_nfkc_cf)し日本語訳するモデルである。 fine tuningも可能。詳細な設定はzipファイル中の「model.npz.yml」「model.npz.progress.yml」を確認してほしい。fine tuning時にはreadmeを読みライセンスに従った取扱いをお願いしたい。

このモデルの性能はKFTT テストデータのBLEUで23程度である。技術文書、論文に対してはもう少し性能が高く、BLEUで30程度とオンラインで公開されている翻訳エンジンと同レベルの性能を出すことができる。BLEUは良い指標とはいいがたいため、 テストサイト で試してみると大体の性能が分かると思う。このBlogを書いている時点ではテストサイトの翻訳エンジン1はFuguMT ver.2020.11.1のmodel.npzを使用している[4]。

多くの場合 「model.npz」の方が良い結果を出力するが、翻訳が難しい文の場合「model_uncased.npz」の方が安定した結果を出力する。githubのfugumtライブラリでは複数の翻訳結果候補から良いと思われる出力を選ぶ機能を実装している。

FuguMT ver.2020.11.1 で利用したデータセット

FuguMT ver.2020.11.1 で使用したCreative Commonsライセンスのデータセットは下記の通り。CCで利用可能なデータセットには非常に助けられた。フリーなライセンスで公開された方々に感謝したい。FuguMTの構築には下記以外に独自に収集したデータも利用している[5]。

使い方

fugumtに記載の通り。githubのDockerfileをbuildし、モデルをダウンロード、marian-decoder経由で使う手順がテストを行いやすい。CPU 1コアで実行した場合1文の翻訳に2-3秒は必要である。

fugumtライブラリでは文章の文分割、訳抜け防止モードの実行、翻訳の適切さのスコアリング、複数の翻訳候補から良い翻訳文を選ぶ機能などを実装している。

pdf_server.pyを使うとpdfminerを用いてPDF文書をそのまま翻訳できる。pdf_server.pyはpickleを出力する。server.pyの機能でPDFと訳文を対比しながら内容を確認できる。 計算時間は1ページあたり1分程度である。

今後の予定

githubにも書いている通り、TatoebaとCCAlignedを用いたモデルは構築済みで性能評価中である。対訳ペア数は1400万に達しているものの、CCAlignedのデータに機械翻訳されたものが多数混在しており総合的な性能が向上するかは検証できていない。これを含め、今後下記のようなことをやりたいと思っている[7]。

  • 対訳ペアを1400万ペアに拡張したモデルの性能評価・公開
  • FastAPI等を利用したAPI化
    • bottleの実装を改善したい
  • 英語→日本語だけではなく日本語→英語のエンジン作成
    • 基本的にはデータを反転させれば作れる
  • Back Translation、BARTやmT5など事前学習モデルの活用、文脈を使った翻訳などモデルの高度化
    • Back Translationの活用はマシンパワーがあれば可能
    • BARTは試行したが性能が向上しなかった。とりあえず中断した検証を再開したい。
    • 1400万対訳ペアのうち7割程度は文脈を考慮可能[8]で文脈を考慮するモデルは構築したい(構築できる)。
  • 英語・日本語以外への対応
    • フランス語、ドイツ語、イタリア語、スペイン語、ロシア語、ポルトガル語は一定程度の対訳をコレクションしている。

その他

とりあえず夏休みの宿題で作ったものを形にして冬休み(+1週間)に公開できたのは良かった。 FuguMTは気軽に使えるがモデル性能はそこまで高くない。何らかのサービスで利用する場合は大手翻訳サイトのAPIと比較してみてほしい。

元々のモチベーションはSuperGLUEのような標準データセットの日本語版を作りたいというものだった。SuperGLUEは昨年末に「解決」されてしまい、xtremeといったマルチリンガルなベンチマークも流行っているのでやや時代遅れ感もある。。。が、勉強にはなった。

次に何をやるかは考え中。今後の予定にあることを地道にやっていくか、全然違うことをやるかも正直決めていない。

対訳ペアのデータの公開は今のところ考えていない。商業的価値のあるデータだと思いつつ、リーガルチェックや税金の問題など様々な課題があるので相当の金額でないと有償提供もしないと思う。

脚注

[1] Marian-NMT: https://github.com/marian-nmt/marian
[2] SentencePiece: https://github.com/google/sentencepiece
[3] 特に差別的な翻訳を行う可能性など十分な検証はできていない。
[4] 安定性は若干劣る。テストサイトはuwsgi+nginxで動作させる構成としている。もっとも、Marian-NMT自体が非常に良くできたソフトウェアなので、npzファイルさえあれば他はいらないかもしれないが・・・。
[5] これらデータを機械翻訳モデル構築に用いた場合、機械翻訳モデル(npzファイル)のライセンスがどうなるかは多くの議論がある。ここでは出所・ライセンスを明確にし、引用条件は配布サイトの表記に従っている。
[6] データはフィルタリングして使用。660万対訳ペアのうち300万対訳ペア程度は自力で収集したデータである。
[7] 趣味でやっているので時間が足りない。加えてAWS費用が重い。
[8] ただの文ではなく、ドキュメントとしてデータを保持している。

機械翻訳と訳抜けとConstituency parsing

翻訳エンジンのお試しサイト(https://devneko.jp/demo/)を更新した。主に下記の機能を追加している。

  • 最大3000文字までの長文対応
  • 訳抜け防止モードの高度化
  • 翻訳結果に対するスコア表示

長文対応は文字数制限を外してnltkのsent_tokenize[1]を使用しているだけである。翻訳結果に対するスコア表示、訳抜け防止モードは以下のように多少工夫した。

訳抜け防止モード

Deep Learningな機械翻訳では訳抜けという現象が発生する。これは訳すべき英文を省略してしまうという現象である。結果、流暢であるが情報が欠けた文章が出力される。Google翻訳やDeepL翻訳などメジャーな翻訳エンジンでも起きることがあり(当然ながら)個人開発の翻訳エンジンではよく発生する。

例えば、下記の英語文を翻訳する例を示す。

Natural language processing (NLP) is a subfield of linguistics, computer science, and artificial intelligence concerned with the interactions between computers and human language, in particular how to program computers to process and analyze large amounts of natural language data.

https://en.wikipedia.org/wiki/Natural_language_processing 11 October 2020, at 18:45 (UTC) の版、Wikipediaより引用

現在の私の翻訳エンジンは上記文章を「 自然言語処理(nlp)は、コンピュータと人間の言語間のインタラクションに関する言語学、コンピュータ科学、人工知能のサブフィールドである。 」と翻訳し、「in particular」以後の情報が抜けている[2]。

訳抜けには様々な理由が考えられるが長い文だと発生しやすい。そこで訳抜け防止モードではconstituency parsing[3]を行ったうえで意味が成立しそうなブロックに分割し翻訳エンジンを適用するフローを採用している。ブロック分割した結果はお試しサイトの一番下に表示される。本件では翻訳対象の文が

Natural language processing ( NLP ) is a subfield of linguistics, computer science, and artificial intelligence concerned with the interactions between computers and human language,

https://en.wikipedia.org/wiki/Natural_language_processing 11 October 2020, at 18:45 (UTC) の版、Wikipediaより引用

in particular how to program computers to process and analyze large amounts of natural language data.

https://en.wikipedia.org/wiki/Natural_language_processing 11 October 2020, at 18:45 (UTC) の版、Wikipediaより引用

に分割された。結果、訳抜け防止モードでは上記の英文を「自然言語処理(nlp)は、コンピュータと人間の言語間の相互作用に関する言語学、コンピュータ科学、人工知能のサブフィールドである。 特に、コンピュータが大量の自然言語データを処理および分析するためのプログラム方法。」と翻訳した。意味としては良くなっている一方で流暢さは損なわれている。 実装した訳抜け防止モードは文を分割して翻訳しているだけであり、現状の機械翻訳エンジンは文脈の考慮もできていない。訳抜け防止モードの翻訳品質は通常モードに比べて低くなる。

翻訳エンジンのお試しサイトでは通常の翻訳×2[4]と訳抜け防止モード×2の結果を文毎に比較し、最も良い結果(スコア算出方法は後述)を採用している。

スコア表示

お試しサイトでは英語文と対応する翻訳文それぞれについてスコアが付与されている。スコアは翻訳文が良いかどうかを表す指標であり、0.0 – 1.0で評価される。概ね0.7以上であればそれなりの訳文になっていることが多く、0.5以下の場合は何かしらの問題が起きていることが多い。特に0.3以下の場合はほぼ確実に訳抜けが発生している。

スコアは「①文の類似度」×「②単語/形態素数の類似度」で計算している。「①文の類似度」はUniversal Sentence Encoder[5] + cos類似度である。LaBSE[6]も試行したがこのタスクではメモリ・計算時間の増加[7]に比べて効果が薄かった。「② 単語/形態素数の類似度 」は英文の単語数と日本語文の形態素数の比率が対訳データの平均(0.85)に近いかを計算している。形態素解析はMeCabを用いた。

所感・その他

お試しサイトの処理フローは以下の通りで機械翻訳エンジンを使う際の対応は大体実施できた気がしている。

  1. 改行が連続した場合は別の文とみなし、処理ブロックを分ける。(途中改行が1つの場合、文は連続しているとみなす。arxivの論文やPPT資料でありがちな改行の入り方に対応している。)
  2. 処理ブロック内の文章をNLTKのsent_tokenizeで文に分割する。
  3. 文に分割されたデータそれぞれに対してconstituency parsingを行い、意味が成立すると思われる一定の長さで文を分割する。
  4. 上記、2.、3.で作成した文のリストを機械翻訳エンジンで和訳する。和訳はハイパーパラメータを変えた2つのエンジンで行う。
  5. 翻訳対象の英語文それぞれについて4つの和訳結果(3.の有無×4.の2つの結果)のスコア(USEのcos類似度×単語/形態素数の平均比)を計算し、一番良いものを採用する。

それなりに複雑な処理になっているがOSSのソフトフェア・モデルをフル活用しているためコードの記述量はそこまで多くない。上記処理もそのうちgithubとかで公開しようと思っている。

(今のところ情熱が残っているので)今後は翻訳エンジン自体の強化を行っていく予定である。

現時点で前回使ったデータに加えて約200万対訳ペアの作成が完了している。加えて50万対訳ペア程度は追加できそうなのでデータ量は1.5倍程度にはなる見込みである。ぼちぼち小文字統一をしなくても良さそうなデータ量になっていることもあり、条件を変えながら深層学習モデルを作って比較するような事もやっていきたい[8]。

文脈が計算可能なデータ(対訳ペアの元となったドキュメント情報が残っているデータ)もそれなりにあるので、文脈パラメータを入れた機械翻訳エンジンの作りたいなーとも思っている。

構築したモデルはCC BY SAくらいのライセンスで公開する予定で自然言語処理分野の英語データセットを和訳する利用方法を想定している。アノテーション構造を保持したい場合の支援機能[9]組み入れも予定しつつ、時間があまりないなーと思っている今日この頃。

脚注

[1] https://www.nltk.org/api/nltk.tokenize.html?highlight=sent_tokenize#nltk.tokenize.sent_tokenize
[2] メジャーな翻訳エンジンは正しく処理する。流石である。
[3] 今回はAllen NLPのhttps://demo.allennlp.org/constituency-parsingを用いた。
[4] 翻訳はハイパーパラメータを変えて2回実行している。複数候補を出して選ぶというのもよく見られる構成だが、本件では行っていない。
[5] https://tfhub.dev/google/universal-sentence-encoder/4 対訳データ作成でもお世話になったモデルである。
[6] https://tfhub.dev/google/LaBSE/1 BERT系のモデルであり、多言語対応のText Embedding用途では最新・最高性能に近いと思われる。
[7] 類似度の妥当性ではUSEに比べてLaBSEがやや良いが、計算時間が数十倍(50倍以上)でありメモリ使用量も増加する。お試しサイトで使っているVPSで動かすのは厳しかった。
[8] AWS課金が凄いことになりそう。。。本当はBack Translationもやりたい・・・。
[9] 英語文→日本語文でタグ構造を維持する程度の機能は入れたい。tokenizer(sentence piece)構築時点でタグを特殊記号扱いし、対訳ペアに正しくタグを扱っている文を追加して学習させる予定である。このあたりは翻訳エンジンそのものに手を入れないと実現しにくく、メジャーな翻訳エンジンで同様の事をやるのは簡単ではないと思っている。

翻訳エンジンの構築(Marian-NMT)

夏休みの宿題(?)としてMarian-NMTを使って翻訳エンジンを構築してみた。構築した翻訳エンジンは「英語→日本語翻訳(https://devneko.jp/demo/)」から試すことができる。訳すべき単語を飛ばすなど深層学習な機械翻訳特有のミスをすることも多いが、個人が試作したものとしては相応の性能な気がする。割と訳せていて正直驚いた。ただ、入力文の適切な分割など前処理的な事をほとんどやっていないので変な結果になることも多い。

データセットは「WEB クロール + Universal Sentence Encoderで収集したデータセット」+「Free(Creative Commonsライセンスなど)のデータセット」、使用した手法はTransformer + sentence pieceであり、バリバリのDeep Learningで現時点でも本格的である。ただし、環境制約(というか時間制約&予算制約(後述)からBack Translationは使えていない。)

上記エンジンでは300文字以内の英語文(複数文の場合性能は落ちる) [1] を日本語に翻訳することができる。訳抜けを防止するモードもあるが、カンマや記号で文を分けているだけなので訳抜け防止モードの性能はあまりよろしくない。

翻訳エンジンを作った理由

本当は日本語でGPT-2辺りのfine tuningを試そうと思っていて「Faster than training from scratch — Fine-tuning the English GPT-2 in any language with Hugging Face and fastai v2 (practical case with Portuguese)」という素晴らしい記事を読んでいた。その中に「For example, to obtain a Portuguese GPT-2, we could download from the Transformers library of Hugging Face the OpenAI GPT-2 pre-trained in English and the MarianMT translator」という記載があったものの、残念ながら「日本語→英語」のモデルは公開されているが「英語→日本語」 のモデルは公開されていなかった[2]。

自由に使える翻訳エンジンは役に立ちそう[3]なので自分で構築することにした。車輪の再発明ではあるが、色々と良い経験になったと思う。

翻訳エンジンの作り方

翻訳エンジンを作るにはデータセット、学習用ソフトウェア、学習環境が必要である。今回は下記を用いた。

  1. データセット: WEBをクローリングして収集[4]+Freeで公開されているものを追加 [5]
  2. 学習用のソフトウェア: Marian-NMT (transformer) + sentencepiece [6]
  3. 学習環境: AWS p3.2xlarge インスタンス [7]
Read more »

脳からの知識蒸留(Distilling the Knowledge from a Brain) – 結果 –

前回からの続き。脳からの知識蒸留を目指し実験を行った。目的は効率的なハンドラベリングであり、今回のPoCでは生体情報をDeep Learningの蒸留と同じ方法、ソフトターゲットの設定で活用できるか?を検証した。

解いた問題と前提

データセット

脳からの知識蒸留を目指すため、前回作成したツールを用いて約330枚のバラの写真に対するハンドラベリングを行った。ハンドラベリング時に取得したデータは次の通り。

  • 病気の区分(黒星病・うどん粉病・健康)
  • 病気の進行度(軽症・中程度・重症)
  • 脳波(集中度を利用)
  • 分類にかかった時間(集中度の平均化のために使用)

元データはバラの病気診断サイト用に収集したもので、黒星病・うどん粉病・健康が1/3ずつとなるよう調整し、ハンドラベリングを実施した(各クラスのデータ数は同じ)。進行度は軽症が半分、中程度以上が半分な感じだが、データセット内の進行度の割合は調整していない。

モデル・学習の概要

今回は3クラス(黒星病・うどん粉病・健康)分類問題を(Convolution層+Pooling層)×2+分類用の層×2なCNNで解くシンプルな問題設定・モデルとした。転移学習や事前学習は行っていない。
脳からの知識蒸留が有効かを確認するため、下記4つのデータで学習し結果を比較した。

  1. 病気区分のラベルのみを用いた学習(普通の学習)
  2. 病気区分のラベルと進行度を併用した学習。病気進行度が高いほど病気区分ラベルの確信度が高くなるようにした。
  3. 病気区分のラベルと脳波を併用した学習。集中度が低いほど病気区分ラベルの確信度が高くなるようにした。(難しく考えなくても分類できたと言う意図[1])
  4. 病気区分のラベルと進行度と脳波を併用した学習。2.と3.の掛け算。

データセットを学習用75%・評価用25%に分割し、2エポック後の評価用データに対する正解率を比較した。学習データ・評価データに含まれる写真は4条件すべてで同一である(4条件でデータ分割による有利不利は生じていない)。loss関数として1.ではcategorical_crossentropyを、2.-4.ではkullback_leibler_divergenceを用いた。これは、2.-4.の正解データが教師の出力(本件では人間の確信度に相当する分布)でありバイナリ値ではない為である。

結果とまとめ

結果は次の通りであった。驚くべきことに[2]、Distilling the Knowledge from a Brainには効果があった。

  1. 通常の学習:正解率 37%
  2. 進行度の併用:正解率 37%
  3. 脳波の併用:正解率 41%
  4. 進行度+脳波の併用:正解率 49%

結果の解釈は難しいが、正解ラベル以外の情報(特に脳波)にも意味がありそうな感じである。データ数が少なく、そもそもの正解率が低いので何ともいえない感もあるので、今後データ数を増やして再度実験を行ってみたいところ。以下、硬い感じのまとめ。
AIが流行るにつれてハンドラベリングの重要性も上がっている[3]。本PoCではハンドラベリング時に脳波を測定し、それをモデル学習時に使用することで学習の効率化が出来る事がわかった。今後のラベリング作業では脳波を測定することがスタンダードになるだろう[4]。分類時の脳波付きデータセットが広く公開されることを期待する[5]。そのようなデータセットのもと、Distilling the Knowledge from a Brainの活用や脳波予測タスクをマルチタスクの1つとして解く学習によって、他のタスクの精度が上がっていくと推測される[6]。
(硬いまとめはここまで。個人的な思い的な考察はその他に続く。)

脚注

[1] この仮定は相当怪しい。
[2] こんな雑な問題設定・解き方で差が出るとは思わなかったが、複数回実行しても結果がほぼ同じであった。同じモデルにtrainを繰り返していないか確認したり、1.-4.の学習順番を変えてみたりもしたが同じ結果だった。びっくり。観測者効果的なもので脳波が変わったのだろうか?それはそれでびっくりだが。
[3] これはたぶん本当。実務では大きな課題。
[4] 脳波計測がスタンダードにはならないだろうが、取りやすい生体データが併用される可能性は感じた。特に心拍とか視線とか。
[5] 欲しい人がいれば今回のデータを公開してもよいかなーと思いつつ、雑にやったところを綺麗にするのが面倒なので、お蔵入りになりそうな予感がしている。
[6] 個人的にマルチタスクへの適用に可能性を感じている(参考論文「One Model To Learn Them All」)が、良い感じのデータが無いので試せていない。暇があったらやるかも。
Read more »

脳からの知識蒸留(Distilling the Knowledge from a Brain) – 準備-

知識の蒸留(Knowledge Distillation)とは?

Deep learningの世界では知識の蒸留(Knowledge Distillation)が行われている。蒸留というと非常にかっこよい響きなのだが、やっているのは「大きなモデル」を用いて「小さなモデル」を「効率的に学習・構築」することである。
バラの病気診断モデルは以前紹介したように次の手順で構築した。

  • データ(写真)を集めて、ラベル(病気の有無など)を人が設定する(ハンドラベリング)。
  • ハンドラベリングしたデータを用いて、教師あり学習を利用し、植物の葉が病気か否かを判別する多値分類モデルを構築する。

上記で構築したバラの病気診断モデルはInception V3をベースにしておりネットワークの規模が大きい(ネットワーク規模の情報)。すなわち、高精度だが低速度である。バラの病気診断モデルをスマホに展開したい場合、若干精度を落としてでもネットワーク規模が小さく高速なモデル(例えばMobileNet)を使いたくなる。普通はデータだけ再利用してモデルは学習しなおすというプロセスが必要となるが、蒸留を用いると効率的な構築が可能となる。ざっくりとした仕組みは次の通りである。

  1. 病気診断モデル(Inception V3 / 先生)に学習用画像データを入力し、その画像に対する「健康・黒星病・うどん粉病・その他カビ系の病気」の4カテゴリの確率を得る。
  2. 病気診断モデル(Inception V3 / 先生)が出した4カテゴリの確率情報も用いて病気診断モデル(MobileNet / 生徒)を学習する。

普通は健康か否かという0/1の情報で学習するが、高精度モデルが診断した確率にも有用な情報が含まれているので、それを利用しようというアイデアである。実際に蒸留は効果があり、モデル圧縮をする場合によく用いられている。詳細はIntelの記事が良くまとまっていて、kerasを用いた実装例も載っている。

脳からの知識の蒸留(Distilling the Knowledge from a Brain)

バラの病気診断サイトを作ったときに時間がかかったのは、病気か否かのラベリングである。一般的に人間によるラベリングは高コストであり、しかも、間違いが含まれている。ハンドラベリングをしたことがある人ならわかると思うが、現実のデータには判定に困る画像も多い。加えて判定基準は人によって異なっている。同症状の画像に異なるラベルが貼られていることは少なくない。
ハンドラベリングは教師である人間から、生徒であるDeep Learningな各モデルへの情報伝達に他ならない。ということは蒸留の仕組みも利用できるはずである。人間が下した0/1の判断だけではなく、それに付随する判断確率の情報を用いれば高速・高精度なモデルが構築できるに違いない。問題は判断確率の分布情報をどうやって得るかであるが、近年のテクノロジーによって解決できる。すなわち脳波を計れば良い[1]。

脳波の測定とラベリング

今回、脳波の測定はNeuroSkyのMindWave Mobile 2で行った。このデバイスを用いてハンドラベリング時の脳波をはかり、その値をラベルの確度の一つとして利用する。MindWave Mobile2は1.5万円くらいで購入でき、python+thinkgearを用いてデータの取得が可能である(serialではなくpyserialが必要なことに注意)。なお、本件はMacで実施したのでWindowsではやり方が異なる可能性がある。
ライブラリはpipから導入できる。

pip install thinkgear
pip install pyserial

ライブラリ導入後、pythonを用いて

device = '/dev/tty.MindWaveMobile-SerialPo'
tg = ThinkGearProtocol(device)
for pkt in tg.get_packets():
  for d in pkt:
    if isinstance(d, ThinkGearAttentionData):
      val = d.value
      now = datetime.datetime.now()
      print("{},{}".format(now, val))

と言う感じでデータが取得できる(上記の例では脳波というよりは集中度をとっている)
今回は下画像のようなラベリング用簡易WEBアプリに脳波取得ロジックを組み込み、ラベリング実施時の脳波(特に集中度)を計測・保存した。ハンドラベリング時には0/1な病気判定だけでなく、その病気の進行度も選べるようになっており、迷いが生じると脳波に現れる[2]。モデル構築の学習時に脳波情報を併用することで、Deep Learning部の収束が早くなれば、脳からの知識蒸留ができた[3]と言えるのではないか。

実験の結果は次ページで報告。

脚注

[1] 別に脳波である必要は無い。むしろ、脳波は計測が難しく、このような用途には適していない。
[2] 実際のところ現れたと言えば現れたが本当に脳波なのかはかなり疑問である。前述の通り、心拍とか血圧とか目線とか判断までの時間とか脳波よりも測りやすくて効果がありそうな指標は多数存在する。
[3] 本件が誇大広告であることは認識している。が、Deep Learning関係の研究論文から著しく外れた言葉使いはしていない(と思う)ので激しい突っ込みは勘弁してください。

AI診断の信頼性:XAI(Explainable Artificial Intelligence)とLIME

これまで3回にわたって、AIで植物の病気を診断するサイトを作った時の話をまとめた。「その他」の所に「作ったモデルにイマイチ自信ないわー」と書き続けた気がするので、(正しく)Deep Learningな人工知能(AI)を構築する難しさと、その対応について記事にしてみた。

Deep Learningを使用したモデルはイマイチ信頼できない

ラノベのタイトルみたいだなーと思いつつ・・・。色々な場所で言われている通り、Deep Learningを使用した判別モデルが実際のところ何を行っているかを知るのは簡単ではない。AIに限らずだが、モデル作成を長くやっているとクロスバリデーションで高精度なモデルが現実世界では全く使えない状況に遭遇する。特に、ドメイン知識から考えてモデルに納得感が無い場合、「評価設計が間違えている」「リーク情報(leakage) を拾っている」「データのバイアスが影響している」事が原因で、現実問題に対して有効でない事が多い。納得感はまっとうなモデルを作る上でとても重要である。私は何をやっているかわからない(説明可能性がない、納得感のない)モデルを用いることに恐怖感を感じるし、それを信頼して使うことは出来ない。(そーいうこともあり、でぃーぷらーにんぐは、しょうじき、しごとではあんまつかいたくない。(画像が対象ならいろいろ確認しつつ使うけど・・・。))

Deep Learningを説明する取り組み

Deep Learningのような複雑なモデルを説明する研究が進んでいる。アプローチとしては、Deep Learningの各層がどのような入力に強く反応するかを調べる方法が有名で、Feature Visualizationに詳しい。その他の手法として、入力を変化させながらモデル出力の変化を見る方法がある。前々回紹介した「“Why Should I Trust You?”Explaining the Predictions of Any Classifier」で提案されたLIME(Local Interpretable Model-Agnostic Explanations)は、入力近傍の動きを探ることでモデルの説明を行う方法である。ブラックボックスなモデルであっても、妥当な動きが見られれば信頼できる、少なくとも、信頼を得る材料にはなるという考え方である。

LIMEを試してみた

LIMEを行うソフトウェアは

pip install lime

でインストールできる。LIMEはモデル構築手法を選ばず適用できるが、scikit-learnやkerasを使っていると利用しやすい。植物の病気診断サイトはkerasを用いたモデル構築を行っており、limeのチュートリアルに沿って診断根拠を把握することができる。
下の画像は典型的な黒星病の葉であり、植物の病気診断サイトでは99%の確率で黒星病であると判定される。

これは正しい判断であるのだが、正しく画像を判定して黒星病と診断しているのか、たまたま黒星病と判定しているのか、何らかのリーク情報を拾っているのかはパッと見はわからない。LIMEを利用すると、AIがどこに反応しているかある程度把握できる。LIMEを利用した結果は下記のようなものとなる。(画像の大きさはモデルの前提にあわせて変更している。)

上の画像では黒星病と判定するにあたって注目した部分を黄色で囲んでいる。画像中、左部分と中央部分は黒星病診断で重要となる黒の斑点を診断根拠して提示しており、納得感がある。一方で右上のバラのトゲ部分を診断根拠している点には違和感がある。これは「黒星病の写真にトゲが写っている画像が多く、診断にあたりトゲに注目するモデルができている」「黒星病を(トゲがある)バラ特有の病気だと認識した」などと解釈できる。LIMEの結果は人が解釈する必要があり、それにはドメイン知識とモデル(データセット含む)の知識が必要となる。本件ではデータセットのほとんどがバラの写真であることから、前者の疑いが強い。

上記は「画像は健康な葉か?」を診断した結果であり、緑の部分は「この葉が健康であると診断する場合、ポジティブな要素として用いる部分」、赤の部分は「この葉が健康であると診断する場合、ネガティブな要素として用いる部分」を示す。画像上部の緑一色の部分が「健康そう」とした根拠、黒星病の特徴である黒の斑点が「健康でなさそう」という判断根拠とされている。この点は納得感があるが、地面部分も「健康でなさそう」という判断根拠とされていて、違和感がある。「地面の画像とともに健康な葉が提示されている画像が少なく、黒の斑点以外に注目してしまう」「茶色の地面を”枯れている”と誤認識した」などの理由が考えられる。
LIMEを利用することで、AIがどのように診断しているかをある程度可視化することができ、納得感が無い場合はどのように修正するかを判断できる。本件ではおそらくデータセットに問題がある。一応気をつかって撮影したはずのデータセットを用いていても、このような問題を内包している。きちんとしたAI構築は簡単ではない。(コードを書いて実行するだけなら簡単だけど・・・。)

XAIの重要性

説明可能なAIをXAI(Explainable Artificial Intelligence)と呼ぶ。前述のLIMEはXAIを実現するための1手法としても位置づけられる(完璧とは言いがたいが)。XAIは、AIが実務で使用されるにつれ重要となっていくテクノロジーであり、私は2つの側面があると考えている。

  1. モデル構築者の不安を解消するテクノロジー
  2. 社会にAIが受け入れられるためのテクノロジー

1.の観点は前述の通りで、ある程度説明性がないと、構築したAIが現実でうまく動くのか不安で仕方ない私のような人を手助けするモノである。(が、この点を重視する人はほぼいない)
2.の観点は重要である(というか本来的な意味はこっちの方である)。これに関連し、モデルの判断について「説明を受ける権利(right to explanation)」があるとする考え方もあり、GDPR2018でも話題になった。GDPRにおいて「説明を受ける権利」が存在しているかは議論がある(左記が整理された論文その日本語の解説)が、この手の権利が今後重視されることは間違いない。

公平性、FADM(Fairness Aware Data Mining)

公平性の観点からも判断理由の説明は重要である。例えば、「この家を買うと、収入に比べて、借入額が多すぎます。そのため、あなたにはお金を貸しません。」という判断には納得感がある。ある意味、相手のことを思い「無理な返済計画の後、破産しないよう」判断しているとも言える。一方で「あなたの名前は怪しいので、お金を貸しません。」という判断には納得できないだろう。不利に判断される名前が、ある地域に特有のものであれば、差別に繋がる判断として大問題となる可能性すらある。
Deep Learningだ、AIだ、人工知能だ、とテクノロジーを使って何らかの判断をするのは良いのだが、データセットや手法に依存して、差別的なモデルが作成される可能性がある。このようなモデルが運用されると、差別を助長する方向で判断がなされ、その拡大につながりかねない。クロスバリデーションで確認した、統計分析した、など理由があっても、現実世界で「差別的な判断」は受け入れられないだろう。
前述のお金を貸す例でいうと、差別は下記のように広がる。

  1. 特定の名前の人(複数)がお金を返さなかったデータが存在する状況下で
  2. 何も考えずに、名前も判断材料とする「AI」を作り、運用すると
  3. 「AI」は特定の名前の人に不利な結果を返すため、その名前の人に提示される金利は上がり
  4. 特定の名前の人の破産率は上がって、1.に戻る

名前には地域や生まれ年(=年齢)が反映されており年収と関連する。「名前」を入れることで精度が上がる「AI」は作成可能だが(現時点でも)実務屋としては「これはダメです」と言わないといけないんだろーなーと思っている。書いていても思うが、実際の関連性も怪しいし。
現時点では微妙としても、GDPRのような規制が進んでいくと、差別的な判断が法的・社会的に問題となるだろう。現在、持てるデータをすべてつっこみ作られた作成者すら何が起きているかよくわからない「AI」が増えている。知らず知らずのうちに差別的な「AI」を運用し、その結果大炎上する可能性は高い。公平性・説明可能性は今後重要性を増していく。
公平性はFADM(Fairness Aware Data Mining)といったキーワードで研究が進んでいるが決定打となるテクノロジーは存在しない。いくつかの手法が提案されているが、差別の定義が難しかったり、計算コストが高かったりと運用が難しい。一方で、今でも(人間の判断でも)差別が行われている可能性はある。差別とは何か?が定式化され、数学的に差別がないと保証された方法ができれば、世の中が良くなるかもしれない。人工知能ブームでいろんな議論が盛り上がっているし、企業によってはお金もあるしで、この手の研究が進めばよいなーと思う。(結局、結論は前回と同じ)

WEBアプリ構築(keras+uwsgi+bottle)編+まとめ&AI構築の悩み(3/3)

前回、前々回から引き続き、植物の写真から病気を判別するサイト(http://www.plant-check.jp/)を作ったときのまとめ。今回はWEBサイトを構築したときのまとめ。

WEBサイトの概要

リンクにあるとおり、WEBサイトはシンプルな作りとなっている。大きなユースケースは下記の2つ。そしてやることはほとんど同じ。

  1. ユーザがサイトの「写真を撮影」ボタンを押すと、自分のスマホから写真を撮ることが出来る。次に「病気をチェック」ボタンを押すと、取った写真の植物が病気か判定される。
  2. ユーザがサイトの「写真を選択」ボタンを押すと、自分のPC/スマホから写真を選択することが出来る。次に「病気をチェック」ボタンを押すと、選んだ写真の植物が病気か判定される。

HTML部分

スマホ経由で写真を取らせるにはcapture=”camera”を使えばOK。

 <input type="file" accept="image/*" capture="camera" id="camera" style="display:none;" name="upload" />

それ以外の部分として、labelタグを使ってボタンを隠したり、若干JavaScriptでボタンの活性・非活性を切り替えたりしているが特殊なことはやっていない。

サーバ部分

サーバ部分の構成は次の通りで、こちらも特殊な構成ではない。

  • sakuraのVPS(ubuntu 16.04 LTS)
  • Docker
  • nginx
  • uwsgi
  • Pythonのアプリ
    • bottleを利用してモデル部分(keras + tensorflow)とWEBアプリ部分をつなげた。

uwsgiとnginxのつなぎはSocketを使用した。(nginx側 uwsgi_pass unix:/path_to/uwsgi.sock、uwsgi側 socket = /path_to/uwsgi.sock )良くわからない場合は、公式サイトのサンプルを見ながら書くのが一番だった記憶がある。
Pythonのアプリ部分はbottleを用いて書いた。毎回毎回モデルをロードするアプローチはさすがに富豪過ぎるので、起動時に判別モデル(植物か否か、病気か否か)をロードしてそれを使いまわすようにしている。
一点はまった点としてuwsgi.confでthreads = 1、enable-threads = falseとしないと動作しなかった。当時forumを確認した感じではkerasのpredict処理がマルチスレッドに対応していないのが原因だったと記憶している(が、モデル読み込み時にフリーズしたような記憶もある)。それと、bottleの制約のようだが、巨大ファイルをアップロードされた場合の対策(chunkごとに読みこんで、一定以上のサイズの場合は処理を停止)を自分で書かないといけないのが面倒だった。

まとめ

モデル構築部分のコード行数は約100行(×2)、サーバ部分のコード行数は約200行だった。「AI(人工知能)が病気を診断!」というサイトがこの程度の行数で書けてしまうのは、便利なライブラリが整備されたおかげで、作者に感謝である。もっとも、モデル構築部分はノウハウ含めて自動化されていくはずで、大手各社もAutoML、Azure Machine Learning、・・・と言った名前でそのような環境をリリースしている。
AIやら人工知能やら何やらの主戦場は、結局何するの?という方向か、ほんまに使えるの?という方向になる気がしていて、クロスバリデーションベースのモデル精度を競っても無意味な時代になりつつあるんだろうなーと思う。(ということで私は自動化大歓迎、その他の思いはその他へ)
今後、情熱が復活すれば他の病気への対応を行う予定。もう少し実験したいことがあるので、コードを公開するのはその後になる見込み。
Read more »

モデル構築(keras/tensorflow+InceptionV3+Data augmentation)編(2/3)

前回から引き続き、植物の写真から病気を判別するサイト(http://www.plant-check.jp/)を作ったときのまとめ。

モデル構築の流れ

前回書いたとおり、今回、(1)植物の葉かそれ以外かを判別する2値分類モデル+(2)植物の葉が病気か否かを判別する多値分類モデルを作成した。構築方法は(1)、(2)ともに同様でkeras, tensorflowを用いて転移学習を行った。モデル構築の流れは下記の通り。バリバリのDeep Learningなので、人工知能(AI)を利用し、植物の病気判定を行った!と言っていいはず(大事なことなので2回目)。

  1. 写真をラベルごと((1)は「植物の葉/それ以外」、(2)は「健康な葉/黒星病/うどん粉病/その他カビ系の病気」)ごとに別のディレクトリに格納する。
  2. kerasを使ってImageNetを学習したInception V3をロードする。
  3. ロードしたモデルの一部(今回は250層以降)を学習可能に設定する。
  4. 問題(2値 or 多値)に応じて、Inecption V3の後段のネットワークを設定する。
  5. 写真データを学習用と検証に分ける。
  6. 写真データをdata augmentationするよう設定する。
  7. 学習、検証する。

モデル構築のコード

上記1.~7.のフローはkeras (+ tensorflow)を用いると簡単に実装できる。2値分類モデルにおける、2.~4.は下記のように実装可能。多値の場合は最終層を「predictions = Dense(クラス数, activation=”softmax”)(x)」てな感じに変えて「loss = “categorical_crossentropy”」とすればよい。ざっくりいうとニューラルネットワークの前段として学習済みのネットワークを用い特徴量抽出等を再利用(=転移学習)し、本件で必要な分類を行うネットワークを追加している。

base_model = InceptionV3(weights='imagenet', include_top=False)
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation="relu")(x)
x = Dropout(0.5)(x)
x = Dense(256, activation="relu")(x)
predictions = Dense(1, activation="sigmoid")(x)
model = Model(inputs=base_model.input, outputs=predictions)
for layer in model.layers[:249]:
   layer.trainable = False
for layer in model.layers[249:]:
   layer.trainable = True
model.compile(loss = "binary_crossentropy", optimizer = optimizers.SGD(lr=0.0001, momentum=0.9), metrics=["accuracy"])

Data augmentationは画像を変形(回転、移動、縮小、拡大などなど)させながらデータを増やして学習する方法である。画像を変形させることで、1つの画像から複数のパターンを生み出す。日本語だとデータ拡張とか呼ばれている(はず)。写真の撮られ方に依存する差異等が吸収できるので、未知データに対する性能の向上に効果がある(と私は思っている)。モデル適用時にも変形させながら何パターンか適用し、その平均を取ると性能向上効果がある(こともある)が、こっちをデータ拡張と言うかはよくわからない。
kerasだと「ImageDataGenerator」を使って簡単に書ける。多値の場合は「class_mode = “categorical”」に変更すればよい。学習データと検証データのsplitを事前に行っていれば、同じようにtest_generatorをかける。

train_datagen = ImageDataGenerator(
    rescale = 1./255,
    horizontal_flip = True,
    fill_mode = "nearest",
    zoom_range = 0.3,
    width_shift_range = 0.3,
    height_shift_range=0.3,
    rotation_range=90)
train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size = (img_height, img_width),
    batch_size = batch_size,
    class_mode = "binary")

学習は下記のように行えばよく、チェックポイントごとにモデルが保存され、精度に応じて自動でストップされる。nvidia-dockerのコンテナでGPU版のtensorflowを入れていれば、GPUを用いた学習が行われる。とても便利。

checkpoint = ModelCheckpoint("/保存用ディレクトリ/モデル名_{epoch:02d}.h5", monitor='val_acc', verbose=1, save_best_only=True, save_weights_only=False, mode='auto', period=1)
early = EarlyStopping(monitor='val_acc', min_delta=0, patience=10, verbose=1, mode='auto')
model.fit_generator(
    train_generator,
    samples_per_epoch = nb_train_samples,
    epochs = epochs,
    validation_data = validation_generator,
    nb_val_samples = nb_validation_samples,
    callbacks = [checkpoint, early])

今まで紹介したコードは、だいたいkerasのsampleコードをベースにしている。自分でやってみたい方はkerasのチュートリアル(https://keras.io/ja/内のリンクから飛べる)を読むのがお勧めである。

モデル構築のポイント

コード自体は簡単に書け、実行してみると検証データでの精度も良いと見える結果が得られる。が、実際に重要なのは「未知データに対する予測性能」で、思ったとおりの結果にならないことがある。これは学習・検証データの関連が強すぎるから(=独立じゃないから)で、学習結果を評価する上で重要なポイントとなる。この手の問題への対応はとっても難しい。私は人工知能やらAIやらと呼ばれるモノの中には、正しく評価されていない、過大評価なヤツも多いと思っている。
Deep Learningを使った場合(特に本件のような非常に複雑なネットワークを組んでいる場合)、「黒星病の特徴である黒の斑点を見て、黒星病と判断している」など「AIの判定に納得感があるか」はわかりにくい。検証すると、「AIはバラが植わっている鉢の色に注目して病気だと判別する」場合もある(詳しくは後述*1)。
このような動きはモデルの説明可能性の文脈でよく話題になっていて、たとえばKDD 2016の「“Why Should I Trust You?”Explaining the Predictions of Any Classifier」に詳しい。論文中の対応案は、まずまず良く動くが、速度面など使い勝手はイマイチという印象を受けた。説明可能性は重要な分野だが、現時点で決定打となる対応策は存在しない。
本件では写真を撮ったのが自分自身ということもあり、背景や鉢が注目点とならないよう気を使っている。具体的には病気の葉と健康な葉それぞれを同じ木・背景で撮影する、様々なパターンを混ぜるなど、変な場所に注目されないようにデータを作成している。
モデルの学習時には完全に未知のデータで検証がされるようにし、また、手動でAIが間違いやすいパターンの解析・チェックを行っている。割と丁寧に判別モデルを作っているが、それでも、「未知データに対する判別能力」は「検証結果として数学的に求められた能力」ほど高くはないんだろうなーと思っている。
Read more »