サービスにAIをフル活用するためにやったこと

Joonsik Baek氏(以下、Joonsik):みなさんこんにちは。私はJoonsikと言います。LINEのMediaPlatformチームから来ました。ここにはたくさんの開発者の方がいらっしゃいますが、みなさん今までの中で、最新のディープラーニングテクノロジーをサービスで使ったことのある方はいらっしゃいますか? もしそうなら、ディープラーニングを実際にサービスで使うのは簡単でしたか?

おそらく簡単ではなかったと思います。今日はLINEがどのようにしてVisionディープラーニングテクノロジーをさまざまなサービスに入れているかということをお話ししたいと思います。

みなさん、LINEのOCRサービスは利用したことがありますか? 画像から文章等を抽出して、翻訳までしてくれます。これは画像を撮影して使うことができます。皆さんのアルバムの写真からも利用することができます。

ここでひとつ疑問が生まれます。「なぜこんなことができるのか?」ですね。これは「PicCell」のおかげなのです。

画像をPicCellに送れば、PicCellがこの画像からすべてのテキストを抽出してくれます。

今日はLINEのVisionディープラーニングのプラットフォーム、PicCellについてお話しします。なぜ、そして、どのようにしてPicCellを作ったかということです。また、おもしろい事例集もあります。最後にはまとめで、今日のプレゼンテーション、私たちのロードマップをお見せして終わりたいと思います。

PicCellを開発した理由

LINEは、世界中で本当によく使われているサービスで、さまざまなファミリーサービスを持っています。

すばらしいプロダクトではありますが、やはり課題もあります。そんな課題を、ディープラーニングのテクノロジーを用いて解決しようと考えています。

ご存知のように、ディープラーニングのエンジニアを見つけるのは非常に難しいですし、ディープラーニングは非常にコストが掛かります。そして私たちが自身のディープラーニングのテクノロジーを開発したとしても、コストが掛かりすぎてそこから恩恵を得るのは非常に難しいです。

また、その他の課題もあります。それはサービスの中で重複する機能がたくさんあるということです。そこで我々は、すべてのサービスのニーズを調査して共通のニーズを把握し、そのニーズにあったディープラーニングサービスを提供できたら、すばらしいのではないかと考えました。

すべてのリソースを集約できることによって、コストを削減するため、こんな結論に至りました。「プラットフォームを作ろう」と。そして、それによってさまざまなサービスで共通に必要なディープラーニング機能を提供できるんじゃないかと思ったわけです。ということで、我々は「PicCell」を開発しました。

PicCellをMediaPlatformチームが開発したわけ

PicCellは、共通のディープラーニング機能に対するプラットフォームです。名前から分かるように、PicCellはVisionのディープラーニングの機能だけを取り扱っています。Vision領域以外は個々のサービスに特化したニーズが多すぎるので、PicCellではVision領域に注力することにしました。今のところ、LINE本体を含めた40以上のLINEのファミリーサービスがPicCellを使用しています。

では、PicCellは一体誰が開発を行うのか? すべてのサービス開発者はサービスの開発で非常に忙しいわけであります。ですので、プラットフォーム専門の開発チームを作りました。我々MediaPlatformチームが、PicCellの開発を行っています。

メディアプラットフォームは、LINEのサービス内に存在するすべてのメディアファイルを取り扱っており、80以上のLINEファミリーサービスがこのプラットフォームを利用しています。

メディアプラットフォームはOBS(Object Storage)上で実行されています。OBSというのはLINEが作られた頃から使われている巨大メディアプラットフォームです。OBSはすべての画像、動画、音声など、LINEのサービスで使用されるあらゆるファイルはここで処理されます。

OBSは、LINEサービスのすべてのファイルを処理しているため、トラフィックのピークタイムは1.5Tbpsになります。そして、全ストレージのボリュームを合わせると100PBになります。つまり、OBSはVisionディープラーニングのすべてをターゲットに持っているということです。

メディアのプラットフォームとPicCellのプラットチームは親和性があります。PicCellはメディアを理解するためのものであるため、メディアプラットフォームを持っているエキスパートである私たちが作るべきだと考えました。

そんな経緯で、我々がPicCellを開発することになりました。

アダルトコンテンツを検出する

開発をはじめてまず考えたのは、第一優先は何かということです。もっとも共通していて、優先度の高いニーズに注力しようと考えました。そこでわかったことは、アダルトコンテンツの検出がもっとも近々の課題で、ニーズが高いことが判明しました。

アダルトコンテンツは、LINEユーザの体験を台無しにするものの中でも非常に大きな要因だったため、これを制限したいと考えました。多くのサービスはこれを何とか制限したいと考えていました。

アダルトコンテンツのフィルターを作るために、LINE ChinaのAIチームが参加してくれました。彼らはこのプロジェクトをResNet50を基にして開発し始めました。このモデルは画像を3つのグループにクラス分けします。例えばこれはアダルトなのか、セクシーなのか、ノーマルなのかということです。これは性的描写のレベルによって分けます。そして350万の学習サンプルを使い、100万のテストセットを用いてモデルを評価しました。

このクオリティは非常に良くて、0.9以上のF1 Scoreを得ました。F1 Scoreというのは、モデルの品質のメトリックでありまして、みなさんに使っていただけるレベルの品質であるということです。また、モデルのチューニングを続けて、すばらしいパフォーマンスが出るようになり、処理時間は300ミリ秒以下になりました。

