Machine Learningチームのミッション

菊地悠氏:Machine Learning1チームの菊地と申します。よろしくお願いします。今日の内容は以下のような順で話をしていきたいと思います。

まず最初にミッションです。多種多様なサービスがあるので、機械学習を適用する領域はいろいろあります。そういう中で、我々のチームは各事業組織から独立しています。LINEのさまざまなサービスに対して機械学習を通した競争力や利益というかたちで貢献するというのがミッションの1つになっています。

加えて、たくさんのサービスがあると共通して使えるコンポーネントが出てきたり、あるサービスで提供した機能を少しいじると別のサービスに使えるというような、民主化や標準化のようなアクティビティが重要になってきます。DSEセンターという組織自体がこういうことをミッションの1つとしているので、機械学習という観点で我々もそこに貢献するということをやっています。

LINEスタンプのレコメンド事例

では次に、先ほどのミッションがどういうプロジェクトやシステム、ツールに具体化されていくのかを紹介させていただきます。

最初の例は、LINEスタンプのレコメンドです。いわゆるUser2ItemとかItem2Itemと言われるようなレコメンデーションをサービス側に提供しています。

LINEスタンプいろいろな国でサービスをしているので、複数の国向けにグローバルに提供しています。実際のユーザよりかなり多いユーザ数分のレコメンドを生成していて、おおよそ数億ユーザに対して数百万のアイテムの中からレコメンデーションするというかなり規模が大きなものになっており、我々のチームで開発と保守運用をしています。

LINE社全体ではいろいろなサービスがあるので、それぞれに対してレコメンデーションを提供するという話が出てくるんですが、我々のチームで過去に開発したことがあるサービスの一覧をお見せすると、こんな感じになります。共通して使えるソフトウェアモジュールは共通化するというアクティビティも行っています。

引き続き、スタンプの事例をご紹介します。LINEで文字を入力していると、スタンプがサジェストされるオートサジェストという機能があるんですが、これは一部のスタンプのクリエイターさんが意味的なタグ情報をラベル付けしてくれた正解データをもとに、今度はスタンプの画像を入力にして、タグが付与されていないスタンプ画像に、深層学習でタグを推定して付けてあげるというものになります。

また、上記と同じようなデータを扱って、今度は見た目が似ているスタンプや意味的に似ているスタンプを探せるという機能も作っていたりします。

スマートチャンネルでの2種類のレイヤーのレコメンデーション

先のプレゼンでも、これまでスマートチャンネルの紹介がいくつかありました。我々のところでは、2種類のレイヤーでレコメンデーションを提供しています。

スマートチャンネルでは、様々なサービスからコンテンツが提供されますが、ここのコンテンツは誰に出せばよいかを、ルールベースであったり、機械学習を使ったレコメンドでターゲティングしています。たとえば、我々もスマートチャンネル向けのスタンプのレコメンドを作っています。

一方で、スマートチャンネル側から見た場合、システム上では同一のユーザに対して、様々なサービスからの複数のコンテンツを表示候補として持っている状態になっています。ユーザがトークリストのページを訪問した時、手持ちのコンテンツの中から、何を出してあげるとよいかという配信最適化が必要になるのですが、ここに関しても、Contextual banditsを使って、裏でリアルタイムで実行するという仕組みがあります。

ここまでご紹介してきたのは主にサービスのレイヤーの話でしたが、1つ下のレイヤーに入るといろいろなサービスで似たようなデータ構造を扱えるほうが開発効率が上がるとか、あるいはサービス横断で複数のサービスのデータを使って何かを作ることができるといった領域での共通化の話が出てきます。特徴量データに関しても、共通に扱えるような仕組みを用意する、ということもやっています。

LINEの社内には、我々以外にも機械学習ををやっている組織が存在しているので、データを加工してプライバシに配慮した上で、他組織に提供するというアクティビティもやっています。

インフラの構成

