Slide 1

Slide 1 text

Dynalystにおける MLワークフローへのPrefect導⼊事例

Slide 2

Slide 2 text

⻑江 五⽉ ⾃⼰紹介 2 @nsakki55 ブログ: https://nsakki55.hatenablog.com/ PrefectやAWSでML基盤を構築する記事を書いてます 業務 ・MLOps ・MLモデリング ・広告データ分析 CyberAgent AI事業本部 Dynalyst MLエンジニア

Slide 3

Slide 3 text

1. なぜPrefectを選んだか 2. Prefectでワークフローを組む⽅法 3. DynalystのPrefect運⽤ 4. Prefectを運⽤した感想 ⽬次 3

Slide 4

Slide 4 text

1. なぜPrefectを選んだか 4

Slide 5

Slide 5 text

5 リターゲティング広告を⾏う広告配信プロダクト リターゲティング広告とは︖ 「前にあるゲームで遊んでたけど◯⽇間ログインしてない」 ユーザーを対象にした広告 インストール 離脱 アプリ復帰 広告配信 Dynalystの紹介

Slide 6

Slide 6 text

6 DynalystのML活⽤ 広告枠 ◯円で広告を表⽰します 広告オークションの⼊札価格決定にMLを活⽤ クリック確率(CTR) アプリ起動確率(CVR) などの ML予測値を元に計算

Slide 7

Slide 7 text

7 DynalystのMLワークフロー N個のモデルの学習が毎⽇M回⾏われる データ取得 前処理 学習 オフライン評価 オンライン評価 データ分布評価 モデルデプロイ データ取得 前処理 学習 オフライン評価 データ取得 前処理 学習 オフライン評価 ・・・ 並列 実⾏ でワークフローを定期実⾏

Slide 8

Slide 8 text

8 DynalystのMLワークフロー ECS Taskでタスクを実⾏ データ取得 前処理 学習 オフライン評価 オンライン評価 データ分布評価 モデルデプロイ データ取得 前処理 学習 オフライン評価 データ取得 前処理 学習 オフライン評価 ・・・ ECS Task ECS Task ECS Task ECS Task でタスク実⾏を制御

Slide 9

Slide 9 text

9 ワークフローツールをなぜ変える︖ ・ML以外のオフライン処理がdigdagで運⽤されていた ・管理するワークフローツールは1つにしたかった ・最初はシンプルな学習バッチを動かせればよかった ・MLワークフローに徐々に機能追加 で運⽤できていた 運⽤課題が出てきた

Slide 10

Slide 10 text

10 ワークフロー運⽤の課題 巨⼤YAMLの認知負荷が増加 タスク1 タスク2 タスクごとのログをCloud Watchで確認 ワークフロー画⾯にログを集約したい タスク1 データ タスク間のデータの受け渡しが困難 タスク2

Slide 11

Slide 11 text

11 ワークフロー運⽤の課題 柔軟な条件分岐を⾏いたい タスク2 タスク1 タスク3 条件A 条件B ワークフローのテストを書きたい

Slide 12

Slide 12 text

12 ワークフロー選定要件 既存システムとの相性 リアルタイムログ監視 開発がしやすい ワークフローを柔軟に組める 低コスト SageMaker Pipeline Step Functions

Slide 13

Slide 13 text

13 なぜPrefectを選択した︖ 既存システムとの相性 リアルタイムログ監視 開発がしやすい ワークフローを柔軟に組める 低コスト タスクをECS Taskで実⾏できる Web UIからログ追跡可能 Pythonで実装 if elseを使って書ける Prefect 2.0から値上がり😰

Slide 14

Slide 14 text

14 詳細はテックブログに記載してます https://developers.cyberagent.co.jp/blog/archives/38253/

Slide 15

Slide 15 text

2. Prefectでワークフローを組む⽅法 15

Slide 16

Slide 16 text

16 本⽇紹介するのは Prefect 2.0 の⽅法です

Slide 17

Slide 17 text

17 PrefectでETLワークフローを実⾏する 抽出 変換 格納 S3から⽣データ ダウンロード ⽣データを集計 S3に集計データ アップロード S3 S3 Web UIからスケジュール実⾏

Slide 18

Slide 18 text

18 Prefectでのワークフロー開発 Pythonでワークフローを作成 Flow・Taskをつくる Try and Errorで開発 Blockの作成 Agentの登録 Deploymentの登録 Prefect Cloudから実⾏ ワークフローを実装する ワークフローを運⽤する

Slide 19

Slide 19 text

19 Prefectでワークフローを実装する Pythonでワークフローを作成 Flow・Taskをつくる Try and Errorで開発

Slide 20

Slide 20 text

