Days-」が開催されました。同社が運営するITエンジニア向けのQ&Aフォーラム「teratail」の中で解決できない問題を解くため、一流エンジニアたちが一同に会して、プレゼンテーションやパネルディスカッションを行いました。成長を止めない機械学習のやり方」では、クックパッド株式会社リサーチエンジニアの染谷悠一郎氏が登場。機械学習を取り入れたサービス開発において、組織や個人に発生しがちな問題と、その解決方法を解説します。染谷悠一郎氏(以下、染谷):ありがとうございます。みなさん、おはようございます。1時間目ということで「成長を止めない機械学習のやり方」というテーマでお話しさせていただきます。今回、AIのセッションオーナーの方からご紹介いただきましてMANABIYAで発表させていただくことになりました、染谷と申します。学生時代はコンピューターサイエンスをずっとやっておりました。実は、機械学習ではなく、機械論理学とか形式手法とかそのあたりをずっとやっておりまして、2016年に卒業してクックパッド株式会社に入社して研究開発部に入りました。今はリサーチエンジニアという肩書きで研究をやっております。いう話はこれから少しずつしていくと思います。うちはAWSをすごく使っているので、AWSの上で機械学習をやりやすくする基盤を作ったり、あとは一応研究開発にいるので、レシピデータを使って分析、ディープラーニングも少しやっております。最初に軽くクックパッドの紹介をさせていただきます。クックパッドはご存知いただいている方が多いと思うんですけども、レシピの投稿・検索サービスを運営しております。現在、Webとスマートフォンでレシピ数が280万品以上、国内の月間利用者数で言うと約6,000万人のユーザーに使っていただいています。最近はグローバル化に力を入れてまして、現状の対応言語が22言語、68カ国でうちのサービスがお使いいただけるようになっています。海外の月間利用者数は3,000万人以上という状況です(注:数字はいずれも2017年12月時点のもの)。クックパッドの研究開発部は、僕が入社して新卒研修を3ヶ月やって、配属が決まる時期の2016年7月にできたんです。僕はクックパッド研究開発部の初期メンバーですね。それからハイヤリングもがんばってます。Alexaのアプリケーションを作る部隊もいたりしてデータサイエンティストだけではないんですけど、国内の研究開発部には合計18名の人間がいます。海外にもデータを中心に仕事をしている人間が10人ほどいます。写真で「何の料理か」判定する料理きろく今日の例示として使うので紹介させていただきたいんですけれども、クックパッドとして深層学習を実際にアプリケーションに取り入れた最初の例として出た......あ、アプリケーションじゃなくてフィーチャーですね。クックパッドの今回のアプリケーションの1フィーチャーとして公開されている、「料理きろく」というものがございます。これはどういうものかというと、スマートフォンの中のカメラロールの写真の中から料理の写真だけを分類して抜き出して、カレンダー上に配置してくれるというそれだけなんですけども。料理して写真を撮るっていう普段の記録行為をまとめてあげるようなサービスですね。実際、中で画像分類が動いています。これはオプトイン型なので、使いたいというユーザーの方にだけ使っていただいているんですけど、現在、20万人のユーザーから利用許諾をいただき、使っていただいてます。その中で2,000万枚以上の料理写真が記録されています。たくさんの写真が判定の対象になるんですけど、現在、そのうち料理写真が2,000万枚あります。研究開発部としては、例えばさっきは「料理か料理じゃないか」に関してだけでしたが、例えば画像からラーメン、チャーハン、その他みたいなレシピの分類をさらに細かくやるとか。うちはユーザーの方からコンテンツを投稿いただくサービスなので、材料名にしょうゆって書かれていたり、おしょうゆって書かれていたり、漢字で醤油って書かれていたり、すごく表記ゆれがあるんですね。あとは、うちのサービスを使っていただいていたらわかると思うんですけど、醤油と砂糖の左側に星が書いてあって、「星を混ぜる」とかステップに書いてあったりします。いった表記ゆれを解消したいときに、データを使ってなんとかできないかやってみたりとか。あとはユーザーさんから直接来るフィードバックを自動でタグ付けするとか。「このサービスに関するフィードバックです」とか、「ポジティブです」「ネガティブです」とかいうのもやったりしてます。これはMANABIYAのスローガン的なところに書いてあったんですけど、「質問まではいかないが気になっていること、回答を知りたいがなかなか知る機会がなかったことを日本中から集めて、今日、明日を通して解決策を見出して知恵を生み出すといったことをやりたい」と言っていますね。僕なりに考えた結果としては、疑問を日本中から集めるということは、要は「実はこういう問題があるんだよ」という話をして、発見されていない課題をまずここで共有するわけですね。そのうえで「じゃあ、こうすべきだ」っていうところまではいかなくても、「例えばこういうことができるよね」と解決策をいくつか列挙して、それぞれ「こういう解決策はこういう問題があるよね」と分析して1つの本当の解決策に向かうための礎にするといったコンセプトなのかなと思ったわけです。これは僕のセッションの説明文なんですけど、一応、最初に考えたときにそのコンセプトに則っています。実際に機械学習をやっている組織において「プロジェクトがスピードアップしない」とか「どうしても機械学習を使ったアプリケーションが出せません」といった課題があるとしましょう。そのうえで原因をいろいろ考えていくんですね。「こうだから機械学習のアプリケーションができない」「こうだから機械学習のプロジェクトが加速しない」というところを考えていって、それを分析していきます。いうわけでタイトルは、「成長を止めない機械学習のやり方」です。今回は機械学習に取り組む現場、とくにうちみたいなサービス開発の現場にちょっと寄っちゃうんですけど、そういったところで機械学習をやるときの課題を見つけて、分析します。人工知能に寄せられる期待の高まりアジェンダはこんな感じですね。前半しゃべりすぎたので、少しかいつまんでいきます。はじめに、「人工知能ブームと幻滅期」。聞いたことのある人はたくさんいると思うんですけど、現在我々は第3次人工知能ブームの真ん中にいるわけです。使おうぜという話がすごく出てきた。応用したいっていう流れがすごくあって、うちみたいなサービス事業も例外じゃないわけですね。みんなが機械学習をやりたいと思っている。この図、見たことある人はいますか?(会場挙手)けっこういますね。これは何かと言うと、人々の期待の時系列変化です。左から右に人々の期待値が変化していく。ハイプと言って、過度な期待が寄せられている分野に関する期待のグラフなんですね。Y軸が期待値で、X軸が時間。機械学習が今どこにいるかと言うと、このへんにいるんですよ。去年の人工知能学会の基調講演で話されていたんですけど、結局、今って機械学習への期待がものすごく膨らんでいて、このあとドスンと落ちる瞬間が来るんじゃないのって言われているわけです。歴史的にもそういう話が何度かあって、今が第3次って言われるのは第1次、第2次が潰れちゃったからですよね。いった期待値が上昇している現状で、このあとどうしようかって考えると、現場としてやっていくことは、機械学習を使ってコツコツと価値を創造していくしかないわけです。結局なんでもなかったじゃんってなっちゃうと、幻滅した瞬間の落ち幅がすごいことになっちゃうので。今回はサービス開発現場のクックパッドの現場で得られた知見を中心に、この問題について考えていきたいなと思っています。第1章、成長を止めない機械学習のやり方、組織・チーム編ということで話していきます。テーマはサービス開発と機械学習ですね。先ほども申し上げたとおり、サービス開発の現場でも機械学習を使いたいというニーズがすごく膨らんでいます。うちもすごくやりたいなと思っているんですけど。そもそもサービス開発企業が機械学習を使うっていうのはどういうことなのかを、ちょっと見直してみます。これは機械学習のワークフローというか、ライフサイクルみたいなキーワードでよく出てくる図を僕がデフォルメして書いてみました。てっぺんの課題発見から、「こんなことやりたいんだよね」「この数字を最大化したいね」ということを決めてから、持ってるデータを集めて、それを分析して......EDAっていうのは、探索的データ分析みたいなやつですね。要はグラフにしてみたり、並べてみたりして可視化して分析して、「モデルはこんなものを作りましょう」ということで学習をして、評価して、「これなら本番に出せるね」ってなったら本番に出すと。フィードバックループがあって、新たな課題を発見してループを回していくというのが機械学習のワークフローだと思います。左の部分が機械学習のモデルを作っているところ。実際に使っているところはあそこなんですね。本番に出ないと使ってることにはなりません。話は飛ぶんですけど、本番にモデルを出すときに、例えば1つの案としてすごくシンプルなモデルのAPIを作って、例えばpredictというendpointが生えていて、そこに画像を投げるとなにかが返ってくるみたいなデプロイ方法を考えたとすると、それに必要なステップはこのくらいあるんですね。聞きなじみがないかもしれないですけど、学習したモデルを持ち出すためにそれをセーブしてダンプして、かたまりの1個のファイルにして、この実行環境を実際に、その実験環境と同じようにモデルが動くような環境を作ってあげて、DockernizeしてAPIサーバーを作ってあげて、Endpointを作って、アプリケーションのサービスの開発の人たちと「このendpointに投げてね」とかコミュニケーションして、実際自分たちの持ってるインフラの環境にインテグレーションすることが必要になります。機械学習を使うための手間と時間の認識のギャップ何が言いたいかと言うと、けっこう手間と時間がかかるんです。機械学習を使うには手間と時間がかかる。一方で、これは実際に我々の今現在使っている料理きろくというサービスの中で機械学習が使われている行です。ある程度抽象化してありますけど、classifierにイメージを投げると、resultが返ってきて、resultが料理だったら何をするというのが、機械学習モデルが真ん中にあって、その周りにコードでロジックが書かれているわけですよね。これは1個の例なので毎回こうとは限らないんですけど、サービス開発という文脈で機械学習を使おうぜってなったら、機械学習モデルの動作というものは、要はif文と一緒なんですよね。ロジックと一緒なんですよ。この画像が料理の写真だったらこうする、料理の写真じゃなかったらこうするというのを実装するわけなので。今みたいに、サービス開発側から見た機械学習のモデルという存在は1行のコードであるべきなんです。いうときに何が起こるかと言うと、例えば、ちょっと字がちっちゃいですけど、こっち(右の絵)はサービス開発の人ですね。こっち(左の絵)はR&Dの人。サービス開発の人がカレーとラーメンだけじゃなくて麻婆豆腐も分類したいとなったとする。先ほども言ったとおり機械学習の分類というのはコードで書かれたロジックと同等に扱われるので、サービス開発の人の頭の中では麻婆豆腐を加えるには、category=麻婆豆腐を足せばいいじゃんって話なんですね。カレーだったらカレーのロジック、カレー用のファンクションを動かして、麻婆豆腐だったら麻婆豆腐用のファンクションをこっちで動かす。実際にR&Dの頭の中にはさっきのサイクルがあって、またデータに直して麻婆豆腐の写真で何枚かまとめて学習するのかって考えると、ここにスピード感のギャップが生まれるわけです。カテゴリー1個足すのに何週間もかかるのはサービス側からは許容しづらい。気持ちのうえでの問題もあるんですけど、こういったかたちでサービス開発とモデルの開発・デプロイというところにはギャップが生まれやすいことがわかってきました。ギャップは人員配置の最適化で埋めるどうすればいいかと言いますと、まず単純な話で人材配置の最適化をすりゃいいよっていう話がありますよね。いうことかと言うと、それぞれサービス開発とR&Dが1人ずつだったらしょうがないんですけど、だいたいチームで動いているので複数の人材が配置されてるわけじゃないですか。時間がかかって困るんだったら、単純な話、こっち(サービス開発)の人がこっち(R&D)に行ってデプロイを手伝ってあげたりすればいいんですよね。単純な話なんですが、とくにサービス開発に機械学習を使うのは不慣れで、まだやったことないという現場だとそうなりがちです。さっきみたいなスピード感のギャップがあるという問題が共有されていないわけです。機械学習とサービス開発の間で「サービス開発のPDCAの流れに機械学習を乗っけるというのはけっこう大変なことなんだぜ」っていうことが共有されてる現場はまだ少ないと思うんですよね。人材配置を最適化すればいいんですけど、根本問題として機械学習からサービス開発において価値を見出すことにおいては、それぞれの時間的スケールにギャップがあるという問題をしっかり共有して歩み寄ることが必要です。実際の対応策としては、例えば人的リソースの配置を見直してみることが実現できているわけです。さっき言ったように、機械学習のモデルを作る側にいたけど、デプロイするところはサービス開発の人が手伝う流れでやってみるっていうことが選択肢に入ってきます。「本当に機械学習に取り組むべきなのか」ここはサラっといくんですけど、人材配置の最適化以外の対応策としては、例えば取り組む問題の見直しと書きましたが、要はさっきみたいなギャップは開発現場ではコストになり得るわけです。先に右下の引用なんですけど、これは2015年かな、Googleが出した論文です。「機械学習のシステムってすごく複雑化しやすくて維持するのがすごく大変で、機械学習ってキラキラしてるけど、使うとシステムにとって潜在的コストになり得るよ」って話ですね。技術的負債の塊であると言ってるんですけど。2つ目の課題を考えられたとして、さっきの開発現場でのスピードのギャップとか、こういった技術的負債になりやすいという部分を加味したうえで、機械学習は本当に利用して取り組むべき価値がある問題なのかを考え直すというのは、さっきみたいな問題を認識しないと正しく話ができないですよね。ここがメインなんですけど、エンジニアとしては、こういった問題があるときに機械学習のモデルの開発と改善が遅くて困るとなったら、開発のサイクルを早くしてあげるために「開発のサイクルが遅いという問題をエンジニアリングで解決しようぜ」という話が当然出てくるわけです。僕なんかもここ派なんですけど。さっきAPI化するのも大変だという話をしたように、結局、機械学習のモデルを学習して、実際にそれが使えるかどうかを確かめて、デプロイして、本番に出して動かすというところの1個1個の大変な部分を、エンジニアリングによってやりやすくしてあげるという話をします。開発の効率化について、今回に関してはクックパッドでどういう取り組みをしているかでお話ししますと、機械学習基盤というものを自分たちで作って改善しています。これはどういったものかと言うと、機械学習に関わる、機械学習の実験をしたりデータを集めて実験して学習したり、実験して学習して分析するみたいなところを効率的にやれるようにするための基盤です。めずらしいかどうかはわかりませんが、うちの部門が意識的にやっているのは、研究開発部の中にこういった基盤を作って改善する人間を配置しています。さっき僕のロールはリサーチエンジニアと言ったんですけど、いわばインフラとか開発基盤の人間が研究開発部にいるっていう状況なんですね。Tokyoで発表したやつです。インフラストラクチャー部の部長と僕とで発表しました。あっち(画像右)はPyData.Tokyoで発表したクックパッドの機械学習基盤です。いった取り組みをしています。複数のGPU環境をどうやって用意するのか具体例としていくつか実際にやっていることの紹介をしたいのですが、例えば1つは、うちにはオンデマンドGPU環境というのがあります。いったものかと言いますと、さっき背景でお話ししたように、海外含めてメンバーがけっこういっぱいいて、しかもリモートでたくさんメンバーがいる。その中で複数の深層学習系のプロジェクトが立ってて、「これやりたいね」というものがある。そこに対して複数名がコミットするという、けっこうアクティブな状況なんですね。その中で実験用の環境をどうするか。いう話があって、どうしたかという話を軽くしたいと思います。bot経由で起動・停止可能なオンデマンドのGPU環境が社内にあります。これは自製したやつですね。言うと、「実験用のインスタンス作ってほしいんだ」とslackに言うわけです。すると裏でAWS的なものがうにょうにょと動いて......少し細かく説明しますか。このへんは置いといて、右のこいつですね。これがAMIと言って、AWSにEC2インスタンスって計算機があるんですけど、その計算機の上で例えばGPUドライバーを設定したりとかCUDAをインストールしたりとかPyTorchを入れたりまでを設定したあとの状態を、スナップショット撮ってセーブしておけるような仕組みがあるわけですね。それができると、設定済みのインスタンスがいくつも立てられているようになる仕組みを使って、うちでは深層学習用に使うAMIというのを部内にいくつか持っていて。「実験用のインスタンスを作って」って言ったら、そのAMIから適切なものを選んで起動して、sshを通すコマンドを返してあげるといったことをやる。Slackの特定のチャンネルの中でGPUインスタンスを使いたいんだったら「GPUインスタンスを作ってくれ」っていうコマンドを叩くと、3分後くらいにsshコマンドが返ってきて、コピペしてターミナルで入ると入れて、中でGPUがすぐ使えるみたいな状況があります。これはわかると思うんですけど、自分で3つ欲しかったら3回やれば3つ返ってくるみたいな感じ。詳しくはさっきの資料とかもあるので、この資料はあとで公開するのでTwitterを見ていただければわかると思います。効率化するための1つの取り組みとしてオンデマンドのGPU環境をお話ししました。1個、これは最近チームでやり始めていますが、プロジェクトのテンプレート化による実験の再現性の向上ということをずっとやってます。いうことかと言うと、例えば一方でまだプロダクションに乗ってないけど画像からメニュー名が分類できるような実験をやっているとします。2ヶ月前くらいに、画像を100万枚使って、ラベルをくっつけて、麻婆豆腐とかラーメンとか分類できるモデルを作るってことをAさんがやっていました。その後「そういえば、あれあったよね。あれをもうちょっとカテゴリー化してこっちで追実験したいんだけど」っていうBさんがいたときに、Aさんの実験を再現できないということがすごく多いんです。なんでかと言うと、いろいろ要因はあるんですけど、まず例えば、実は100万枚の画像データをいかにバージョン管理するかみたいなノウハウがないということがありあます。いうのはGitでプッシュするわけにはいかないので、じゃあこれどうしようかみたいな。LFSみたいなのもあるんですけど、まあ、なんかやらないといけない。再現性が低下しがちなんですね。耳馴染みがないかもしれませんが、これを解消するためにワークフローエンジンみたいなものがあって。ワークフローエンジンって何かと言うと、例えばクラウドストレージのここから画像を持ってきて、画像をベクターに変換して、さらにクラウドストレージの別の場所にそのベクターを書き戻すみたいなフローをプログラムで書いてあげて、実行するとそれが再現されます。例で言うとDigdagとか、あとはAirflowとかLuigiとかあるんですけど。それを部内で整備しようってなるかというと、そこまではコストをかけたくないっていうときに、ちょっといいのが見つかりました。Pythonのライブラリなんですけど。(会場挙手)あんまりいないですね。これってもともとCookiecutterってプロジェクトのテンプレート化のツールなんですね。ご存知の方がいるかどうかわかんないですけど、Rubyにはbundlerっていうのがあって、Rubyのライブラリを作りたいときにはbundlerで自分のテンプレートを吐かせてそのあと開発すれば、公開まですんなりできるんですけど。Scienceで実験を再現するPythonには、Cookiecutterというのがあります。ほかにもあるんですけど、テンプレートを生成するツールですね。CookiecutterにPythonパッケージを作りたいですと言うと、Pythonのパッケージのよくあるかたちのディレクトリの構成がダーっと生成できkます。これはテンプレートもプラグインみたいにほかの人が開発できるような設定になっています。実はデータサイエンス用でもあるんですよ。scienceというのがあります。Scienceを使ってテンプレートを生成すると何ができあがるかと言うと、ザッとこんな感じのディレクトリ構成で、もうちょいいろいろあるんですけど生成されます。各種規約ディレクトリって書いてあるんですけど、要はまずソースというディレクトリができて、ソースの下にデータとモデルというのがあって。データを作るソースはここに書いて、モデルをトレインするやつはここに書けるみたいな、規約に則ったディレクトリが切られているわけですね。一方でソースと同じ階層にデータっていうディレクトリが切られて、こいつは基本的にデータを入れる場所なのでGitにあがらないようにあらかじめignoreされている。一方でMakefileのほうにtargetがあって、このtargetを使うとAmazonのクラウドストレージにデータを規約に則ったプレフィックスを切ったうえでコピーされるみたいなtargetが書かれている。それは逆もできるわけですよね。何言ってるかわかんなくなってきたと思うんですけど。追実験したいとなって、先ほどは「ソースコードはあるけどデータはどっかいっちゃったよ」っていう話になってたんですけど、「ここだよ」って指してあげて。こいつをcloneしてあげて、さっきのデータを持ってくるtargetをmakeするわけですね。クラウドストレージ上にある規約のプレフィックスの下にあるデータがシュッとローカルに落ちてきて、実験がすぐに再現できるといったような。データのバージョニングとか細かい問題は残るんですけど、けっこう手軽で小規模なチームにおいてはすぐに再現性の向上が狙えるいいツールでした。これはよかったので、うちの社内のエンジニアがもうちょいいいやつにしようということで、実はオープンソースのプロジェクトができています。開発の効率化を担当する人を配置するさっきのやつはすごく平たく言うとdockerを使ってないんですね。dockerを使わずにrequirementsってかたちで依存ライブラリを列挙してあげて、それで実験の環境を再現できるということだったんですけれども、事はそううまくいかない場合もあるので、できればdockerで再現性を保証してあげたいという気持ちがあって、さっきのやつのdocker版みたいなものを作っています。notebookとかやるとdocker......が立ち上がって、ローカルマシンでもportをしっかりつなげられて、こっちのブラウザから見られるようになるとか、そういったことができるようになっていて、ここはちょこちょこ開発しているような感じです。いうのもいわゆる機械学習基盤の1つですね。モデルの開発の効率化は、要は研究開発部の中で基盤を作るエンジニアも配置されていて、そこで積極的に改善しているといった背景があります。一例としていくつか紹介しました。Tips集みたいにはしたくなかったんですけど、実際にチームで機械学習をやろうぜとなったときに、このへんをお世話する人がチームの中にいるとやっぱりいいと思います(笑)。開発の効率化というのはこんな感じでやっていきますよって話をしました。一方で、課題としてすごく大きいのがデプロイですね。学習したモデルを実際に使うとなったときに、どう使うかという話です。デプロイの選択肢ってけっこういろいろあるんですよ。うちはRailsで動いているのでRubyになっちゃうんですけど、サーバーのコードの中に機械学習のモジュールを食い込ませる。実際にバッチプログラムとかどこかのサーバー上のAPIポイントの裏側で機械学習が呼ばれて、その判定結果を実際に動作に活かすみたいなサーバーに埋め込むやり方があったりとか。あとPythonパッケージ化するみたいなのもありますね。社内のPythonパッケージのレポジトリにあげておいて、モデルをインストールするとモデルのクラスが使えるようになるとかっていうのもあるんですけど。あとはさっき言ったAPIですね。ちっちゃいHTTPで通信できる小さなAPIサーバーを作ってあげて、その中にモデルを入れるみたいな。いくつかあってそれぞれに良いところと悪いところがあるわけなんですけど、ちょっと今日は時間がないのでAPIがいいという前提で話を進めていってしまいます。モデルを読み込んで外部リクエストに応じて、要はpredictみたいなエンドポイントがあったり、あとはヘルスチェックするhello波動とか、なんでもいいんですけど、エンドポイントが立ってるというだけのちっちゃいアプリケーションを作るのがおすすめです......っていう話はさっきあったPyData.Tokyoのスライドにも書いてあるので、もし詳しく知りたい方がいればそちらを参照ください。あ、でも、良い理由はこれから話します(笑)。APIが良い理由はいくつかあって、機械学習のモデルを呼び出すだけのAPIなので、すごくMicroservice的な考え方なんですよね。マイクロにもほどがあるってほどマイクロなんですけど。Microserviceの利点とほぼ一致するんですけど、まず機械学習をやるモデルの部分とアプリケーション、例えばWebサーバーのほうで異なる技術が使えるという部分ですよね。うちだとサーバーはほとんどRubyで書かれていて、機械学習はPythonでやることが多いのでそこはもう顕著です。デプロイの効率化をどうするかあとは機械学習のモデルというのは、深層学習だったらGPUの上で動かしたいときに、1つの独立したサービスとして存在していると、そのへんの取り回しがききやすくなる。あとはこれもMicroserviceの利点ですけど、サービスで分化されたAPI、WebサーバーとAPIという部分が機械学習APIと疎結合になっていると機械学習APIだけ必要な分をスケールして伸ばせるとかですね。これはちょっと細かい話なんですが、機械学習のモデルは、さっきも言ったとおり写真が料理かそうでないかを見分けたり、料理の写真からメニューを当てたりっていう、1個1個はけっこうプリミティブな存在なんですよ。料理かそうでないかを見分ける分類器みたいなのは必ずしもアプリケーション1個じゃないんですよね。さっきの料理きろくで使う場合もあれば、もしかしたらユーザーから投稿されたレシピの写真が料理じゃなかったらアドミンツールで警告を出して「このレシピはちょっと変だよ」と通知してあげるっていう使い方もできるかもしれない。Microservice系の良さとして機械学習のモデルというプリミティブな存在を各所で再利用するというチャンスも生まれるといった話があります。