こんにちは、AI・機械学習チームの氏家と農見です。
エムスリーでは、東京のみならず福岡・関西など全国各地にメンバーがおり、開発を進めています。 ただ、チーム全員での交流も大事ということで、AI・機械学習チームでは四半期に一度のペースでチーム全員で集まって様々なイベントを開催しています。
今回は、そのイベントの最新版として機械学習コンペを開いたので、その様子をご紹介します!
ちなみに、前回はGameDayと称して、開発環境で人為的に発生させた障害に対して、その対応のシミュレーションをしました。 こちらの記事で当日のワイワイした雰囲気を感じていただけるので、ぜひこちらもご覧ください!
チーム内機械学習コンペ
今回は「おすすめの記事を推薦するメールマガジンについて、ユーザーがどの記事を読みたいか」を予測して、チーム内で精度を競いました。
機械学習コンペとは与えられたデータを元に機械学習モデルを作成し、決められた評価指標に対しての性能を競うものです。 代表的なものにKaggleがあります。
与えられたタスクの中で、その問題をよく分析し、データの処理やモデルの選定、学習などを工夫することで性能に差が出ていきます。
チーム内機械学習コンペをする目的
今回はAI・機械学習チーム全員でコンペに参加しました。 AI・機械学習チームは機械学習エンジニアだけでなくソフトウェアエンジニアもほぼ同数在籍しているチームで、当然ですが、機械学習以外の部分に強みを持ったメンバーも多くいます。 そんな中、チーム内でコンペをするのは3つの目的がありました。
- 推薦モデルへの理解を深める: チームの主要業務の一つである推薦タスクについて、実際に手を動かすことで、推薦モデルに必要なデータや勘所を理解する
- チームメンバーの相互理解: 普段の業務では見えにくい、各メンバーのモデリングスキルや問題解決へのアプローチを共有して、相互理解を深める
- 実サービスに載せる: ここで得られた知見を元にモデルをブラッシュアップし、実際のサービスとしてリリースする
コンペの流れ
提供データ
コンペで使うデータとして、次のデータを用意しました。
- 学習データ: 過去のメールマガジン配信実績からユーザーごとの「どの記事を」「クリックしたか/しなかったか」のログデータ
- 特徴量:
- ユーザー情報: 匿名化済みの年齢、診療科、ログイン頻度などのユーザー属性
- 記事情報: タイトル、本文などの基本情報に加えて、カテゴリ、タグ、記事の長さ、公開日などのメタデータ
- 配信コンテキスト: 配信日時、曜日、メールマガジンの種類など
この辺は、社内の実際の推薦システムに使っている情報を参照しつつ、できるだけ実務に近い形で提供できるようにしています。
事前準備
学習データに加えて、サンプルコードとリーダーボードも用意しました。 特にサンプルコードは、今回のコンペは半日という短期決戦を想定していたので、簡単な特徴量を使った学習から結果提出まで動く最低限の環境、コードまで手厚めに準備しています。 これは、機械学習を頻繁に触らないメンバーが基本的な学習コードを書くのに時間がかかり一度も結果提出できない、ということを防ぐためです。
当日の流れ
当日は会議室に集まってタスクを解いていきます。 今回は短期コンペということもあり各自のローカル環境*1で学習、推論していきます。
事前準備でしれっと紹介しましたが、リーダーボードまで用意する徹底ぶりです。
今回は次のようなスケジュールで行いました。
- 13:00~13:30 コンペの内容の説明
- 13:30~16:30 コンペ
- 16:30~17:00 結果発表と解法紹介
3時間と機械学習コンペとしては短めですが、サンプルコードがあった分、試行錯誤しつつみんなでワイワイする時間としてはちょうど良い時間でした。
解法紹介
コンペではチームメンバーがさまざまな解法でモデルを作りましたが、その中でも今回のコンペで効果的だった解法についていくつか紹介します。
ユーザーごとのバイアスを特徴に入れる
今回のコンペはクリックしたかどうかのAUCを評価指標としていたため*2、ユーザーごとの記事の嗜好はもちろんですが、そもそもクリックしやすいユーザーかどうか、というバイアスを強く加味できているかで大きな差がつきました。 言い換えると、クリックしやすいユーザーについて適切に予測値を高くできていることが評価指標上重要なコンペでした。
では具体的にどういう解法があったかというと、ユーザーごとのクリック数の平均のほか、中央値、標準偏差などの統計量を特徴量として入れることでユーザーごとのバイアスを考慮させるのが効果的でした。 他にも、学習データ上で一度もクリックがないユーザーの予測値を後処理で下げる、といったことも上位解法ではありました。
このように、最適化したい評価指標を意識してモデル設計をするのが重要で、これは実務でも重要な視点ですね。
記事のタグ情報を特徴に入れる
ユーザー側の特徴だけでなく、記事の情報を適切に入れるのも有効でした。 記事に関するデータとして、記事のタイトル、種別、本文などが与えられていましたが、今回は短期間、かつ比較的メモリが少ないMacBookでの実施という制約があったため、それらのデータを使って低次元で効率的に特徴を作る必要があります。
実際に上位解法では、記事のジャンルを表すタグのうち出現頻度の高いものを特徴量としていました。 エムスリーでは全ての記事に対して疾患や薬剤などのタグが自動で付与されています。 このタグは記事を端的に表す情報として実際の推薦システムでも大活躍していますが、今回のコンペでも有効だったようです。
解法紹介 番外編: Clineを使い倒す
今回のコンペの特徴として、3時間という超短期決戦が挙げられます。 上位に食い込むためには、特徴量を吟味して実装して実験して...という流れを高速に回していく必要がありました。 そのために有効な戦略はなんでしょう?
はい、みなさんのご想像の通り、生成AIを利用した解法ですね。 AI・機械学習チームでは生成AIでコードを書くツールであるClineを利用しているので、Clineにコードの生成部分を任せつつ、効きそうな特徴量を試していく、というアプローチが有効でした。
Clineにコード生成を任せると一口に言ってもやはりプロンプトの内容は重要です。 素朴にClineを使い倒すと考えると、次の例のように、入力データ形式を与えつつ特徴量から考えてもらうアプローチがありそうです。
機械学習コンペの特徴量について考えてください ### 入力データ 以下のようなcsvが与えられます。 user_id, sent_date, item_id
このプロンプトでもそれなりに効く特徴量を生み出すコードを生成してくれます。 一方で、上位解法には次のようなプロンプトが見られました。
ユーザー毎にどういうカテゴリーの記事をクリックするかの統計量を作って特徴量にしてください
効きそうな特徴量にあたりをつけ、実装して欲しい特徴量に具体性を持たせてプロンプトに与えるパターンです。 タスクの設計やデータの特徴などをコンテキストとして全て適切に与えるのは難しいため、コンテキストから特徴量に当たりをつける部分を人間が担当し、生成AIには実装に注力してもらうのが有効だったようです。 言い換えると、生成AIのあまりに広すぎる潜在空間を適切なプロンプトによって狭めており、このようなプロンプトエンジニアリングは現代のエンジニアの価値の1つだなぁと実感させられます。
これからコンペを開催する人へ
今回我々もコンペ初開催でしたが、コンペ設計に不安はありつつなんとか完走した知見をまとめます。 この記事を読んで1日程度の短期コンペを開催してみよう、と思っていただけた方の参考になれば幸いです。
テーマ選定は実務に近い内容にする
公開データでもチーム内コンペとしては成立するものの、前述のコンペの目的なども考えて、できるだけ実務に近い内容でコンペを実施するのをおすすめします。 実サービスに載せるつもりでなくとも、タスク設計や評価指標、計算リソースなどを実際の業務内容から逆算して設計しておくと、当日の解法はそのまま知見として普段の業務に役立ちます。 実際に今回のコンペでも、学習データの削減による効率化や記事特徴の組み込み方など実際の推薦システムで使っているテクニックも多く使われており、業務の参考になったというコメントもありました。
実益以外にも、やはり普段の業務で馴染みのあるデータでコンペをするのは盛り上がりが違い、コンペとしての体験も良かったように感じます。 コンペ主催者が直近に解いたタスクを題材にし、主催者のモデルと精度を競い、モデルをブラッシュアップするのも良いかもしれません。
データ、サンプルコードを手厚く用意する
今回スムーズにコンペが進んだ要因として、サンプルコードの存在が大きかったです。 LightGBMやpandasなど定番のライブラリを含んだ環境、最低限の学習から結果提出まで行えるコードを用意しておくことで、本番ではコンペにおける本質的な改善に取り組めました。
特徴量についても、コンペ当日に各々がデータを探しに行ったり泥臭いjoin作業をしていると時間がもったいないため、特徴量はすぐに読み込める形式で準備しておき、当日はそれのみを使うレギュレーションにしておくとスムーズだと思います*3。
開催前に全力でタスクを解いておく
今回はできなかったものの、開催前に準備側が一度は全力でタスクを解いておくのも重要です。
今回のコンペでは短期コンペということもあり各自のローカル環境で学習しましたが、学習/テストデータの容量が大きく、ローカルではまとまった量の特徴量を扱えませんでした。 また、検証データとテストデータに一部記事の重複があり、コールドスタートの設定が一部崩れてしまっていました。
いずれもサンプルコードの規模であれば問題にはならないものの、少し本気で解けば事前に気づけるものでした。 それらも制約と考えて最適化していくのも楽しいのですが、コンペの趣旨や当日の時間を考えると、事前にある程度本気でタスクを解いてコンペの参加体験が想定通りになっているか確認することをお勧めします。
リーダーボードを用意する
コンペがスムーズに進み、盛り上がった最大の要因はリーダーボードの存在でした。 3時間程度ということもあり当初はテストデータでの一発勝負も考えていましたが、結果的にはリーダーボードによる順位のリアルタイムフィードバックがあることが競技性のある良いコンペの重要な要素でした。
また、前述の通り今回のコンペはチーム理解も目的としていたため、リーダーボードでリアルタイムで推移する順位を取っ掛かりとして会話や議論が起きるのはかなり体験として良いものでした。
今回はStreamlitでcsv提出、順位公開機能を実装しましたが、面倒な方はKaggleのInClassコンペが使えるかもしれません。 公開データを使う際には検討すると良いと思います。
余談
せっかく集まったから、ということで、当日はBBQも開催しました。
まとめ
今回は、AI・機械学習チームで開催した社内コンペを紹介しました。 実務で機械学習モデルを作るのももちろん楽しいですが、今回のように競技としてモデルを作るのも楽しいですし、チームビルディングとしても有用です。 たまにはコンペを開催して、チームでわいわいしてみてはいかがでしょうか。
we are hiring!
AI・機械学習チームでは機械学習モデルを楽しみながら作れるエンジニアを募集しています。 次のリンクからご応募お待ちしています!