機械学習チームにおけるソフトウェアエンジニアの役割
修士・博士としてデータマイニング分野の会議で発表を行うなどの経験を重ねていた伊藤氏は、2007年にソフトウェアエンジニアの職に就いた後、検索エンジンやNLP(Natural Language Processing:自然言語処理)といった、さまざまな経験を経て、2017年に現在の(クックパッド株式会社)機械学習グループに配属となりました。
話すトピックは大きく2つ、「『機械学習チームにおけるソフトウェアエンジニアの役割』と『Web企業における機械学習分野のキャリア形成』について話していきます」と切り出し、セッションを始めました。
伊藤氏は本題に入る前に、「機械学習プロジェクトには、通常のソフトウェア開発とは異なる点がある」として「モデルに振る舞いが隠蔽されているため、コードを読んでも振る舞いが分からない」「入力データに結果が依存し、さらには入力の傾向が変化する場合がある」「知見を共有して安全性を確保するのが難しい」といった特徴を挙げました。
こうした前提条件がある機械学習プロジェクトを多数見てきた伊藤氏の所感として、最近では(機械学習の導入・管理の)難しさをエンジニアリングで対処し、またデータサイエンティストをサポートするチーム編成(MLエンジニアやデータエンジニアなど)を敷くようになり、結果としてAIや機械学習分野で活躍するソフトウェアエンジニアが増加してきたといいます。そのような環境・状況でソフトウェアエンジニアはどういった貢献をしてくべきなのか。伊藤氏は「『プロジェクトのライフサイクル』に注目することでその部分が見えてくる」と続けました。
機械学習プロジェクトは、その内容から3つの大きな「ステージ」に分けることができます。
- Jupyter Notebookを利用して探索的な試行錯誤を行う「実験」ステージ
- 実験に用いたコードをリファクタリングし、必要に応じてライブラリ化も行いCI環境へ組み込んでいく「コード整理」ステージ
- ライブラリを利用したサービスを提供したり監視体制を整えたりする「デプロイ」ステージ
実際のプロジェクトでは、この3つのサイクルを何度も回すことで精度を向上・頑健化させ、「より良いシステム」に改良を加えていきます。「悪いプロジェクト」ではこのサイクルをスムーズに回すことができなくなり、サイクルが回らないと精度も向上せず、モデルが固定化されてしまうという状況に陥ってしまいます。
ソフトウェアエンジニアが機械学習チームで求められるポイントは、この「プロジェクトのサイクルを高速かつ安全に回すことができる環境を整備していくこと」であると伊藤氏は強調し、各ステージにおけるそれぞれの問題をエンジニアリングで解決する方法について、詳細な解説に踏み込みました。
【1】「実験ステージ」における問題
このステージにおける問題は大きく2つ。「データの取得」と「計算機リソース」です。
「これだけは絶対やっちゃダメ」と念押しながら「データを簡単に取得できる環境を構築する前にリサーチャーやデータサイエンティストを大量に雇ってはいけない」という「データ取得に関するアンチパターン」を紹介。彼らが出すアウトプットはデータの取得コストに依存するため、データの取得コストが増えてしまう状況(データ取得が容易に行えない状況)では十分な結果を残せない、というのがその理由です。伊藤氏は「これはいわば『丘サーファー』のようなものです。まずは彼らに水を届ける体制を整えなければなりません」と例えました。
扱うデータの種別には「データベースのテーブル群」と「ログファイル」が存在します。そして、データサイエンティストはこれらの両方のデータに自らアクセスできる必要があります。
現在、巨大なデータを保持し、簡単に抽出できるプラットフォームの選択肢は沢山存在します。そして、これらの仕組みをうまく活用することで社内のあらゆるデータを分析基盤に載せることが可能となります。この際、「くれぐれも人手によるデータ投入は行わず、自動で投入できるような仕組みを整備してください」と伊藤氏は強調しました。
「参考までに」と伊藤氏は自社事例を紹介。クックパッドでは機械学習チームとは別にDWHチームが存在し、必要なデータをSQLで簡単に取得できる環境を整備しています。詳しくは以下のスライドに内容がまとまっています。
もう1つの問題「計算機リソース」については、複数人で単一サーバにログインして作業をしているとリソースが足りなくなり、実験が進まない……というものです。この問題を解決するために、クックパッドでは計算機リソースの管理用Slackウェアを作成し、Slack上のやり取りでリソースの準備から不要になったリソースの廃棄までを自動で行う仕組みで対応しました。
【2】コード整理ステージにおける問題
次の「コード整理ステージ」では「コードが理解できない」「ポータビリティがない」という2つの問題について解説。
前者の「コードが理解できない」では、稼働しているモデルの生成コードについて言及。ただでさえ難しい機械学習のアルゴリズムは、コードが整理されていないとさらに理解が難しくなってしまいます。「これらのコードを『まずはスクリプトにしていく』ことが大切」と伊藤氏は語ります。コードのリファクタリングを行い、自動テストの仕組みに稼働コードを載せていくことで、プロジェクトメンバーの理解も深まります。コード整理のタイミングでは分業では行わず、リサーチャーとエンジニアのペアで取り組むことで、知見の共有もできる上にチームメンバーのスキルも均一化できるのでオススメとのことです。
後者の「ポータビリティがない」の問題は、実験・整理・デプロイという異なる環境下で動作させるためには、実行環境にポータビリティがないと辛い……といった内容です。多数のライブラリに依存する機械学習プロジェクトではこの「ポータビリティ」が非常に重要なポイントとなります。伊藤氏はこの問題について、コンテナ型の仮想化環境を提供するOSSである「Docker」を導入することで解決しました。都度同じDockerコマンドを打ち込むのが面倒という氏は、Docker導入と併せてプロジェクトのテンプレート生成ツールである「Cookiecutter Docker Science」というOSSも併用しています。
【3】デプロイステージにおける問題
3つ目の「デプロイステージ」では、「デプロイの効率化」を挙げました。プロジェクトでは実験とコード整理を経てできた機械学習の結果を環境にデプロイする必要があります。このデプロイ作業をスムーズに実施するためにはインフラ基盤を整備し、デプロイコストを効率化していかなければいけません。
伊藤氏はこの課題に対して「爆速で深層学習のモデルをデプロイするツール」である「Kelner」を紹介しました。先に紹介した「Cookiecutter Docker Science」および「Kelner」について「これらのツールはオススメなのでぜひ使ってみてほしい」と太鼓判を押しました。