メルカリの機械学習環境を勉強してみた

# 内容
メルカリさんのMLプラットフォームについて

# なんの知識が身につく記事になっているか？
- 日本の有名企業が使用してるMLのプラットフォームで使われている技術を知ることが可能
- MLFlowのパイプラインをローカル環境で構築/使用する方法

# 勉強した動機
- メルカリさんの[Mercari ML&Search Talk #3](https://engineering.mercari.com/blog/entry/20220617-1460348232/)という記事の中でメルカリさんが使用しているプラットフォームの説明があり、世の中で使われている技術について知っておきたかったため。
- 知らない言葉がいっぱいありそうだったため

# 勉強した感想
- kubernetesの知識がない状態でメルカリさんのプラットフォームを構築しようとしたのは無謀だった。結果、KubeFlowのPipeLineしか触ることができなかった。
- 使用しているソフトウェアがyamlファイルで履歴管理できるものを多く使用している点に俗人性を排除しよとする意図を感じた

# メルカリのMLプラットフォーム
まず、メルカリにおけるＭＬプラットフォームの定義は以下です。
>メルカリにおけるMLプラットフォームとは、機械学習システムを構築・管理するための技術やインフラ全体を指します。
>データ探索とモデルのトレーニング管理、推論を実行するためのエンドツーエンドのシステムと定義します。

メルカリさんで使用されているMLプラットフォーム例は以下です
- Kubeflow（本記事ではKubeFlowメインで解説）
- mlflow
- [polyaxon](https://engineering.mercari.com/blog/entry/20201203-674faad2c1/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/948a99b0-4b3e-0ce9-b4f5-f4195cc4c0d7.png)

# トレーニングプラットフォーム
トレーニングに用いるプラットフォームだけ本記事では紹介します、運用などに使用するソフトウェアまで勉強しきれませんでした...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/e914e88b-beb1-9836-ca40-50fad10d2b0f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/9ffa02ad-7878-1579-784b-d672dc75ae47.png)


上記のプラットフォーム上で以下のようなフローで学習を回しているようです
1. ユーザーがKubeflow pipelineを作成
1. ローカルまたはCircle CI(※１)経由でデプロイ
1. チームのGCPプロジェクトからDockerイメージなどを取得
1. トレーニングの結果をSlackで通知
1. トレーニング終了後、モデルのパラメーターと精度をmlflowに格納
1. モデルをチームのGCPプロジェクトにプッシュ
1. 結果が悪い場合には再トレーニング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/7045e8d5-d2f4-25f7-190d-856204105910.png)

ここまで、メルカリの記事を読んで、自分の全く知らなかったKuberentes（k8s）とKubeFlowについて調査＆環境構築をしてみたいと思います。

