カンムを支える技術 ~機械学習編~

バックエンドエンジニアの吉田です。カンムでは機械学習を用いた機能開発を担当しています。 バンドルカードでは後払い機能であるポチっとチャージで機械学習が使われています。 去年のAdvent Calendarで石澤さんが カンムを支える技術2020 という記事を書いてくれていましたがそこではあまり触れられていなかった機械学習まわりの取り組みについて簡単にご紹介します。 バンドルカードのサービスはAWSで構築されているので基本的にはAWSに寄せつつも機械学習ではGCPも活用しマルチクラウドで運用しています。

f:id:kanmu-tech:20210610153614p:plain

Data Preparation

DWHとしてBigQueryを利用しています。BigQueryにはバンドルカードのトランザクションデータやFirebaseで取得したアプリのイベントログ、サーバのアプリケーションログ等が集約されておりデータ分析やA/Bテストの集計、障害調査等に使われています。 機械学習においては、時系列データの各種統計量やラグ特徴量の追加といった特徴量エンジニアリングや前処理にもBigQueryを使っています。SQLで処理できるものは基本的にBigQueryに任せて学習用のデータセットを作成しています。

RDSに保存されているバンドルカードのデータは日次でBigQueryに同期しています。 ここでは単純にPostgreSQLのテーブルをほぼそのままBigQueryに転送しているだけで複雑なワークフローは必要なかったことと、GUIも必要なかったのでシンプルなDigdag/Embulkを採用しECS/FargateのScheduled tasksで実行時のみコンテナを立ち上げて処理するような構成にしています。エラーのときは最低限Slackに通知しているのと容易にリトライができるように同期処理が冪等になるようにだけは気をつけています。

続いてGCPではCloud SchedulerからCloud Dataflowのジョブが起動されます。 ここではBigQueryからデータを取得し特徴量エンジニアリングや前処理を行った後、CSVファイルでCloud Storageにアップロードされます。 これも同様に日次で実行されますが、トリガーはCloud Schedulerによる定時実行なので先ほどのBigQueryの同期処理の完了時間からバッファを持たせて実行させています。本当はBigQueryへのデータ同期の正常終了に続けてジョブ実行されるようにフローを組みたいところですが同期に失敗していても大きな問題はないのとそもそもほぼ失敗することはなく実運用上困ってはいないのでよしとしています。ここで作成されたデータセットがモデルの学習で使われます。

Training & Serving

本番で稼働するモデルの再学習は新しく学習データが追加されるタイミング (ポチっとチャージでは月初) や特徴量の追加、パラメータの変更などモデルが更新されるタイミングで行われます。

モデルの学習とサービングはSageMakerを利用しています。学習/推論用のコンテナだけ用意しておけば、データセット、モデル/メトリクス等の成果物、推論用のエンドポイントを一元管理してくれるので非常に便利です。 推論コンテナはGunicorn/Flaskを使ったシンプルなREST APIとなっています。

モデルの学習からサービングまではStep Functionsによって実行されています。すべてのタスクが完了したら、学習結果のログやメトリクスから性能に問題がないことを確認します。 Lambdaから呼び出す推論エンドポイントは環境変数で管理されているので、まず検証環境のエンドポイントを書き換えてテストデータでリクエストを投げてみて想定どおりの結果が返ってくることを確認します。問題がなければ本番環境も切り替えます。モデルの更新はそこまで頻繁に行われるわけではないのでこの辺は自動化せずに慎重に人間が確認をするようにしています。

推論のリクエストパラメータが変更されるような場合にAPIのバージョニングが必要となりますがこれもLambdaで解決するようにしています。

Inference & Monitoring

バンドルカードからはリアルタイムで推論しています。アプリからのユーザの操作であったりバッチ処理であったりトリガーは様々ですが、推論及びその後処理には多少時間を要するので非同期で処理をしています。 RDSにジョブをenqueueすることでWorkerが推論処理を行い、その結果をRDSに書き込みます。

モニタリングに関してはエラーやレイテンシ等の各種メトリクスのMackerelによる監視やRDSのジョブキューの監視を行い異常があった場合はslackやPagerDutyで通知をしています。 また、推論のリクエストと結果に異常がないか、後処理の結果が想定どおりであるかRedashのダッシュボードなどを用意して確認をしています。

推論時の特徴量のデータドリフトの監視の為にSageMaker Model Monitorなども検討しましたがサービスの特性上急にinput/outputの分布が変わったりすることもないし継続的にモデルを学習させているのでそのタイミングで性能劣化や分布に変化がないか確認すれば充分なので見送っています。

Development

開発はローカルマシンで行うことが多いですが、モデルの学習などコンピューティングリソースが必要な場合はGCPインスタンスも使います。 開発環境は基本的にすべてコンテナ化してローカルでもクラウドでも同じ環境で開発ができるようにしています。 パッケージ管理はpoetryを使い、linter/formatterにpysenを使っています。 実験管理はMLflow Trackingを使っています。GitHub issue, データセット, モデル等の成果物, メトリクスを一元管理して過去の実験をすぐに再現できるようにしています。

まとめ

機械学習の立ち上げ当初はモデルや推論APIの開発, バンドルカードへのインテグレーションまですべてひとりで開発していたので、パイプラインの整備までは手が回らず手動でEmbulkを実行して、SageMaker Notebookを使ってモデルを学習させて、、みたいな最低限の状態からスタートしてそこから少しづつ自動化したり改善を行って今のような構成になりました。まだまだ改善したいところはたくさんあります。エンジニア積極採用中です。

kanmu.co.jp