マルチモーダルなDNNを扱うサービスの本番環境でやらかした話
こんにちは!ころんです。
ちょっと長い間更新をさぼっていましたが、元気にやってます!
よく見たら去年のADTも書いてなかったですね。今年は17日目になります。
TL;DR
- Concatレイヤーの順番が設計したモデルと同じか確認しよう
- モデルをデプロイする前に精度指標以外にもモデルの分布を確認しよう
- 学習時とServingで同じ特徴量をいれたら同じ出力になるか確認しよう
DNNモデル
現在とあるサービスの機械学習のモデリングとその運用の仕事に携わっています。
(詳細はお話できなくて申し訳ないです)
機械学習と言っても様々なドメインがありますが、画像とテーブルデータを用いたDNNを作成しています。いわゆるマルチモーダルですね。
モデルの構造としては画像の畳み込みレイヤーとテーブルデータの特徴の全結合層をそれぞれn次元にまで圧縮、Concatした特徴量を全結合層に通してスカラー値を出すようなモデルです。下記はイメージ図です。
一般的なマルチモーダルモデルのアーキテクチャになっており、学習したモデルをk8sでマネージドしているサーバーにServingし運用しています。
また学習時と推論時では参照しているリポジトリや環境も違うため※1、それぞれが独立して動作するような構成になっています。
※1 学習はGCPのAI Platform、推論時はk8sでtewnsorflowのバージョンは合わせて運用しています
何が起こったか
上記で作成しているモデルは特注なロス関数を組み込んでいるため、学習が終わったらモデルの重みを保存し、Serving時はその重みを読み込んだ上で学習時に使ったモデル構造を再度記述した上で実行しています。
そしてモデルを本番環境にリリースして数日後、社内からモデルが出している値がほとんど変化しないという報告をもらいました。
原因
通常tensorflowでモデルを保存するときは、モデル構造と重みを同時に保存するsaved modelやh5形式が使われます。
しかしながら、今回は重みだけを保存する形式のためサーバーには学習時に使ったコードをコピーして記述する必要がりました。
ここでミスをやってしまいます。
アーキテクチャに戻りますが、Concatする際はTable data + Imageの順番でベクトルの結合をしています。
しかし、サーバー側ではImage + Table dataで結合してしたのが原因で、本来計算される重みが適切にかけられていない事象が発生していました。
コードで表すとこんな感じ。
原因が発覚しすぐに修正PRを出しましたが、裏では様々なバッチが動いており復旧には数日かかりました。
解決策
上記の事象をチームで共有後に解決策を練りました。
1. レビューの強化
PRでサーバーのモデル構造に変更を加える際は、元となる学習のコードもセット(githubのurlで十分)にしてレビューをするように意識付けをしています。
チームでは複数のMLエンジニアがモデルを作成しているので、それぞれのモデルにメインの担当者を付けてダブルチェックする体制も入れました。
2. 検算の仕組みを作る
学習したモデルとサーバーから返される値に違いがないかをチェックする仕組みを作る。これをするとサーバーに実装した前処理にもミスがないか確認できるのでCI/CDに組み込んで自動的に検出できるようにします。
噂ですがTensorflow Pipelineにはそういう機能があるらしい?
3. データの可視化
実は本番環境へデプロイする前に、testに使った真値と予測値との分布の乖離を確認するために可視化した結果をSlackに通知する機能がありました。
今回はたまたまconcatを逆にしても大きな乖離が出なかったため見落としていました。しかし、よく見ると以前学習したモデルに比べてピークになっている値が多くあったため、傾向として捉えることができたはずでした。
そもそも可視化をしていなかれば気づけなかったことが多くあります。単純にモデルのRMSEといったロス指標だけではなく、必要箇所でデータの可視化を行うことが改めて大切であるということが学べた機会でした。
まとめ
今回はDNNのConcatレイヤーでやらかして本番にデプロイしちゃった話を書かせていただきました。問題発覚時は入社して一番冷や汗書いたので、ML系のサービスを運用する際には気をつけましょう。
明日のTUT Advent Calender 18日目はあやふみさんです!
まだタイトルも決まってないようですが、 どうなるんでしょう👀