ZenML: Framework Pipeline MLOps yang Modular dan Cloud-Agnostic

# ZenML: Framework Pipeline MLOps yang Modular dan Cloud-Agnostic ## Pendahuluan Membangun model machine learning yang akurat hanyalah sebagian kecil dari tantangan dalam produksi ML. Tantangan sesu...

By Ruby Abdullah · · tutorial
ZenMLMLOpsPipelineOrchestrationPython

ZenML: Framework Pipeline MLOps yang Modular dan Cloud-Agnostic

Pendahuluan

Membangun model machine learning yang akurat hanyalah sebagian kecil dari tantangan dalam produksi ML. Tantangan sesungguhnya terletak pada bagaimana membuat pipeline yang reproducible, scalable, dan mudah di-maintain. ZenML hadir sebagai framework MLOps open-source yang dirancang untuk mengatasi masalah ini dengan pendekatan yang modular dan cloud-agnostic.

ZenML memungkinkan data scientist dan ML engineer untuk mendefinisikan pipeline ML menggunakan Python decorator yang sederhana, sambil tetap memberikan fleksibilitas penuh untuk mengintegrasikan berbagai tool dan platform cloud. Dengan konsep "stacks" yang unik, Anda bisa berpindah dari local development ke production di cloud tanpa mengubah kode pipeline.

Dalam tutorial ini, kita akan mempelajari ZenML dari dasar hingga membangun pipeline end-to-end yang mencakup data ingestion, preprocessing, training, evaluation, dan deployment.

Prasyarat

Sebelum memulai, pastikan Anda memiliki:

  • Python 3.8 atau lebih baru
  • pip package manager
  • Pemahaman dasar tentang machine learning
  • Familiar dengan scikit-learn atau framework ML lainnya

Instalasi ZenML

Instalasi ZenML sangat mudah menggunakan pip:

pip install zenml

Untuk instalasi dengan integrasi tambahan:

pip install "zenml[server]"

Setelah instalasi, inisialisasi ZenML repository di project Anda:

zenml init

Jalankan ZenML dashboard secara lokal:

zenml login --local

Dashboard akan tersedia di http://127.0.0.1:8237 dan memberikan visualisasi lengkap pipeline, artifacts, dan stacks Anda.

Konsep Dasar: Steps dan Pipelines

Mendefinisikan Steps dengan @step

Step adalah unit kerja terkecil dalam ZenML. Setiap step adalah sebuah fungsi Python yang di-dekorasi dengan @step:

from zenml import step

import pandas as pd

@step

def loaddata() -> pd.DataFrame:

"""Memuat dataset dari sumber data."""

df = pd.readcsv("data/trainingdata.csv")

return df

@step

def preprocessdata(df: pd.DataFrame) -> pd.DataFrame:

"""Membersihkan dan memproses data."""

df = df.dropna()

df = df.dropduplicates()

return df

ZenML secara otomatis melakukan type checking dan serialization pada input/output setiap step berdasarkan type hints yang Anda berikan.

Mendefinisikan Pipeline dengan @pipeline

Pipeline menghubungkan beberapa steps menjadi alur kerja yang terstruktur:

from zenml import pipeline

@pipeline

def trainingpipeline():

"""Pipeline untuk training model ML."""

data = loaddata()

processeddata = preprocessdata(data)

model = trainmodel(processeddata)

metrics = evaluatemodel(model, processeddata)

return metrics

Menjalankan pipeline semudah memanggil fungsi:

if name == "main":

trainingpipeline()

Parameterisasi Steps

Anda bisa membuat steps yang menerima parameter konfigurasi:

from zenml import step

from pydantic import BaseModel

class TrainingConfig(BaseModel):

learningrate: float = 0.01

nestimators: int = 100

maxdepth: int = 5

@step

def trainmodel(

data: pd.DataFrame,

config: TrainingConfig = TrainingConfig()

) -> object:

"""Melatih model dengan konfigurasi yang dapat disesuaikan."""

from sklearn.ensemble import RandomForestClassifier

X = data.drop("target", axis=1)

y = data["target"]

model = RandomForestClassifier(

nestimators=config.nestimators,

maxdepth=config.maxdepth

)

model.fit(X, y)

return model

Artifacts dan Materializers

Memahami Artifacts

Setiap output dari step secara otomatis disimpan sebagai artifact. Artifact adalah data yang dihasilkan dan dikonsumsi oleh steps dalam pipeline. ZenML melacak setiap artifact dengan metadata lengkap termasuk versi, tipe, dan lineage.

from zenml import step, logartifactmetadata

@step

def trainmodel(data: pd.DataFrame) -> object:

model = RandomForestClassifier()

model.fit(Xtrain, ytrain)

