Re:ゼロから始めるML生活

どちらかといえばエミリア派です

小さいMLOpsってこんなもんかと思ってやってみる

この間はMetaflowを使ってみました。

www.nogawanogawa.com

ワークフロー管理+実験管理が可能なように、Metaflow + MLFlowを使ってコードを書いてみたいと思います。 多分、これだけでもMLOpsのごくごく一部は対応できていると思うので、今回はそのメモです。

参考

下記の記事で、小さく始めて大きく育てるMLOpsという内容が紹介されていました。

cyberagent.ai

こちらの記事では、「Hydra、MLflow Tracking、Kedro、Optunaを導入するところから始めてみては?」といった趣旨になっていました。

Hydraを使ってハイパーパラメータの管理、Optunaを使ってハイパーパラメータの探索を行うという事になっています。 ハイパーパラメータの管理は、規模が大きくなるに連れて管理の重要度が上がってきますので、ということなんでしょう。 Optunaも、使えるなら使ったほうが良いと思います。

今回は、めんどくさかったので最低限でいいと思ったので使っていませんが、これを読んでいる方は上の記事に習うのが良いと思います。 三流エンジニアの私より、その道のプロが言っていることの方が正しいと思いますので。

今回は上の記事を読んで、実際に自分でガチャガチャいじっててみようと思ったのがこの記事を書くモチベーションになります。

お題

文書生成

最近文書生成を題材に遊んでみていたので、今回もそちらを題材にやってみたいと思います。

www.nogawanogawa.com

こちらをベースに色々作っていきたいと思います。

今回の主な技術要素

本当はハイパーパラメータ管理や自動チューニングなども導入したほうが良いということは重々承知しつつ、簡単のため今回はワークフロー管理と実験管理に絞って導入することを考えます。

ワークフロー管理:MetaFlow

ワークフローライブラリについてはそれぞれ特徴がありますので、正直人それぞれ好みのものを使ったら良いと思っています。 今回はたまたま最近調べたMetaflowをそのまま使おうと思います。

www.nogawanogawa.com

実験管理:MLFlow

時々議論になっていたりするんですが、Metaflowでも実験管理はできないことはなく、「MLFlow v.s. Metaflow」という構図の記事をたまに見かけます。

git-academy.com

Metaflowでも、一応実行時の結果などを保存しており、それをJupyter-notebookなどで参照することで実験管理ができます。 ただ、個人的には、SaaS以外で実験管理するならMLFlow一択だと思っているので、ここについては特に選定理由はそんなもんです。

「餅は餅屋」、それぞれの特色をうまく組み合わせて使ったらいいと思うので、MetaflowとMLFlowを共存して使うのも良いと思います。 MLFlow自体、特に使用が難しいものでもないのですんなり使えるかと思いますし、ダッシュボードなどもデフォルトで使えるのでその点でも良いかと思います。

www.nogawanogawa.com

やってみる

Metaflow

Metaflowを導入すること自体はそこまで難しくないです。 処理の流れごとにメソッドを切って上げるだけなので、main.pyの記述を変更します。

# -*- coding: utf-8 -*-
from metaflow import FlowSpec, step

from readfile import readfile, prepareData
from encoder import EncoderRNN
from attnDecoderRNN import AttnDecoderRNN
from trainer import Trainer

INPUT = "INPUT"
OUTPUT = "OUTPUT"

class TextGenFlow(FlowSpec):

    @step
    def start(self):  
        print("Reading File...")
        text_df = readfile("data/entail_evaluation_set.txt")
        self.src, self.target, self.pairs = prepareData(INPUT, OUTPUT, text_df)
        self.next(self.init_network)

    @step
    def init_network(self):
        print("Initializing Network...")
        hidden_size = 256
        self.encoder = EncoderRNN(self.src.n_words, hidden_size)
        self.attn_decoder = AttnDecoderRNN(hidden_size, self.target.n_words, dropout_p=0.1)
        self.next(self.train)

    @step
    def train(self):
        print("Training...")
        self.trainer = Trainer(src=self.src, target=self.target, pairs=self.pairs)
        self.encoder, self.decoder = self.trainer.trainIters(encoder=self.encoder, decoder=self.attn_decoder, n_iters=75000)
        self.next(self.end)

    @step
    def end(self):
        print("Evaluation...")
        self.trainer.evaluateRandomly(encoder=self.encoder, decoder=self.attn_decoder)

if __name__ == '__main__':
    TextGenFlow()

ちょこちょこっと書き直しただけですが、大筋は前回とそこまで変わりません。

これだけで、

  • ワークフローを途中から再実行
  • 過去の実行のときの値を確認

などができるようになります。

MLFlow

MLFlowに関しては、使用するライブラリよって使い方が異なるようですので、ドキュメントを確認しながらやります。

www.mlflow.org

今回はPytorchを使用しているので、

  • pytorchのモデルを保存
  • 学習時のメトリックを記録
  • 学習時のハイパーパラメータを保存

くらいを実施していきたいと思います。

ドキュメントを見る限りでは、mlflow.pytorchってのでモデルの保存、その他はlog_param、log_metricでいけそうでした。

www.mlflow.org

最後にgithubつけましたが、10行前後追加しただけです。 こんな感じにトラッキングできます。

mlflow ui

f:id:nogawanogawa:20200719101225p:plain

考察

さて、こんな感じでちょっとした書き直しだけで、結構色々できるようになりました。

  • ワークフロー管理(Metaflow)
  • 特徴量管理(一部、Metaflow)
  • 実験管理(MLFlow)
  • 配信(MLFlow)

MLOpsと言っても欲しい機能を挙げたらキリがないですし、全部入りが欲しいとなったらMLOpsのSaaS使うのが手っ取り早いと思います。 一方で簡単に書くだけでも色々便利になりますし、ちょっとの努力で結構いろんなことができるようになるので、もし余力があればこの辺もやってみるのが良いかと思います。

書いたもの

適当に書いた残骸はこちら。

github.com

感想

今回は、MetaflowとMLFlowを実際のコードに使ってみようと思ったので、やってみた次第です。 個人的にはMetaflowは簡単に使えると思いますし、MLFlowもSaaSを使用しないのであれば実験管理ライブラリとしては筆頭だと思っています。

MLOpsはなかなか範囲は広いですが、これだけやるだけでも使い勝手はだいぶ良くなると思います。 これくらいの小規模からやるのが、敷居が低くて良いのかなとか思いました。