※１　[Circle CIに関するリンク](https://qiita.com/gold-kou/items/4c7e62434af455e977c2) 
Jenkinsと比較して設定をyamlファイルで設定できる点が大きな違いと感じた。この後、登場するKubernetesもyamlファイル管理であり、履歴管理可能な環境を選択している印象を受けた。

# Kubernetes
- 読み方
    - クーベネティス、クーベルネティス、クバーネティス、クバネティスなど様々
- コンテナのオーケストレーションツール
    - 複数のコンテナを管理することが可能
    - 複数の物理マシンに複数のコンテナが存在することが前提
    - 望ましい状態を維持する
        - コンテナを〇個、ボリュームを△個など
        - YAMLファイルで望ましい状態を記述しておく
        - 障害などでコンテナが停止したりした場合は自動で削除して生成してくれる
- もともとはGoogle社の技術だったが、GoogleがCloud Native Computing Foundation（CNCF）を立ち上げ、CNCF寄贈して開発がオープンになったことで普及が進む.
    - Kubernetesは現在CNCFにより策定された規格でOSS
    - CNCF自身もKubernetesを開発しているがサードパーティ製のKubernetesも多く存在している
        - AWS,Azureなどのクラウドサービスではクラウド用にカスタマイズされたKubernetesサービスを提供
            - [リンク](https://www.cncf.io/certification/software-conformance/)

![image.![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/dc479fee-5ce0-b7b7-9b11-fa8b3a87cf2e.png)
png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/aa861dc8-f22f-1dff-27ba-052728bb49bc.png)

- Kubernetesの構成
    - クラスター
        - マスターノードから成る「コントロールプレーン」と、実際にコンテナ稼働するワーカーノードから成る「データプレーン」から構成されるKubernetesシステムのこと
            - マスターノード
                - etcd
                    - 状態管理のため
                        - 必要なサービスやPodの情報が記述されている
                        - マスタノード側で記述されているだけの状態をオブジェクトといい、実際に実行され生成されたものをインスタンスという
                - kube-scheduler 
                    - どのノードで Pod を動かすかをコントロールするため
                -  kube-apiserver 
                    -  kubectlからの命令をうけとって操作を実行する
            - ワーカーノード
                - コンテナエンジン
                    - dockerなど
                - 
    - pod
        - コンテナとVolumeがセットになった１まとまりのこと
        -  AWS の EC2 インスタンスなど
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/440fae1a-d04e-a57e-3f2e-b82108e69fc6.png)
[図の出典：AWS](https://aws.amazon.com/jp/blogs/startup/techblog-container-k8s-1/)

ワーカーノード側の詳細な図が以下

- Searvice
    - 外部からのアクセスを自動で捌いてくれるオブジェクト
        - Podをまとめて管理してくれており、外部からはサービスのIPアドレス（ClisterIP）にアクセスすればサービスが管理するPodのアドレスはきにする必要がない
        - 物理マシンをまたいでPodを管理することも可能
- ReplicaSet
    - Podの数を管理
- Deployment
    - Podのデプロイ（配置や実行）を行う
        - Podで何のImageを使うかなどの情報をもっている


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/92a4232e-684d-5e6e-11fe-77bb7514fcdf.png)
[図の出典：Basicinc エンジニアブログ](https://tech.basicinc.jp/articles/154)

# KubeFlow
- Kubeflowは機械学習パイプライン（データ抽出、特徴量エンジニアリング、モデル学習、モデルデプロイ）をK8s環境で実行するためのツール
    - KubeFlowの各コンポーネントはKubernetess上で動作する
        - KubernetessのAPIを使用しPodなどを操作するため
    - 元々はGoogle社内で使用されていたものを社外に向けて一般化してオープンにしたもの
- 様々な[Component](https://www.kubeflow.org/docs/components/central-dash/overview/)がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/be7714d0-b90e-6ac8-2d6b-be3724fb0145.png)
    - Notebook ServersではJupyter Notebookが使用できる
    - PipeLineで一連の処理を行える

## Pipelines
- Pipelines
    - どのような処理を行っていくかが可視化されている
    - 自作したパイプラインをアップロードすることも可能（YAMLファイル）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/e4c13cee-91bf-5e9d-1e1c-506cadab0efb.png)

- Run
    - 作成したPipeLineを選択し実行するとパイプラインが実行される
    - 実行時の引数などをGUI上から入力することも可能
    - 今どのStepが実行されているかなどもわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/ad0d7f34-f02d-79b5-01bf-72a252d5f685.png)

- Experiment
    - Runした結果を確認することができる
        - Stepごとの結果も確認可能
            - どのStepに問題があるかなどもわかる
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/83d36c1d-9ab9-9dcc-a0c2-6329725d1239.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/0e4cfae9-5617-5d34-bb87-0f2847e37439.png)
数字を表示するだけのパイプラインの例↓。出力結果なども確認可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/ee078ab2-eded-90db-3200-e181daaaf281.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/030832b7-4a3c-6942-790d-ae6ff3a09b7f.png)

- 自作パイプラインの作成手順
    - [参考](https://www.kubeflow.org/docs/components/pipelines/sdk/build-pipeline/)
    - コンポーネントを作成する(python環境上での操作)
        - コンポーネントは２種類存在する
            - 既存のコンポーネントを使用する場合
                - Kfp.component.load_from_url(コンポーネントのパス)と記述する
                 コンポーネントのパスに存在するコンポーネント（再利用したい実装）を取得できる
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/39c177b0-5a4a-21c2-d223-49b13e30107a.png)


            - 自作関数をコンポーネント化する場合
                - kfp.components.create_component_from_funcと記述する
                - 関数を実装したpythonの関数をfunc=の引数とする
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/08747e09-bdff-ddc2-69b6-625bd419438a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/695c2d9b-ca4e-ed70-8fbd-b16d4bb2e8f3.png)


    - パイプライン化 する方法(python環境上での操作)
        -  先ほど生成したコンポーネントをパイプラインとして定義した関数を作成する
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/d64fdab3-3b70-01ee-6717-35e1f5cd9244.png)
    - パイプラインファイルをKubeFlowにアップロードする方法
        - 自作したpiplineファイルをコンパイルする(python環境上での操作)
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/600f4224-5056-e8ec-45af-5149f8bdf1f6.png)
        - pipeline.yamlファイルが生成されるのでGUI上でアップロードする