20 Prefectでワークフローを実装する Pythonでワークフローを作成 import pandas as pd import boot3 bucket = boto3.resource("s3").Bucket(s3_bucket) def extract(file_name: str) -> pd.DataFrame: bucket.download_file(Key=file_name, Filename=file_name) df = pd.read_csv(file_name) return df def transform(df: pd.DataFrame) -> pd.DataFrame: df_transformed = df.groupby(["type1"]).mean().reset_index() return df_transformed def load(df: pd.DataFrame, file_name: str) -> None: df.to_csv(file_name) bucket.upload_file(Key=file_name, Filename=file_name) def etl_flow(download_file_name: str, upload_file_name: str): extracted_df = extract(file_name=download_file_name) transformed_df = transform(extracted_df) load(transformed_df, file_name=upload_file_name) if __name__ == "__main__": etl_flow(download_file_name="extract.csv", upload_file_name="transformed.csv") Pythonでワークフローを作成 Flow・Taskをつくる Try and Errorで開発

Slide 21

Slide 21 text

21 Prefectでワークフローを実装する Flow・Taskをつくる from prefect import flow, task import pandas as pd import boot3 bucket = boto3.resource("s3").Bucket(s3_bucket) @task(name="extract task") def extract(file_name: str) -> pd.DataFrame: bucket.download_file(Key=file_name, Filename=file_name) df = pd.read_csv(file_name) return df @task(name="transform task",retries=3, retry_delay_seconds=60) # リトライ設定 def transform(df: pd.DataFrame) -> pd.DataFrame: df_transformed = df.groupby(["type1"]).mean().reset_index() return df_transformed @task(name="load task", timeout_seconds=30) # タイムアウト設定 def load(df: pd.DataFrame, file_name: str) -> None: df.to_csv(file_name) bucket.upload_file(Key=file_name, Filename=file_name) @flow(name="ETL Flow") def etl_flow(download_file_name: str, upload_file_name: str): extracted_df = extract(file_name=download_file_name) transformed_df = transform(extracted_df) load(transformed_df, file_name=upload_file_name) if __name__ == "__main__": etl_flow(download_file_name="extract.csv", upload_file_name="transformed.csv") Pythonでワークフローを作成 Flow・Taskをつくる Try and Errorで開発

Slide 22

Slide 22 text

22 Prefectでワークフローを実装する Try and Errorで開発 $ python etl_flow.py 15:35:30.208 | INFO | prefect.engine - Created flow run for flow 'ETL Flow' 15:35:32.454 | INFO | Flow run - Created task run 'extract task-0' for task 'extract task' 15:35:32.455 | INFO | Flow run - Executing 'extract task-0' immediately... 15:35:33.780 | INFO | Task run 'extract task-0' - Finished in state Completed() 15:35:34.033 | INFO | Flow run - Created task run 'transform task-0' for task 'transform task' 15:35:34.034 | INFO | Flow run - Executing 'transform task-0' immediately... 15:35:35.185 | INFO | Task run 'transform task-0' - Finished in state Completed() 15:35:35.487 | INFO | Flow run - Created task run 'load task-0' for task 'load task' 15:35:35.488 | INFO | Flow run - Executing 'load task-0' immediately... 15:35:36.556 | INFO | Task run 'load task-0' - Finished in state Completed() 15:35:36.557 | INFO | Flow run - ETL flow finished 15:35:36.830 | INFO | Flow run - Finished in state Completed('All states completed.') Pythonでワークフローを作成 Flow・Taskをつくる Try and Errorで開発

Slide 23

Slide 23 text

23 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Prefect Cloudから実⾏

Slide 24

Slide 24 text

24 Prefectの構成要素を知る Flow Code Prefect Cloud Agent Deployment Flow 実⾏ Storage Block Flow Code Infrastructure Block Flowの管理・実⾏設定のメタデータ 登録 アップロード ダウンロード Flow実⾏ Deoloymentに設定できるFlow管理・実⾏設定 Prefect CloudからFlowをポーリングし、 infrastructure上で実⾏する Flowの実⾏・管理を⾏うWeb UIサービ ス Deployment Storage/Infrastructure Block Agent Prefect Cloud

Slide 25

Slide 25 text

25 Prefectの構成要素を知る Flow Code Prefect Cloud Agent Deployment Flow 実⾏ Storage Block Flow Code Infrastructur e Block Flowの管理・実⾏設定のメタデータ 登録 アップロード ダウンロード Flow実⾏ Deployment

Slide 26

Slide 26 text

26 Prefectの構成要素を知る Flow Code Agent Deployment Flow 実⾏ Storage Block Flow Code Infrastructur e Block 登録 アップロード ダウンロード Flow実⾏ Prefect Cloud Flowの実⾏・管理を⾏うWeb UIサービ ス Prefect Cloud