logartifactmetadata(

artifactname="model",

metadata={

"accuracy": float(model.score(Xtest, ytest)),

"nfeatures": Xtrain.shape[1],

"algorithm": "RandomForest"

}

)

return model

Custom Materializers

Materializer mengontrol bagaimana artifact diserialisasi dan dideserialisasi. Anda bisa membuat custom materializer untuk tipe data khusus:

from zenml.materializers import BaseMaterializer

from zenml.enums import ArtifactType

import json

import os

class CustomModelMaterializer(BaseMaterializer):

ASSOCIATEDTYPES = (CustomModel,)

ASSOCIATEDARTIFACTTYPE = ArtifactType.MODEL

def load(self, datatype):

filepath = os.path.join(self.uri, "model.json")

with open(filepath, "r") as f:

data = json.load(f)

return CustomModel.fromdict(data)

def save(self, model):

filepath = os.path.join(self.uri, "model.json")

with open(filepath, "w") as f:

json.dump(model.todict(), f)

Stacks: Infrastruktur yang Modular

Konsep Stack

Stack adalah konfigurasi infrastruktur yang mendefinisikan di mana dan bagaimana pipeline dijalankan. Setiap stack terdiri dari beberapa komponen:

  • Orchestrator: Menjalankan pipeline (local, Airflow, Kubeflow, dll.)
  • Artifact Store: Menyimpan artifacts (local, S3, GCS, Azure Blob)
  • Experiment Tracker: Melacak eksperimen (MLflow, WandB, Neptune)
  • Model Deployer: Men-deploy model (MLflow, Seldon, BentoML)
  • Container Registry: Menyimpan Docker images
  • Step Operator: Menjalankan steps di environment khusus (SageMaker, Vertex AI)

Mengelola Stacks

# Melihat stack yang tersedia

zenml stack list

Mendaftarkan komponen baru

zenml artifact-store register mys3store \

--flavor=s3 \

--path=s3://my-bucket/zenml

zenml orchestrator register mykubeflow \

--flavor=kubeflow \

--kubernetescontext=my-cluster

Membuat stack baru

zenml stack register productionstack \

--orchestrator=mykubeflow \

--artifact-store=mys3store

Mengaktifkan stack

zenml stack set productionstack

Stack Components Detail

Berikut contoh konfigurasi stack yang lebih lengkap:

# Registrasi experiment tracker MLflow

zenml experiment-tracker register mlflowtracker \

--flavor=mlflow \

--trackinguri=http://mlflow-server:5000

Registrasi model deployer

zenml model-deployer register mlflowdeployer \

--flavor=mlflow

Stack lengkap untuk production

zenml stack register fullstack \

--orchestrator=mykubeflow \

--artifact-store=mys3store \

--experiment-tracker=mlflowtracker \

--model-deployer=mlflowdeployer

Integrasi dengan MLflow dan Weights & Biases

Integrasi MLflow

Instal integrasi MLflow:

zenml integration install mlflow -y

Gunakan MLflow experiment tracker dalam step:

from zenml import step

from zenml.integrations.mlflow.flavors.mlflowexperimenttrackerflavor import (

MLFlowExperimentTrackerSettings

)

import mlflow

mlflowsettings = MLFlowExperimentTrackerSettings(

experimentname="myexperiment"

)

@step(

experimenttracker="mlflowtracker",

settings={"experimenttracker": mlflowsettings}

)

def trainwithmlflow(data: pd.DataFrame) -> object:

mlflow.autolog()

model = RandomForestClassifier(nestimators=100)

model.fit(Xtrain, ytrain)

accuracy = model.score(Xtest, ytest)

mlflow.logmetric("accuracy", accuracy)

mlflow.logparam("nestimators", 100)

return model

Integrasi Weights & Biases

zenml integration install wandb -y

from zenml.integrations.wandb.flavors.wandbexperimenttrackerflavor import (

WandbExperimentTrackerSettings

)

import wandb

wandbsettings = WandbExperimentTrackerSettings(

project="my-zenml-project",

entity="my-team"

)

@step(

experimenttracker="wandbtracker",

settings={"experimenttracker": wandbsettings}

)

def trainwithwandb(data: pd.DataFrame) -> object:

config = {"nestimators": 100, "maxdepth": 5}

wandb.config.update(config)

model = RandomForestClassifier(*config)

model.fit(Xtrain, ytrain)

wandb.log({"accuracy": model.score(Xtest, ytest)})

return model

Model Deployment

ZenML mendukung deployment model melalui berbagai deployer:

from zenml import step, pipeline

from zenml.integrations.mlflow.steps import mlflowmodeldeployerstep

@step

def deploymenttrigger(accuracy: float) -> bool:

"""Menentukan apakah model layak di-deploy."""

return accuracy > 0.85

@pipeline

def deploymentpipeline():

data = loaddata()

processed = preprocessdata(data)