ここまではMLエンジニアの話でしたが、たくさんのサービスむけに機械学習のサービス提供するためには、当然そのためのインフラが必要になります。我々は、自分たちでも計算機クラスタを持っています。

この画面上の左から右に順番に見ていくと、例えばLINEのメッセンジャーアプリが一番左の大きな箱になっているんですが、続けて左から2番目の箱が事業別に存在しているサーバ、対向するシステムになっています。その次の3つ目の箱が、いろいろなサービスのデータを集約した社内のデータ基盤になります。下のほうのDatalake Hadoopと書いてあるところですね。

大まかには上記のような流れでデータが入ってくるんですが、このDatalake Hadoop自体は、Data Platform室というところが保守運用、開発あるいは分析用のアプリケーション機能などを提供しています。我々はそこのユーザでもあるんですが、さらにGPUを使って計算したりもしたいので、一番右側にある我々で管理しているシステムも持っています。

今ここでお見せしているのは2018年、つまり2年ぐらい前に我々が運用していたシステムで、当時はApache Mesosという計算機クラスタのオープンソースの環境を使っていました。

直近ですと、これがKubernetesで別のシステムに変わったり、Mesos上で動いていたAPIサーバなども、社内のプライベートクラウド環境がだんだん整ってきたこともあって、マネージドサービスに移行するような感覚で移植して、我々が保守運用するものを減らしていったりしています。

他にも、マシンラーニングを適用してレコメンデーションを提供していくと、その先は過去に提供したレコメンドを新しいものに改善していくというプロセスに変わるんですけど、そういった観点で自分たちが使いたいツールを作るということでA/Bテストのツールを用意しています。最初はデータ分析を行っている牟田さんのチームに使っていただくところから始まり、その後自分達でも使うようになって、いまでは利用者が増えてきたのでA/Bテストのダッシュボードもサポートして、ということもチームの中でやっていたりしています。

4つのポジションと求めるスキル・経験

以上が、だいたいチームの中でやっているアクティビティになります。

そして、ここまで紹介してきたような開発を進めていくにあたって、我々は4つのポジションを用意しています。画面中央に青色で書いてあるところにプロダクトマネージャー、プロジェクトマネージャー、サーバーサイドエンジニア、MLエンジニアの4つです。

我々はチームの中に閉じていろいろ開発するというのもあるんですが、エンジニアリング組織の中の1つなので、例えば先ほどのHadoopクラスタを管理しているData Platform室と連携したり、サービス向けに何かを作る際には、作ったものの良し悪しを判断するところをデータサイエンティストの力を借りたり、当然事業側のメンバーにも企画者と話をしたり開発者と連携したりというかたちで仕事をしていくことになります。

役割は大きく4つあって、それに応じてポジションも4つに分けてあるんですが、左から右に順に説明します。

MLエンジニアは、当然機械学習のアルゴリズムの検討や選定、実装等をやります。自分が作った仕組みに関しては、保守運用するというところも入ってきます。

サーバーサイドエンジニアは、MLエンジニアが作るマシンラーニングのアルゴリズムやエンジンを動かすためのプラットフォームだったり、あるいは何らかのAPIなどでラップしてあげてサービス側が使いやすいようにしてあげたりというような開発と保守運用をやっています。

それから、プロダクトマネージャーとプロジェクトマネージャーですが、プロダクトマネージャーは事業側に直接アプローチをする企画を立てるケースもありますし、よりエンジニアリング色が強い企画を立てたりして、作るものを決める役割です。あとは多様なサービスの開発運用が並行して進められるので、プロジェクトマネージャーも専門的な業務として別で募集をしています。

以上の4つのポジションがあるんですが、実務では当然全員がちょうどいいバランスでいつでもチームの中にいるわけでもなかったりするので、ある1名が複数のロールで業務を行うというケースもあって、このあたりは適正、経験や、本人のやる気など状況によって柔軟に進めています。