Slide 27

Slide 27 text

27 Prefectの構成要素を知る Flow Code Deployment Flow 実⾏ Storage Block Flow Code Infrastructur e Block 登録 アップロード ダウンロード Flow実⾏ Prefect Cloud Agent Prefect CloudからFlowをポーリングし、 infrastructure上で実⾏する Agent

Slide 28

Slide 28 text

28 Prefectの構成要素を知る Flow Code Deployment Flow 実⾏ Storage Block Flow Code Infrastructure Block 登録 アップロード ダウンロード Flow実⾏ Prefect Cloud Agent Deoloymentに設定できるFlow管理・実⾏設定 Storage/Infrastructure Block

Slide 29

Slide 29 text

29 Prefectの構成要素を知る Flow Code Prefect Cloud Agent Deployment Flow 実⾏ Storage Block Flow Code Infrastructure Block Flowの管理・実⾏設定のメタデータ 登録 アップロード ダウンロード Flow実⾏ Deoloymentに設定できるFlow管理・実⾏設定 Prefect CloudからFlowをポーリングし、 infrastructure上で実⾏する Flowの実⾏・管理を⾏うWeb UIサービ ス Deployment Storage/Infrastructure Block Agent Prefect Cloud

Slide 30

Slide 30 text

30 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Blockの作成 Prefect Cloudから実⾏ from prefect.filesystems import S3 import os block = S3(bucket_path="prefect-etl", aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'], aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'] ) block.save("etl-s3-block") $ python storage_block.py

Slide 31

Slide 31 text

31 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Blockの作成 Prefect Cloudから実⾏ from prefect.infrastructure import DockerContainer block = DockerContainer(env={ "EXTRA_PIP_PACKAGES": "s3fs pandas prefect-aws" }) block.save("etl-docker-container-block") $ python infrastructure_block.py

Slide 32

Slide 32 text

32 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Agentの登録 Prefect Cloudから実⾏ $ prefect agent start -q etl Starting v2.9.0 agent connected to https://api.prefect.cloud/api/accounts/.../workspaces/... ___ ___ ___ ___ ___ ___ _____ _ ___ ___ _ _ _____ | _ ¥ _ ¥ __| __| __/ __|_ _| /_¥ / __| __| ¥| |_ _| | _/ / _|| _|| _| (__ | | / _ ¥ (_ | _|| .` | | | |_| |_|_¥___|_| |___¥___| |_| /_/ ¥_¥___|___|_|¥_| |_| Agent started! Looking for work from queue(s): etl... 23:42:09.694 | INFO | prefect.agent - Created work queue 'etl'.

Slide 33

Slide 33 text

33 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Deploymentの登録 Prefect Cloudから実⾏ from etl import etl_flow from prefect.deployments import Deployment from prefect.filesystems import S3 from prefect.infrastructure.docker import DockerContainer from prefect.server.schemas.schedules import CronSchedule storage = S3.load("etl-s3-block") infrastructure = DockerContainer.load("etl-docker-container-block") deployment = Deployment.build_from_flow( flow=etl_flow, name="etl-flow-deployment", version=1, work_queue_name="etl", storage=storage, infrastructure=infrastructure, tags=['dev'], schedule=(CronSchedule(cron="0 0 * * *", timezone="Asia/Tokyo")) ) deployment.apply() $ python deployment.py

Slide 34

Slide 34 text

34 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Prefect Cloudから実⾏ Prefect Cloudから実⾏

Slide 35

Slide 35 text

35 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Prefect Cloudから実⾏ Prefect Cloudから実⾏ Prefect Cloud Agent elt.pyダウンロード Docker containerとしてFlow実⾏ etl.py ダウンロード Flow実⾏

Slide 36

Slide 36 text

36 Prefectでワークフローを運⽤する Blockの作成 Agentの登録 Deploymentの登録 Prefect Cloudから実⾏ Prefect Cloudから実⾏

Slide 37

Slide 37 text

3. DynalystのPrefect運⽤ 37

Slide 38

Slide 38 text

38 Prefect移⾏後のイメージ 38 オンライン評価 データ分布評価 モデルデプロイ データ取得 前処理 学習 オフライン評価 ・・・ ECS Task ECS Task ECS Task ECS Task 元々の構成

Slide 39

Slide 39 text

39 Prefect移⾏後のイメージ 39 オンライン評価 データ分布評価 モデルデプロイ データ取得 前処理 学習 オフライン評価 ・・・ ECS Task ECS Task ECS Task ECS Task ・ワークフローツールだけ変える ・既存のアプリケーションコードは変えない 変える・変えない要素

Slide 40

Slide 40 text