model = trainmodel(processed)

accuracy = evaluatemodel(model, processed)

shoulddeploy = deploymenttrigger(accuracy)

if shoulddeploy:

mlflowmodeldeployerstep(

model=model,

deploydecision=shoulddeploy,

workers=3

)

Caching

ZenML secara default mengaktifkan caching untuk setiap step. Jika input dan kode step tidak berubah, ZenML akan menggunakan hasil sebelumnya:

# Menonaktifkan caching untuk step tertentu

@step(enablecache=False)

def alwaysfreshdata() -> pd.DataFrame:

"""Step ini selalu dijalankan ulang."""

return pd.readcsv("livedata.csv")

Menonaktifkan caching untuk seluruh pipeline

@pipeline(enablecache=False)

def nocachepipeline():

data = alwaysfreshdata()

process(data)

Caching sangat berguna untuk menghemat waktu dan resource saat melakukan iterasi pada bagian tertentu dari pipeline.

Pipeline Scheduling

ZenML mendukung penjadwalan pipeline secara periodik:

from zenml.config.schedule import Schedule

Jadwalkan pipeline untuk berjalan setiap hari

schedule = Schedule(

cronexpression="0 8 " # Setiap hari jam 8 pagi

)

trainingpipeline = trainingpipeline.withoptions(

schedule=schedule

)

trainingpipeline()

Anda juga bisa menjadwalkan dengan interval:

from datetime import timedelta

schedule = Schedule(

intervalsecond=timedelta(hours=6),

starttime="2026-01-01T00:00:00"

)

ZenML Dashboard

ZenML menyediakan dashboard web yang powerful untuk monitoring:

# Login ke ZenML server

zenml login --local

Atau koneksi ke remote server

zenml login https://my-zenml-server.com

Dashboard menyediakan:

  • Pipeline Runs: Visualisasi DAG pipeline dan status setiap step
  • Artifacts: Browser untuk melihat semua artifact yang dihasilkan
  • Stacks: Manajemen stack dan komponen infrastruktur
  • Model Registry: Tracking model versions dan deployment status

Contoh Praktis: Pipeline ML End-to-End

Berikut contoh lengkap pipeline dari data ingestion hingga deployment:

import pandas as pd

import numpy as np

from sklearn.modelselection import traintestsplit

from sklearn.preprocessing import StandardScaler, LabelEncoder

from sklearn.ensemble import RandomForestClassifier

from sklearn.metrics import accuracyscore, classificationreport

from zenml import step, pipeline, logartifactmetadata, ArtifactConfig

from zenml.client import Client

from typing import Tuple

from typingextensions import Annotated

from pydantic import BaseModel

Konfigurasi

class ModelConfig(BaseModel):

testsize: float = 0.2

nestimators: int = 200

maxdepth: int = 10

randomstate: int = 42

minaccuracy: float = 0.85

Step 1: Data Ingestion

@step

def ingestdata() -> Annotated[pd.DataFrame, "rawdata"]:

"""Mengambil data dari sumber."""

from sklearn.datasets import loadiris

iris = loadiris(asframe=True)

df = iris.frame

df.columns = ["sepallength", "sepalwidth",

"petallength", "petalwidth", "target"]

logartifactmetadata(

artifactname="rawdata",

metadata={

"numrows": len(df),

"numcolumns": len(df.columns),

"columns": list(df.columns)

}

)

return df

Step 2: Data Preprocessing

@step

def preprocess(

df: pd.DataFrame,

config: ModelConfig = ModelConfig()

) -> Tuple[

Annotated[np.ndarray, "Xtrain"],

Annotated[np.ndarray, "Xtest"],

Annotated[np.ndarray, "ytrain"],

Annotated[np.ndarray, "ytest"],

Annotated[StandardScaler, "scaler"]

]:

"""Preprocessing: split, scale, encode."""

X = df.drop("target", axis=1).values

y = df["target"].values

Xtrain, Xtest, ytrain, ytest = traintestsplit(

X, y,

testsize=config.testsize,

randomstate=config.randomstate,

stratify=y

)

scaler = StandardScaler()

Xtrain = scaler.fittransform(Xtrain)

Xtest = scaler.transform(Xtest)

return Xtrain, Xtest, ytrain, ytest, scaler

Step 3: Model Training

@step

def train(

Xtrain: np.ndarray,

ytrain: np.ndarray,

config: ModelConfig = ModelConfig()

) -> Annotated[RandomForestClassifier, "trainedmodel"]:

"""Melatih model RandomForest."""

model = RandomForestClassifier(

nestimators=config.nestimators,

maxdepth=config.maxdepth,

randomstate=config.randomstate,

njobs=-1

)

model.fit(Xtrain, ytrain)

