てくすた

ピクスタ株式会社のエンジニア・デザイナーがつづるよもやまテクニカルブログです

機械学習の精度向上と高速化について

エンジニアの id:necojackarc です。

ここ数ヶ月、長年貼られたガムテープを剥がして綺麗に貼り直すような仕事をしています。

本エントリではピクスタと機械学習についてで軽く触れた、私が今年の春頃に取り組んでいた機械学習を使ったタグ翻訳の精度向上と高速化についてご紹介します。

texta.pixta.jp

翻訳精度向上

翻訳精度*1向上のアプローチとして、まずは翻訳精度が低い原因を特定する必要があります。

調査の結果、学習データの問題、より具体的に言うと、学習データの多様性の低さが翻訳精度を低下させている原因のひとつでした。

データの多様性の低さが翻訳精度を低下させる理由を以前のエントリでも取り上げた「タイ」という言葉を例にして考えてみます。

とある画像についた「タイ」を翻訳するとき、その画像に付いている他のタグが重要になります。画像に「海」や「日本食」などがついていれば、なんとなくこの「タイ」は “Sea bream” に翻訳されると良さそうな気がしますよね。

もしこの時、「日本食」というタグがついた画像について分類器が未学習だった場合、「海」という言葉に分類結果が引っ張られることになります。

極端な例ですが、もし「タイ」と「海」がついてる Thailand の画像しか学習しておらず、「日本食」というタグが付いた画像に関して未学習の場合、先ほどの画像は「海」というタグに引っ張られ “Thailand” へと翻訳されることになります。

ピクスタでは1000万を超える画像があり、それぞれにクリエイターが思い思いのタグをつけています。そのため、画像とタグ (テキスト分類で考えるとテキストの数とそのボキャブラリ) がかなりの数になっており、学習データ選定の重要性が非常に高くなっています。

そこで、学習データの多様性を向上させることで、翻訳精度を高められるのではないかと考えました。

学習データの多様性向上

データ量不足については、クラウドソーシングで既に解消の目処が立っていた*2ため、ここで注目すべきは「いかに少ない学習データで高い学習効果を得るか」という問題でした。

ここでは、タグ翻訳に使用できる予算から「最大どれくらい学習データを集めることができるか」という見積もりを行い、各検証で使用する学習データ量を固定し、学習データの選択による精度の変化のみを調査しました。

また、学習データの選択については、どのような抽出方法が現実的な計算量で高い多様性を得られるかという観点でいくつか試してみました。

最終的にどのように学習データを抽出したかを簡単にご紹介すると、まずは母集団の中からある一定の大きさを持った部分集合を作るということをしました。

ここでは、完全にランダムで抽出する、検索結果の上位画像を使う、画像についてるタグの数を考慮するなど、いくつかの方法を試しました。

そして、その部分集合の中から、できるだけボキャブラリが大きくなる組み合わせを抽出し、それを学習データとしました。

ただし、ボキャブラリが最大になる組み合わせを求めるのは計算量が大きすぎるので、ヒューリスティックなアルゴリズムで部分集合からの絞り込みを行いました。

これらを実践し学習データの多様性を増やしたところ、適合率が数10ポイント上昇しました。

このように、機械学習の手法に手を入れることなく、学習データの収集を工夫するという方法で、大幅な翻訳精度向上を達成できました。

翻訳高速化

ピクスタ内のとあるバックエンドシステムにおいて、タグ翻訳が処理時間の大半を占めている処理がありました。

さらに悪いことに、この処理が社内業務上のボトルネックにもなっていました。

翻訳のボトルネック調査

ボトルネックを調査したところ、学習データを取得するための RDB (MySQL) へのアクセスが原因であることがわかりました。

ここまでは予想通りだったのですが、コードを追ってみたところ、既にかなりのチューニングが施してあり、正直目標数値(2秒かかってたところを0.2秒)をクリアするのは難しいと感じました。

より詳細に調べてみたところ、そもそもこのデータを RDS のデータ構造で保持する必要がないということが判明しました。

そこで、Key-Value ストア型の NoSQL を導入することで、大規模データを高速に扱うという、RDS が苦手とする部分(RDS には高度なトランザクション制御が必要なため、一般的に並列データアクセスが難しい)を補うことにしました

学習データは今後も増え続ける予定でしたので、NoSQL の導入は効果的だと考えました。

具体的には、これまで使っていた MySQL の代わりに DynamoDB を使用することにしました。

DynamoDB

DynamoDB は Key-Value ストア型の NoSQL で、AWS のサービスのひとつです。

Amazon DynamoDB は、1 桁台のミリ秒単位のレイテンシーを必要とするすべての規模のアプリケーションに対応した高速かつフレキシブルな NoSQL データベースサービスです。完全マネージド型のクラウドデータベースで、ドキュメントとキー値のストアモデルの両方をサポートしています

Amazon DynamoDB (フルマネージドNo SQLデータベースサービス) | アマゾン ウェブ サービス(AWS 日本語)