Prefectを導⼊するために考えたこと Flowの実⾏ Flowの管理 Prefectの設定管理 CI/CD Flowをどこで実⾏する︖ Flowのコードをどこで管理する︖ Prefectの計算リソースをどこで管理する︖ PrefectへのFlowデプロイをどうやって⾏う︖

Slide 41

Slide 41 text

41 Prefectを導⼊するために考えたこと Flowの実⾏ Flowの管理 Prefectの設定管理 CI/CD 既存システムに合わせECS Taskで実⾏ stg, prodはECS Taskで実⾏、開発はローカルDocker環境で 実⾏するために、Docker Imageで管理 既存システムのインフラ管理に合わせTerraformで管理 既存システムに合わせてGitHub Actionを利⽤

Slide 42

Slide 42 text

42 DynalystのPrefect運⽤ 全体構成

Slide 43

Slide 43 text

43 Flow開発の流れ ローカル開発 Flowコードをimage化 ローカルPCでコンテナとして実⾏ Try and errorで開発

Slide 44

Slide 44 text

44 Flow開発の流れ CI/CD Flowを追加したPRをmerge FlowをECRにデプロイ Prefect CloudにDeployement登録

Slide 45

Slide 45 text

45 Flow開発の流れ stg・prod実⾏ Prefect Cloudから定期・⼿動実⾏ Terrafromで管理したAgent(ECS Service)が ECS TaskとしてFlowを実⾏

Slide 46

Slide 46 text

46 Flow開発の流れ 環境差分の解消 Flowをコンテナ化することで コンテナをどこで実⾏するか︖ にdev・prodの環境の差を減らせる

Slide 47

Slide 47 text

47 DynalystのPrefect運⽤ 全体構成

Slide 48

Slide 48 text

48 MLワークフローの組み⽅ ECS Taskを実⾏するタスクを組み合わせる @flow("ML Workflow") def ml_workflow(model): train_model = train_model_task(model) update_model = update_model_task(train_model) validate_data = validate_data_distribution_task(train_model) validate_model = validate_model_online_performance_task(train_model) モデル学習 モデルデプロイ データ分布評価 オンライン評価 ML Workflow CPU=4048 memory=8096 CPU=512 memory=1024 CPU=2048 memory=4048 CPU=1024 memory=2048 Taskごとに リソースを変更

Slide 49

Slide 49 text

49 DynalystのPrefect運⽤ ディレクトリ構成 ├ .github/workflows... Deployment登録・image build/push ├ ml_workflows ....... MLワークフローの実装 ├ Dockerfile ......... Prefectで実⾏するコンテナ⽤Dockerfile └ prefect_flows ...... Prefect Flowの実装 ├ flows └ tasks ワークフローツールの仕様に合わせて、アプリケーションコードを変更したくない → アプリケーションコードの実装と、Prefectの実装は分けた

Slide 50

Slide 50 text

50 DynalystのPrefect運⽤ CI/CD ECR prod-flow:latest ECS Task Block image= prod-flow:latest ECS Task Flow実⾏ Agent (ECS Service) Flow image download ・FlowのimageをECRで管理 ・ECS Task Blockの 実⾏imageに指定 Flow image push deployment 登録

Slide 51

Slide 51 text

51 DynalystのPrefect運⽤ Flow実⾏画⾯例 ログの集約が可能となった

Slide 52

Slide 52 text

52 DynalystのPrefect運⽤ パラメータの活⽤ 実⾏時パラメータに計算リソース・ 学習設定を渡す 特定のモデルだけ学習する、 メモリを⼀時的に上げる などの動的な変更が可能

Slide 53

Slide 53 text

4. Prefectを運⽤した感想 53

Slide 54

Slide 54 text

54 Prefectでよかったこと 失敗時の原因調査・リトライが楽になった Prefect Cloudにログを集約できた ワークフローのテストを書けるようになった 計算リソースの変更が容易 通常のPythonコードを実装するような開発体験

Slide 55

Slide 55 text

55 Prefectで困ったこと PrefectはFlow実⾏環境を⽤意する必要があるため、インフラ知識が必要 → ソフトウェアエンジニアメンバーに相談しながら進めた ベストプラクティスが普及していない → 公式Slack Communityで似た課題の議論を探した Prefectのコードと、アプリケーションコードの境⽬が曖昧になる → 明確にディレクトリを分けた

Slide 56

Slide 56 text

まとめ 56

Slide 57

Slide 57 text

57 まとめ ・なぜPrefect︖ 既存システムとの相性・開発のしやすさ・WebUIの存在 ・どうやってPrefect運⽤してる︖ FlowをDocker Imageで管理 FlowをECS Taskで実⾏ Prefectの設定をTerraformで管理 GitHub ActionでCI/CD