logartifactmetadata(

artifactname="trainedmodel",

metadata={

"algorithm": "RandomForestClassifier",

"nestimators": config.nestimators,

"maxdepth": config.maxdepth

}

)

return model

Step 4: Model Evaluation

@step

def evaluate(

model: RandomForestClassifier,

Xtest: np.ndarray,

ytest: np.ndarray,

config: ModelConfig = ModelConfig()

) -> Annotated[float, "accuracy"]:

"""Mengevaluasi performa model."""

ypred = model.predict(Xtest)

accuracy = accuracyscore(ytest, ypred)

report = classificationreport(ytest, ypred, outputdict=True)

logartifactmetadata(

artifactname="accuracy",

metadata={

"accuracy": accuracy,

"precisionmacro": report["macro avg"]["precision"],

"recallmacro": report["macro avg"]["recall"],

"f1macro": report["macro avg"]["f1-score"]

}

)

print(f"Model Accuracy: {accuracy:.4f}")

print(classificationreport(ytest, ypred))

return accuracy

Step 5: Deployment Decision

@step

def decidedeployment(

accuracy: float,

config: ModelConfig = ModelConfig()

) -> Annotated[bool, "deploydecision"]:

"""Memutuskan apakah model layak di-deploy."""

shoulddeploy = accuracy >= config.minaccuracy

if shoulddeploy:

print(f"Model LAYAK deploy (accuracy: {accuracy:.4f} >= {config.minaccuracy})")

else:

print(f"Model TIDAK layak deploy (accuracy: {accuracy:.4f} < {config.minaccuracy})")

return shoulddeploy

Pipeline Definition

@pipeline

def mlpipeline():

"""Pipeline ML end-to-end."""

rawdata = ingestdata()

Xtrain, Xtest, ytrain, ytest, scaler = preprocess(rawdata)

model = train(Xtrain, ytrain)

accuracy = evaluate(model, Xtest, ytest)

deploydecision = decidedeployment(accuracy)

return deploydecision

Menjalankan pipeline

if name == "main":

run = mlpipeline()

print(f"Pipeline selesai! Run ID: {run.id}")

Best Practices

  • Gunakan Type Hints: Selalu definisikan type hints pada parameter dan return value step untuk memastikan ZenML bisa melakukan validasi dan serialization yang tepat.
  • Pisahkan Konfigurasi: Gunakan Pydantic BaseModel untuk konfigurasi agar mudah di-override dan di-track.
  • Manfaatkan Caching: Biarkan caching aktif untuk step yang tidak memerlukan data real-time.
  • Organisasi Kode: Pisahkan steps ke dalam modul terpisah berdasarkan fungsinya (ingestion, preprocessing, training, evaluation).
  • Logging Metadata: Selalu log metadata penting pada setiap artifact untuk memudahkan debugging dan tracking.
  • Environment Isolation: Gunakan Docker settings untuk memastikan reproducibility di semua environment.
  • from zenml.config import DockerSettings
    
    

    dockersettings = DockerSettings(

    requirements=["scikit-learn==1.3.0", "pandas==2.0.0"],

    requiredintegrations=["mlflow"]

    )

    @pipeline(settings={"docker": dockersettings})

    def reproducible_pipeline():

    ...

    Kesimpulan

    ZenML menyediakan framework yang elegan untuk membangun pipeline MLOps yang reproducible dan modular. Dengan konsep stacks yang fleksibel, Anda bisa dengan mudah beralih antara development lokal dan production di cloud tanpa mengubah kode pipeline. Integrasi yang luas dengan tools populer seperti MLflow dan Weights & Biases membuatnya menjadi pilihan yang solid untuk tim yang ingin menerapkan MLOps best practices.

    Fitur-fitur seperti caching otomatis, artifact tracking, dan pipeline scheduling menjadikan ZenML solusi yang komprehensif untuk mengelola lifecycle machine learning dari eksperimen hingga production.

    Artikel Terkait

    Tutorial ClearML: Platform MLOps Open-Source untuk Experiment Tracking dan Pipeline Automation

    Tutorial ClearML: Platform MLOps Open-Source untuk Experiment Tracking dan Pipeline Automation ClearML adalah platform M...

    Tutorial Metaflow: Framework MLOps dari Netflix untuk Data Science

    Tutorial Metaflow: Framework MLOps dari Netflix untuk Data Science Metaflow adalah framework open-source yang dikembangk...

    Tutorial Kedro: Pipeline Data Science yang Reproducible dan Terstruktur

    Kedro: Pipeline Data Science yang Reproducible dan Mudah Dirawat Sebagian besar proyek data science dimulai dari satu no...

    Tutorial Lengkap Apache Airflow: Workflow Orchestration untuk Data Pipelines

    Tutorial Lengkap Apache Airflow: Workflow Orchestration untuk Data Pipelines Apache Airflow adalah platform open-source ...