## kubeflowとkubernetes
Pipleineの各StepごとにPodが生成され実行される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/7fe8351a-7a9a-eed6-8488-dfaa3eb4f40b.png)
[図の出典：ubuntu](https://ubuntu.com/blog/data-science-workflows-on-kubernetes-with-kubeflow-pipelines-part-1)

yamlファイルをアップロードすると[Argo](https://qiita.com/MahoTakara/items/ca34c90cbf7e737efb03)のWorkflowのInstanceがK8aのAPIを操作し、Podの操作を行う
(Argo Workflowもyamlファイルでワークフローを定義する)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/f8af1543-9901-c9f9-138d-127547286c47.png)


# ローカル環境にk8s環境とkubeFlow　PipeLine環境を構築する手順
いろいろあり、DashBordはあきらめ、PipeLine環境だけを構築しました。

## 環境構築方法①　GKE(Google Kubernetes Engine)上にKubeFlowをInstallする方法
GCPの無料枠が$300であり、KubeFlow環境を構築するには無料枠では足りないとの記載があったため断念しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/9f369ed1-bbc8-bf31-6f65-e7dc52e8e954.png)

個別で環境を構築するより、この方法が断然簡単だとは思います。
他にもAWS上での構築方法などが[公式HP](https://www.kubeflow.org/docs/started/installing-kubeflow/)に載っています。

## 方法② Docker上で構築する方法
私はこの方法で行いました。

まず、Docker DesktopのKubernetesを有効化します。
ローカルにkubectlコマンドがInstallされます。また、Docker Desktop起動時にKubernetesコンテナが起動するようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/3d6cf75c-372b-254f-1e61-a698abc3258f.png)

次に、[PipelineのInstall](https://www.kubeflow.org/docs/components/pipelines/installation/localcluster-deployment/)を参考に、KubeFlowをInstallします。リンクの内以下のスクショ部分だけを実行します。
KubernetesのEngineの上にKubeFlowを構築します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/317b165a-ddbc-ddab-9967-fd718c79896d.png)

kubectl applyにより以下のyamlファイルに記述されているオブジェクトを生成しています。いろいろ生成しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/3cdca4f2-687c-c2ec-44bc-28283531c9e9.png)

ml-pipline-uiのサービスが動作していることが分かります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/12e5a1ce-a480-29d0-5110-45b529a09bf0.png)

Port-forwardでローカルホストの8080でuiのPodにアクセスできるように指定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/48ecbd08-3438-5c6f-6389-781f93ec15ca.png)

これでLocalhostの8080でKubeflowのPipeLineにアクセスできるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/00f8850a-94e9-3d2b-cd7c-605159d0cb62.png)

## 構築失敗例
- [Minikubeをつかった構築](https://v0-2.kubeflow.org/docs/started/getting-started-minikube/)
    - ２個くらいissueが存在するが、[issue](https://github.com/kubeflow/kubeflow/issues/2863)によりうまく構築できなかった。
KubeFlowのバージョンが古くうまくいかなかった模様。Docker DesktopのK8sもver.1.22以上だとうまくいかないので注意が必要。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/3230cd51-3409-21e5-a8fe-b685adfd0bd9.png)

- Linux環境のコンテナにminikubeとKubeflowを構築する方法
    - VM（仮想環境）上にMinikubeを構築しないと正常に動作しない模様。なんだか面倒臭そうだったので諦め。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/3dcfc4ef-189c-5630-09ee-c5ab8837ac3f.png)

カーネルの中にvirualboxが必要とするヘッダーが含まれていないという事らしい。厳密には、カーネルと完全に同一バージョンのヘッダーパッケージが入っている必要があるという事のようです
VBが必要としているのは↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/59bd996a-345c-ca58-537c-3b24e3669862.png)

現在のコンテナに入っているのが↓で足りていない模様。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/12841693-0d1a-65bd-3aa3-e23c5aa77368.png)