こちらを採用した理由として、

  • フルマネージドでスケールも楽ちん(お金を払えばスループットが増える)
  • ピクスタ内で既に使用しており運用実績と知見がある

などがあります。

DynamoDB に関しては、下記のスライドがわかりやすくて良いです。

RDS から逐次的に読み出していた処理を、DynamoDB のデータを一括でメモリ上にキャッシュし、メモリ上のデータを用いて計算を行う、という方法へと変更することにしました。

並列並行プログラミング

DynamoDB の導入により、当初2秒程度かかっていた処理を0.4秒程度まで短縮することができましたが、目標値である0.2秒までは持っていくことはできませんでした。

そこで、DynamoDB への問い合わせをマルチスレッドで実装することにしました。

具体的にどのように実装してみたかは、Qiita へDynamoDBから大量レコードを並列に取得する方法 としてプロトタイピング時に書いたコードの一部を公開しています。

また、Ruby での並列並行プログラミング (プロセス・スレッド)については以下の記事が勉強になりました。

www.toptal.com

IO のマルチスレッド化だけでは、目標を達成できていなかったので、更にマルチプロセスも導入したりもしてみましたが、これはプロセスフォークのコストなどが原因で、思うような成果がでなかったため、導入を見送りました。

結果、並列並行プログラミングを用いたことで、0.25秒程度まで短縮することができました。

分散システム化

単一マシンでの処理に限界を感じたので、分散システム化をしてみることにしました。

翻訳システムへ渡すタスクを各マシンが参照できるキュー上に格納しておけば、容易に分散システム化可能ということをこれまでの作業から想像できました。

それをやるのにうってつけの SQS というサービスをピクスタでは既に使用していました。

Amazon Simple Queue Service(SQS)は、高速で、信頼性が高く、スケーラビリティに優れ、十分に管理されたメッセージキューサービスです。SQS を利用すると、簡単かつコスト効率良く、クラウドアプリケーションのコンポーネントを切り離すことができます。

Amazon Simple Queue Service(メッセージキューサービス : Amazon SQS) | アマゾン ウェブ サービス(AWS 日本語)

また、タグ翻訳の最適化を進めていくうちに、タグ関連部分をマイクロサービスとして切り出すことが可能だとわかってきました。

マイクロサービス化

マイクロサービス化について、他のエンジニアや、技術コンサルタントとしてピクスタをサポートしていただいている和田卓人 (id:t-wada) さんと話をしてみたところ、実現可能かつメリットもあるという結論になりました。

さらにこのとき、ピクスタではベトナムでラボ型オフショア開発を始めることが決定していました。

texta.pixta.jp

こうして、ベトナムオフショア開発第一弾として、タグ関連のマイクロサービスの開発が決定しました!

実はピクスタでは既にマイクロサービス化へ取り組んでおり、いくつか既にマイクロサービスとして稼働しているものが存在します。

これについてもまた、エンジニアブログでご紹介したいと思います。

まとめ

今回は機械学習の精度向上と高速化という2つの課題にどのようにアプローチしたのかについてご紹介しました。

精度向上については、

  1. 精度向上部分は学習データの多様性が問題となっていた
  2. 学習データに多様性を加える工夫をした

高速化については、

  1. データアクセス部分が最大のボトルネックとなっていた
  2. RDB から NoSQL へデータを移行しデータアクセスの高速化を行った
  3. 更にデータアクセスを高速化をするために、並列並行プログラミングを行った
  4. スケールアウト可能な分散システムとして再設計を行った

ということを行いました。

また、学習データの多様性向上の節の注釈でもれましたが、学習データ収集のスケール化にも挑戦しました。

学習データ収集のプロセス自体にあった問題を解決するために、どのようなアプローチをとったかを次回紹介したいと思います。

そしてもちろん、ピクスタでは「機械学習・データ分析」エンジニアも募集しております。

画像の自動分流およびタグの自動設定など、挑戦できるテーマは非常に豊富

ピクスタと機械学習について

テーマは非常に豊富かつ、まだ手をつけていない部分も沢山残っています。「我こそは開拓せむ!」という精神を持ったエンジニアをお待ちしております!

ピクスタでは各メンバーのは裁量が大きく、自分がやりたいと思った仕事に論理的根拠があり、かつそれをきちんと説明できるのであれば、ほぼ何でも挑戦することができるという魅力があります。

「機械学習という武器を自由にぶん回したい!」という方にはピッタリの環境だと思いますので、興味のある方は是非ご応募ください。

最後までお読みいただき、ありがとうございました。

recruit.pixta.co.jp

*1:精度という曖昧な言葉を使っていますが、今回向上させたかったものは「適合率 (precision)」であったため、適合率をメインの指標として扱いました。精度と言っている理由は、この文脈では一般的な「翻訳精度」という意味を持たせているためです。

*2:学習データ収集のスケール化として、後日投稿予定です