パフォーマンスと品質が非常に良かったのでサービスインしまして、最終的にこれをアダルトコンテンツのフィルターとしてLINEサービスに適用しました。そして我々は、アダルトコンテンツをフィルターし、ブロックできるようになりました。

しかし、まだ問題はありました。クオリティは問題なかったのですが、より多くのサービスでこれを使うには、リクエストのピークタイムを扱うのは難しいということがわかりました。ということで、何かしないといけないと思ったわけです。

膨大なリクエストをハンドリングするためにやったこと

それでは、この大量のリクエストをハンドリングするために行ったアプローチについてお話しします。最初にKafkaを中に入れました。

これはピーク時にスロットルの役割をします。そして私たちは新しいゲートウェイを作りました。これは同期・非同期のAPIを提供しています。ゲートウェイは入ってくるイメージすべてをKafkaに書き込みます。そして同期のリクエスト、非同期のリクエストが、そのトピックについて書き込まれます。

それから我々は「Pacman」を開発しました。

これはKafkaのリクエストをプロセス処理するためです。Pacmanは優先キューを持っていますので、同期リクエストの処理を最初に取り扱うことができます。そしてこの同期APIは、サービスだけに使うことにしました。これはリアルタイムの処理だからです。

同期のリクエスト処理は、リソースがちゃんとあるときには同期のリアルタイムプロセッシングを行うので、ある時間内で処理できるようになったわけです。

しかしながら非同期のリクエストは、やはりコールバックをサービスに戻す必要があります。コールバックをサービスに戻すとき、いくつかのコールバックのメッセージがなくなっていることがわかりました。

もしかしたらネットワークの問題なのかもしれませんし、サービスサーバのデプロイメントの問題なのか、他の問題が原因なのかもしれません。そしてなくなっているコールバックは、想定外の問題をサービスにもたらします。

そこで、このコールバックが送られていることを担保する必要があります。ということで、我々はdead-letter queueをKafkaで作りました。このdead-letter queueのメカニズムは非常にシンプルです。

パブリッシャーがメッセージをメッセージキューにプッシュします。そしてコンシューマがこれを消費してプロセス処理します。コンシューマが成功時にこのメッセージをプロセスできれば、コンシューマがこの通知をメッセージキューに送ります。

もしコンシューマがこのメッセージの処理に失敗したら、コンシューマはAck通知の代わりにNackを送ります。そして落ちてしまったメッセージが自動的にdead-letter queueに入ります。TTLが失効すると、またメッセージがメッセージキューに入ってきます。そしてコンシューマが、それをまた処理します。

我々はKafkaのdead-letter queueと「Spiderman」をPicCellに入れました。

Spidermanは、コールバック保証のために開発されました。Spidermanがコンシューマとしてコールバックが成功するまで送ります。Spidermanという名前の由来は、蜘蛛の巣のようにコールバックを絶対に漏らさないからです。

我々はPicCellをこのようなかたちで安定化させてきました。しかしながら改善の余地はまだあります。

GPUのリソースを削減する

もう1つの問題は同じ画像を重複して受け取ることがあることです。ユーザが好きな写真をシェアしているのかもしれません。

もちろん我々はこれらを処理してアダルトコンテンツかどうか判別する必要があるのですが、それにはGPUのリソースが必要です。ですが、GPUサーバは非常に高価で、普通のサーバと比べて高く付きます。

そして、重複処理はGPUリソースの無駄遣いでもあり、またお金の無駄遣いでもあるのです。なので我々は、RedisをPicCellに入れて結果をキャッシュするようにしました。

結果はPacmanからやってきますので、これをRedisに書きます。そしてゲートウェイとSpidermanが、それをクライアントにデリバリーします。

ゲートウェイがリクエストを受け取ると、毎回Redisの中のキャッシュの結果を検索します。Redisになければ処理をします。

もしRedisの中にすでにキャッシュがあれば、ゲートウェイはキャッシュされた結果を再利用できます。このようにして我々がGPUのリソースをセーブしました。

動画のアダルトコンテンツを検出する

こうして悪意のある画像をクリーンアップできるようになり、しばらくはうまくいっていました。ですがLINEはビデオサービスにもフォーカスをしていますので、多くのユーザがビデオもシェアしています。そしてアダルトコンテンツとしては、画像よりも動画がインパクトが強いです。

では、どうするべきなのか?

我々は新しいディープラーニングの機能でビデオフィルタリングを作るのか。でも既に多くのリソースをアダルトイメージのフィルタリングの開発に使っていますので、シンプルなアプローチを適用したいと思いました。

ビデオの構成を見ると、これは要するに写真がグループ化されたものではないかと思いました。

そこで、ある間隔でフレームのサンプルが取れるのではないかと考え、これをjpegにコンバートすればいいのだと思いつきました。

つまり、ビデオは画像のグループであると考えたのです。ということで、アダルト画像のフィルターをビデオにも適用することにしました。

ある画像のプロセスのあとで動画の結果を集約し、結果を推測できるので簡単です。

ということで、「Timberman」を開発しました。

Timbermanは、ビデオからスナップショットを抽出して、jpegに変換します。Timbermanのおかげで、PicCellの中のすべてのプロセスが非常にシンプルになりました。すべてのコンポーネントはイメージのフィルタリングプロセスに注視できますので、すべてのスナップショットの結果をPacmanが集約できます。

最終的に、我々はすべてのイメージやビデオをPicCellで処理することができるようになりました。この結果には非常に満足していたのですが、続けて別の問題が起こりました。