必要とされるスキルと経験は、MLエンジニアは機械学習の知識が必須で、サーバーサイドになるとコンピューターサイエンスの知識がより求められます。プロダクトマネージャーとプロジェクトマネージャーは、企画したり折衝したりというところでエンジニアの手助けができるための必要な知識、経験が求められます。

最後に、個別に紹介する時間はないんですが、チームのメンバーにどういうところにやりがいがあるかとか、どういう人が向いてると思うかというのを簡単にアンケートを取ってみたところ、こんな感じになっています。

サービスがいろいろあったり、社内で作るシステムを自分たちで提案したりコントロールしたりできるので、そういう裁量の大きさを魅力に感じるという声が比較的多いかなと思っています。

私からの発表は以上になります。ありがとうございました。

機械学習プラットフォームの概要

並川淳氏:よろしくお願いします。それでは「機械学習を用いた最新事例の紹介」というタイトルで発表させていただきます。

これまでの発表でもマシンラーニングの仕事についてはいろいろ紹介があったんですが、私たちはLINEの各種サービスでマシンラーニングの技術を用いて価値を提供すると言いますか、サービスを通してユーザに価値を提供するということを仕事にしています。

具体的には、各サービスから集まってきたユーザの行動パターンのログやいろいろなメタデータなどを1つのHadoopクラスタに集約して、そのデータをマシンラーニング専用の計算機クラスタに持ってきて学習して、またマシンラーニングの結果をサービスに返す、そういう仕事を日々しています。

その仕事の中身については、オンライン学習もあればバッチ学習もあって、画像や音声を使った学習もあれば、ユーザのログを使ったレコメンデーションの仕事などもあり、多岐に渡っています。

いくつか特徴があるんですが、典型的な壁というか大変なところで言いますと、やはりLINEのサービスはユーザ数が多いので、データ量がけっこう多いというのがあります。マシンラーニングそのものについて言うと、データ量が多いというのはアドバンテージでしかなくて基本的には楽なんですが、システムを作る観点でいうとデータ量が多いと作るのは大変になってきます。

1台のサーバーではとても計算できないような大量のデータが来るので、この手のマシンラーニングの仕事をするためには、統計や機械学習だけではなくて並列計算など一般的なエンジニアとしての知識が必要になってきて、そこが少しハードルが高いなと。例えば、機械学習についてはものすごい専門知識を持っているとか特徴量のエンジニアリングがすごく得意みたいな人にも活躍してほしいのですが、一般的なエンジニアリングスキルが必要という参入障壁があるので、僕らはそこを解決したいと思っています。

巨大なデータを扱うためのフレームワークを開発

今日お話するのは、そういう巨大なデータがあったとしても簡単にデータを扱うことができるようなフレームワークを社内で作成したので、それについてご紹介をさせていただきたいと思っています。

このフレームワークの特徴ですが、GPUクラスタの効率的な利用ですとか、あとはHadoopクラスタからのデータのロードに時間がかかると非効率なので、そういう非効率な部分がなくなるように抽象化したりしています。

ただ、そうはいっても特殊なマシンラーニングのフレームワークだと開発が難しいので、データの前処理や後処理にSparkを使いたいとか、モデルを書くためのPyTorch やTensorFlowなど、使い慣れたツールはそのまま使える。そういうコンセプトでフレームワークを開発しました。

どのようなものかを簡単に説明すると、フレームワークを使う人は、preprocess関数, main関数, postprocess関数の3つの関数を書けば、基本的には並列計算の知識がなくても巨大なデータが扱えるシステムになっています。

このフレームワークはHadoopクラスタや弊社内のS3ライクなオブジェクトストレージに対するデータアクセスと、preprocess, main, postprocessの各段階のデータの流れを抽象化しています。各段階の中での並列化はMPIで、各段階の間のデータの転送はZeroMQを使うことによって全体的に高速なフレームワークを実現しています。

我々のチームではKubernetesを使っているんですが、我々が作ったフレームワークを使うことでKubernetesの知識があまりなくても使えます。あとは先ほども言いましたが、並列計算の知識がなくても使えるというところが特徴です。

このフレームワーク自体は並列計算やKubernetesの抽象化や簡略化にフォーカスしていて、MLOps的な部分は一般的なバッチの管理システムやMLFlowなど、別のフレームワークによって行っています。

これがサンプルコードです。

このあたりはPySparkを書いたことがある人は似たようなコードを書いたことがあるかもしれません。まずpreprocess関数が何をやるかを説明すると、イテレータが引数で渡ってくるので、それを変換してイテレータとして返す処理をしています。イテレータをループして変換するコードを書けば、そのまま並列計算で動きます。

main関数のところもそうで、この例ではPyTorchとかHorovodというMPIで並列計算を使うライブラリを使った例になっていて、そういうものを使ってasyncでデータを読んできて学習するようなコードをここに書きます。ここの出力はpostprocess関数の引数に渡ってくるので、postprocess側でまた変換処理をして、最終的にはHadoopクラスタやオブジェクトストレージにデータが出力されます。この3つを書けば基本的に動きます。

これはKubernetes上でMPIを使う場合の例なんですが、呼び出しはこういうかたちです。

countでノード数を指定していて、num_preprocessorsで1ノードあたりのCPU数やGPU数を指定するんですが、こういうかたちでCPUノードやGPUノードをどう割り当てるかという部分について記述すると走ります。

フレームワークを作ってよかったこと

こういうフレームワークを使って、実際に我々がどういうシステムを作っているかを紹介したいと思います。今日ご紹介するのはGraph Neural Networkを使った事例です。

この図が何を表しているかというと、ユーザがスタンプを購入したログをグラフ構造として表しています。ユーザには年齢や性別、住んでいる所在地のメタデータが付いていて、スタンプには作者や値段のメタデータなどが付いています。そういうものをグラフ構造として表しています。このグラフ構造に対し、Graph Convolution で畳み込んで、ユーザやアイテムの埋め込みベクトルを構築し、それを使ってスタンプの推薦をしたり他のマシンラーニングの特徴量に使っています。

ユーザが数億人いてスタンプも何百万と数があるので、グラフ全体はものすごく大きくて、メモリにはなかなか乗り切らないようなサイズになっています。なので、我々はこのグラフを計算するにあたってプリプロセスの部分でサブグラフを構築して、そのグラフの近傍をサンプルにするアルゴリズムで実際に学習するメイン関数に送るというアルゴリズムで実装しました。

モデル自体はGraphSAGE的なあまりメモリを使わないモデルを使っていて、スタンプやメタデータのembeddingは保存しますがユーザのembeddingは近傍からaggregateして計算するようなアルゴリズムを使っています。いろいろネットワークを試したんですが、私たちのタスクではGraph Attention Networkが一番パフォーマンスが出ていました。

ユーザのembeddingは先ほど言ったように近傍から計算するんですが、実際にサービングするときにはそれをRedisなどのストレージに保存して適用するというかたちでやっています。

こういうフレームワークを作って実際に適用してみてよかったことなんですが、最初の狙い通り開発効率の改善にはすごく効きました。これまでやはり並列計算などに開発工数を取られていることが多かったので、そこが抽象化されてモデル開発に集中できるようになったところがメリットかなと思います。

あとは、大きなデータを学習するときも、小さなデータと同じような感覚で開発できるようになったというのがあります。あとは、GPU使用率の向上は狙い通りでできて、かなり効率的に使用することができるようになりました。

それから、これはあまり期待していなかったんですが、コードレビューがしやすくなったというのがあって、それぞれの関数に何を書くかがだいたい整理されてみんな同じようなコードを書くようになったので、レビューがすごく楽になりました。

今日は事例紹介ということでピンポイントに並列計算のフレームワークについて紹介させていただきましたが、我々のマシンラーニングのチームではもっといろいろなものを作っていて、機械学習や分析に興味がある人を歓迎しています。

以上です。