Kubeflow Pipelines – 파이프 라인 UI에서 결과 시각화

소개

Kubeflow Pipelines UI는 기본적으로 여러 유형의 시각화를 제공하고 있습니다. 그래서 성능 평가 및 비교 데이터를 보여주기 위한 방법으로 사용할 수 있습니다. 이 시각화 기능은 출력 뷰어를 사용하고 있습니다. 컴포넌트의 결과물을 출력 뷰어를 이용하여 시각화 할 수 있는 것입니다. 출력 뷰어를 사용하려면, 파이프 라인 컴포넌트의 애플리케이션에서 JSON 파일을 로컬 파일 시스템에 저장하면 됩니다.

시각화된 출력 결과는 Kubeflow 파이프 라인 UI를 통해서 확인 할 수 있습니다. Artifacts 페이지와 , Run output 페이지에서 시각화된 출력 결과를 조회 할 수 있습니다.

Artifacts

Artifacts 탭에는 선택한 파이프 라인 단계의 시각화가 표시됩니다.

Kubeflow 파이프 라인 UI에서 Artifacts 탭을 열려면, 다음 절차대로 진행하시면 됩니다.

  1. Experiments 클릭하여 현재 파이프 라인 실험 목록을 조회합니다.
  2. 보려는 실험의 ‘실험 이름’을 클릭하십시오.
  3. 보려는 실행의 “실행 이름”을 클릭하십시오.
  4. Graph 탭에서 보려는 파이프 라인 컴포넌트를 나타내는 단계를 클릭하십시오. 세부 사항이 Artifacts  탭을 표시하며 슬라이드 됩니다.

Run output

Run output 탭에는 선택한 실행의 모든 ​​단계에 대한 시각화가 표시됩니다.

Kubeflow 파이프 라인 UI에서 Run output 탭을 열려면, 다음 절차대로 진행하시면 됩니다.

  1. Experiments 클릭하여 현재 파이프 라인 실험 목록을 조회합니다.
  2. 보려는 실험의 ‘실험 이름’을 클릭하십시오.
  3. 보려는 실행의 “실행 이름”을 클릭하십시오.
  4. Run output 탭을 클릭하십시오.

출력 뷰어를 위한 메타데이터 저장하기

파이프 라인 컴포넌트의 결과물을 출력 뷰어를 통해서 시각화 할 수 있습니다. 출력 뷰어를 통해서 결과물을 시각화 하려면, JSON 형태의 메타 데이터 파일을 로컬 저장소에 작성해야 합니다. 파일 이름은 /mlpipeline-ui-metadata.json 을 사용합니다.

JSON은 outputs 배열을 가지고 있습니다. 각 outputs 항목은 출력 뷰어의 메타 데이터를 설명합니다. JSON 구조는 다음과 같습니다.

{
  "version": 1,
  "outputs": [
    {
      "type": "confusion_matrix",
      "format": "csv",
      "source": "my-dir/my-matrix.csv",
      "schema": [
        {"name": "target", "type": "CATEGORY"},
        {"name": "predicted", "type": "CATEGORY"},
        {"name": "count", "type": "NUMBER"},
      ],
      "labels": "vocab"
    },
    {
      ...
    }
  ]
}

출력 뷰어의 메타 데이터에는 생성할 뷰어와 사용할 데이터에 대한 정의가 포함되어 있습니다.

Kubeflow Pipilines 시스템은 컴포넌트가 컨테이너 파일 시스템에 저장한 메타 데이터 파일을 읽어와서 Kubeflow Pipelines UI에서 지정한 뷰어를 생성합니다. Kubeflow Pipelines UI는 데이터를 메모리에 로드하여 렌더링합니다.

컴포넌트가 해당 메타데이터 파일을 컨테이너 파일 시스템에 쓰는 경우 Kubeflow Pipelines 시스템은 파일을 자동으로 Artifact 저장소에 저장합니다. Kubeflow Pipelines UI는 이 파일을 사용하여 지정된 뷰어를 생성합니다. 메타 데이터에는 Kubeflow Pipelines UI 가 아티팩트 데이터를 가져오기 위한 위치가 정의되어 있습니다. Kubeflow Pipelines UI는 데이터를 메모리에 가져와서 렌더링합니다.

주의 : Kubeflow Pipilines 0.3.0 버전에서 지원하는 아티팩터 데이터의 사용 가능한 위치는 Google Cloud Storage, Amazon S3, http https 입니다. 이슈 데이터를 정상적으로 가져오기 위해서는 Kubeflow Pipelines UI 에서 해당 아티팩터 데이터 위치로 접근할 수 있어야합니다. 그래서 설치 환경에 따라서 별도의 접근 권한을 Kubeflow Pipelines UI 에 부여해줘야 할 수도 있습니다.

다음 표는 outputs 배열에서 지정할 수 있는 메타 데이터 필드입니다. 각 output 항목에는 type이 있어야합니다. type 값에 따라 사용하는 필드 값은 약간 다를 수 있습니다.나중에 페이지의 출력 뷰어 목록에 설명 된대로 다른 필드가 필요할 수도 있습니다.

outputs

필드 이름설명
format아티팩트 데이터의 형식입니다. 기본값은 csv입니다. (현재 사용 가능한 유일한 형식은 csv입니다.)
header아티팩터 데이터의 헤더로 사용될 문자열 목록입니다. 예를 들어, 테이블에서 이 문자열은 첫 번째 행에서 사용됩니다.
labels이슈 열 또는 행의 레이블로 사용되는 문자열 목록입니다.
predicted_col예측 열의 이름입니다.
schema아티팩트 데이터의 스키마를 지정하는 {type, name} 객체의 목록입니다.
source데이터의 전체 경로입니다. 사용 가능한 위치에는 http, https, Amazon S3 및 Google Cloud Storage가 포함됩니다. 경로에는 와일드 카드 ‘*’가 포함될 수 있으며,이 경우 Kubeflow Pipelines UI는 일치하는 소스 파일의 데이터를 연결합니다. source는 인라인 문자열 데이터도 포함 할 수 있습니다. storage 이 inline일 때 경로 대신 문자열 데이터를 포함합니다.
storagestorage 가 inline 인 경우 source값이 위치 대신 인라인 데이터로 사용 됩니다. 이것은 텐서 보드를 제외한 모든 유형의 출력에 적용됩니다.
target_col대상 열의 이름입니다.
type데이터를 시각화하는 데 사용되는 뷰어의 이름입니다. 아래 목록은 사용 가능한 유형을 보여줍니다.

사용 가능한 출력 뷰어

Kubeflow Pipelines 에서 제공하고 있는 출력 뷰어는 다음과 같습니다.

  • Confusion matrix
  • Markdown
  • ROC curve
  • Table
  • TensorBoard
  • Web app

사용 가능한 뷰어 유형과 각 유형에 필요한 메타 데이터 필드에 대해 알아보도록 하겠습니다.

출력 뷰어 사용하기

사용 가능한 뷰어 유형과 각 유형에 필요한 메타 데이터 필드에 대해 알아보도록 하겠습니다.

Confusion matrix

분류결과표(Confusion Matrix)는 대상의 원래 클래스와 모델이 예측한 클래스가 일치 하는 경우의 개수를 세어서, 그 결과를 표나 나타낸 것입니다. 정답 클래스는 행(row)으로 예측한 클래스는 열(column)로 나타냅니다.

타입: confusion_matrix

메타 데이터 필수 필드 :

  • format
  • labels
  • schema
  • source

메타 데이터 선택 필드 :

  • storage

뷰어는 다음 위치에서 분류 결과 데이터를 읽을 수 있습니다

  • source 필드에 포함 된 분류 결과 형식의 문자열입니다. storage 필드의 값은 inline 이어야 합니다.
  • source 필드에 지정한 경로의 원격 파일에 분류 결과를 읽어옵니다.. storage 필드는 비어 있거나 inline을 제외한 모든 값을 포함 할 수 있습니다.

confusion_matrix 뷰어는 데이터 구문을 분석하기 위해 schema에 정의된 값들을 사용합니다. labels은 x 및 y 축에 나타낼 클래스 이름입니다.

Example:

	metadata = {
    'outputs' : [
    # Confustion matrix that is hardcoded inline
    {
      'type': 'confusion_matrix',
      'format': 'csv',
      'schema': [
        {'name': 'target', 'type': 'CATEGORY'},
        {'name': 'predicted', 'type': 'CATEGORY'},
        {'name': 'count', 'type': 'NUMBER'},
      ],
      'source': <CONFUSION_MATRIX_CSV_INLINE>
			'storage': 'inline',
      'labels': list(map(str, vocab)),
    },
    # Confustion matrix that is read from a file
		{
      'type': 'confusion_matrix',
      'format': 'csv',
      'schema': [
        {'name': 'target', 'type': 'CATEGORY'},
        {'name': 'predicted', 'type': 'CATEGORY'},
        {'name': 'count', 'type': 'NUMBER'},
      ],
      'source': <CONFUSION_MATRIX_CSV_FILE>,
      'labels': list(map(str, vocab)),
    }]
  }
  with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

파이프 라인을 구성하고 실행하기

분류결과표(Confusion Matrix)는 출력하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, sklearn을 사용한 간단한 분류결과표 프로그램 코드를 작성합니다. confusion_matrix() 메소드를 사용하여 분류결과표를 만들고, csv 형태의 파일로 저장하기 위해서 데이터를 가공합니다. 예제에서는 데이터를 외부 저장소에 저장하지 않고 inline 으로 사용하기 위해서, 저장한 csv 데이터를 다시 문자열로 읽어온 후, 메타데이터의 source 의 필드에 저장합니다. 만약 외부 저장소를 사용하고 싶으면, storage 필드를 삭제하고, source 필드에 저장할 곳의 위치를 지정하면 됩니다.

다음은 프로그램의 전체 코드입니다.

src/confusion_matrix.py

import json
import os

import pandas as pd
from sklearn.metrics import confusion_matrix

y_target = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]

vocab = [0, 1, 2]

cm = confusion_matrix(y_target, y_pred, labels=vocab)

data = []
for target_index, target_row in enumerate(cm):
    for predicted_index, count in enumerate(target_row):
        data.append((vocab[target_index], vocab[predicted_index], count))

df_cm = pd.DataFrame(data, columns=['target', 'predicted', 'count'])

output = '.'
cm_file = os.path.join(output, 'confusion_matrix.csv')
with open(cm_file, 'w') as f:
    df_cm.to_csv(f, columns=['target', 'predicted', 'count'], header=False, index=False)

lines = ''
with open(cm_file, 'r') as f:
    lines = f.read()

metadata = {
    'outputs': [{
            'type': 'confusion_matrix',
            'format': 'csv',
            'schema': [
                {'name': 'target', 'type': 'CATEGORY'},
                {'name': 'predicted', 'type': 'CATEGORY'},
                {'name': 'count', 'type': 'NUMBER'},
            ],
            'source': lines,
            'storage': 'inline',
            'labels': list(map(str, vocab)),
        }]
}

with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM python:3.6.10-slim

RUN pip install sklearn pandas

COPY ./src /app
WORKDIR /app

	CMD ["python", "/app/confusion_matrix.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-confusion-matrix:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-confusion-matrix:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

dsl.ContainerOp(
    name='confusion-matrix',
    image='kangwoo/kfp-confusion-matrix:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl

def confusion_matrix_pipeline():
  dsl.ContainerOp(
    name='confusion-matrix',
    image='kangwoo/kfp-confusion-matrix:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )


if __name__ == '__main__':
    arguments = {}
    my_run = kfp.Client().create_run_from_pipeline_func(confusion_matrix_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 confusion_matrix 화면입니다.


Markdown

마크 다운 뷰어는 Kubeflow 파이프 라인 UI에서 마크 다운 문자열을 렌더링합니다.

타입 : markdown

메타 데이터 필수 필드 :

  • source

메타 데이터 선택 필드 :

  • storage :

뷰어는 다음 위치에서 마크 다운 데이터를 읽을 수 있습니다

  • source 필드에 포함 된 마크 다운 형식 문자열입니다. storage 필드의 값은 inline 이어야 합니다.
  • source 필드에 지정한 경로에서 원격 파일의 마크 다운 코드. storage 필드는 비어 있거나 inline을 제외한 모든 값을 포함 할 수 있습니다.

Example:

	metadata = {
    'outputs' : [
    # Markdown that is hardcoded inline
    {
      'storage': 'inline',
      'source': '# Inline Markdown\\n[A link](<https://www.kubeflow.org/>)',
      'type': 'markdown',
    },
    # Markdown that is read from a file
    {
      'source': 'gs:///your_bucket/your_markdown_file',
      'type': 'markdown',
    }]
  }
  with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

파이프 라인을 구성하고 실행하기

마크 다운을 출력하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, 마크 다운을 저장하는 프로그램 코드를 작성합니다. 예제에서는 데이터를 외부 저장소에 저장하지 않고 inline 으로 사용하기 위해서, 저장한 csv 데이터를 다시 문자열로 읽어온 후, 메타데이터의 source 의 필드에 저장합니다. 만약 외부 저장소를 사용하고 싶으면, storage 필드를 삭제하고, source 필드에 저장할 곳의 위치를 지정하면 됩니다.

다음은 프로그램의 전체 코드입니다.

src/markdown.py

import json

metadata = {
    'outputs': [{
            'storage': 'inline',
            'source': '# Inline Markdown\\n[A link](<https://www.kubeflow.org/>)',
            'type': 'markdown',
        }]
}

with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM python:3.6.10-slim

COPY ./src /app
WORKDIR /app

CMD ["python", "/app/markdown.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-markdown:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-markdown:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

dsl.ContainerOp(
    name='markdown',
    image='kangwoo/kfp-markdown:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl


def markdown_pipeline():
  dsl.ContainerOp(
    name='markdown',
    image='kangwoo/kfp-markdown:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )


if __name__ == '__main__':
    arguments = {}
    my_run = kfp.Client().create_run_from_pipeline_func(markdown_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 markdown 화면입니다.


ROC curve

ROC(Receiver Operator Characteristic) 곡선은 클래스 판별 기준값의 변화에 따른 위양성률(fall-out)과 재현율(recall)의 변화를 시각화한 것이다. 위양성율(fall-out)은 실제 양성 클래스에 속하지 않는 표본 중에 양성 클래스에 속한다고 출력한 표본의 비율을 뜻합니다. 위양성율은 FPR(false positive rate)라고도 합니다. 재현율(recall)은 실제 양성 클래스에 속한 표본 중에 양성 클래스에 속한다고 출력한 표본의 비율을 뜻합니다. 재현율은 TPR(true positive rate)라고도 합니다. 위양성률(fall-out)과 재현율(recall)은 일반적으로 양의 상관 관계가 있습니다.

타입 : roc

메타 데이터 필수 필드 :

  • format
  • schema
  • source

메타 데이터 선택 필드 :

  • storage

뷰어는 다음 위치에서 데이터를 읽을 수 있습니다

  • source 필드에 포함 된 ROC 곡선 형식의 문자열입니다. storage 필드의 값은 inline 이어야 합니다.
  • source 필드에 지정한 경로의 원격 파일에 분류 결과를 읽어옵니다. storage 필드는 비어 있거나 inline을 제외한 모든 값을 포함 할 수 있습니다.

Example:

	metadata = {
    'outputs': [
    # Roc that is hardcoded inline
    {
      'type': 'roc',
      'format': 'csv',
      'schema': [
        {'name': 'fpr', 'type': 'NUMBER'},
        {'name': 'tpr', 'type': 'NUMBER'},
        {'name': 'thresholds', 'type': 'NUMBER'},
      ],
      'source': <ROC_CSV_INLINE>
			'storage': 'inline',      
    },
    # Roc that is read from a file
		{
      'type': 'roc',
      'format': 'csv',
      'schema': [
        {'name': 'fpr', 'type': 'NUMBER'},
        {'name': 'tpr', 'type': 'NUMBER'},
        {'name': 'thresholds', 'type': 'NUMBER'},
      ],
      'source': <ROC_CSV_FILE>
    }]
  }
  with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

파이프 라인을 구성하고 실행하기

ROC(Receiver Operator Characteristic) 곡선을 출력하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, sklearn을 이용하여 ROC 곡선을 생성하는 프로그램 코드를 작성합니다. roc_curve() 메소드를 사용하여 ROC 곡선 만들고, csv 형태의 파일로 저장하기 위해서 데이터를 가공합니다. 예제에서는 데이터를 외부 저장소에 저장하지 않고 inline 으로 사용하기 위해서, 저장한 csv 데이터를 다시 문자열로 읽어온 후, 메타데이터의 source 의 필드에 저장합니다. 만약 외부 저장소를 사용하고 싶으면, storage 필드를 삭제하고, source 필드에 저장할 곳의 위치를 지정하면 됩니다.

다음은 프로그램의 전체 코드입니다.

src/roc.py

import json
import os

import pandas as pd
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve

X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=5)

model = LogisticRegression().fit(X, y)
y_hat = model.predict(X)

fpr, tpr, thresholds = roc_curve(y, model.decision_function(X))

output = '.'
df_roc = pd.DataFrame({'fpr': fpr, 'tpr': tpr, 'thresholds': thresholds})
roc_file = os.path.join(output, 'roc.csv')
with open(roc_file, 'w') as f:
    df_roc.to_csv(f, columns=['fpr', 'tpr', 'thresholds'], header=False, index=False)

lines = ''
with open(roc_file, 'r') as f:
    lines = f.read()

metadata = {
    'outputs': [{
        'type': 'roc',
        'format': 'csv',
        'schema': [
            {'name': 'fpr', 'type': 'NUMBER'},
            {'name': 'tpr', 'type': 'NUMBER'},
            {'name': 'thresholds', 'type': 'NUMBER'},
        ],
        'source': lines,
        'storage': 'inline',
    }]
}
with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM python:3.6.10-slim

RUN pip install sklearn pandas

COPY ./src /app
WORKDIR /app

CMD ["python", "/app/roc.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-roc:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-roc:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

dsl.ContainerOp(
    name='roc',
    image='kangwoo/kfp-roc:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl


def roc_pipeline():
    dsl.ContainerOp(
        name='roc',
        image='kangwoo/kfp-roc:0.0.1',
        output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
    )


if __name__ == '__main__':
    arguments = {}
    my_run = kfp.Client().create_run_from_pipeline_func(roc_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 roc 화면입니다.

ROC 곡선을 볼 때, 커서를 ROC 곡선 위로 가져 가면 커서의 가장 가까운 fpr 및 tpr 값에 사용 된 thresholds 값을 볼 수 있습니다.


Table

table 뷰어는 지정된 소스 경로의 데이터에서 HTML 테이블을 작성합니다. 여기서 헤더 필드는 테이블의 첫 번째 행에 표시 될 값을 지정합니다. 테이블은 페이징 기능을 지원합니다.

타입 : table

메타 데이터 필수 필드 :

  • format
  • header
  • source

메타 데이터 선택 필드 :

  • storage

뷰어는 다음 위치에서 데이터를 읽을 수 있습니다

  • source 필드에 포함 된 데이터 문자열입니다. storage 필드의 값은 inline 이어야 합니다.
  • source 필드에 지정한 경로의 원격 파일에 분류 결과를 읽어옵니다. storage 필드는 비어 있거나 inline을 제외한 모든 값을 포함 할 수 있습니다.

Example:

	metadata = {
    'outputs' : [
    # Table that is hardcoded inline
    {
      'type': 'table',
      'format': 'csv',
      'header': [x['name'] for x in schema],
      'source': <TABLE_CSV_INLINE>
			'storage': 'inline',
    },
    # Table that is read from a file
		{
      'type': 'table',
      'format': 'csv',
      'header': [x['name'] for x in schema],
      'source': <TABLE_CSV_FILE>
    }]
  }
  with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

파이프 라인을 구성하고 실행하기

테이블을 출력하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, 테이블을 생성하는 프로그램 코드를 작성합니다. 테이블롤 출력할 데이터를 만든 후, csv 형태의 파일로 저장하기 위해서 데이터를 가공합니다. 예제에서는 데이터를 외부 저장소에 저장하지 않고 inline 으로 사용하기 위해서, 저장한 csv 데이터를 다시 문자열로 읽어온 후, 메타데이터의 source 의 필드에 저장합니다. 만약 외부 저장소를 사용하고 싶으면, storage 필드를 삭제하고, source 필드에 저장할 곳의 위치를 지정하면 됩니다.

다음은 프로그램의 전체 코드입니다.

src/table.py

import json
import os

import pandas as pd
from sklearn.metrics import classification_report

y_true = [1, 0, 1, 1, 0, 1]
y_pred = [0, 1, 1, 0, 0, 1]

target_names = ['class 0', 'class 1']
report = classification_report(y_true, y_pred, target_names=target_names, output_dict=True)
print(report)

df_report = pd.DataFrame(report).transpose()

output = '.'
table_file = os.path.join(output, 'table.csv')
with open(table_file, 'w') as f:
    df_report.to_csv(f, header=False)

lines = ''
with open(table_file, 'r') as f:
    lines = f.read()

metadata = {
    'outputs': [{
        'type': 'table',
        'format': 'csv',
        'header': [''] + [x for x in df_report],
        'source': lines,
        'storage': 'inline',
    }]
}

with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM python:3.6.10-slim

RUN pip install sklearn pandas

COPY ./src /app
WORKDIR /app

CMD ["python", "/app/table.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-table:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-table:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

dsl.ContainerOp(
    name='table',
    image='kangwoo/kfp-table:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl


def table_pipeline():
  dsl.ContainerOp(
    name='table',
    image='kangwoo/kfp-table:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )


if __name__ == '__main__':
    arguments = {}
    my_run = kfp.Client().create_run_from_pipeline_func(table_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 table 화면입니다.

TensorBoard

tensorboard 뷰어는 Start Tensorboard 버튼을 출력 페이지에 추가합니다.

타입 : tensorboard

메타 데이터 필수 필드 :

  • source

출력 페이지에서 다음을 수행 할 수 있습니다.

  • Start Tensorboard 을 클릭하면, Kubeflow 클러스터에 Tensorboard 인스턴스가 시작됩니다. Tensorboard 포드가 실행되면, 버튼 텍스트가Open Tensorboard 로 전환됩니다.
  • Open Tensorboard 를 클릭하면 source 필드에 지정한 logdir 데이터를 읽어오는 TensorBoard 화면에 접속 할 수 있습니다..
  • Delete Tensorboard 을 클릭하면, Tensorboard 인스턴스가 종료됩니다.

Kubeflow Pipelines UI는 TensorBoard 인스턴스를 완전히 관리하지 않습니다. Start Tensorboard  버튼은 편리한 기능이므로 파이프 라인 실행을 볼 때 워크 플로우를 중단 할 필요가 없습니다. Kubernetes 관리 도구를 사용하여 TensorBoard 포드를 재활용하거나 삭제해야합니다.

Example:

	metadata = {
    'outputs' : [{
      'type': 'tensorboard',
      'source': <TENSORBOARD_PATH>,
    }]
  }
  with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

외부 저장소 설정 하기

tensorboard 뷰어는 텐서보드를 실행할 수 있는 버튼을 제공하고 있습니다. 버튼을 클릭하면 텐서보드가 실행이 됩니다. 이때 실행되는 텐서보드는 텐서플로우의 로그가 저장된 위치에 접근할 수 있어야합니다. 그래서 텐서보드가 지원하는 형태의 외부 저장소가 필요합니다.

예제에서는 kubeflow와 함께 설치된 minio를 S3 호환 저장소로 사용하겠습니다. 만약 별도의 저장소를 사용하고 있다면, 외부 저장소 설정 하기는 넘어가도 됩니다.

가. minio에 사용할 버킷을 생성하겠습니다.

버킷을 생성하기 위해서 minio에 접속해야합니다.

다음 명령어를 실행하면, minio의 서비스 정보를 조회할 수 있습니다.

kubectl -n kubeflow get service minio-service

정상적으로 실행되면, 다음과 같은 결과를 확인 할 수 있습니다.

NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
minio-service   ClusterIP   10.103.56.47   <none>        9000/TCP   15d

로컬 환경에서 minio에 접속하기 위해서 port-forward 를 실행합니다.

kubectl -n kubeflow port-forward svc/minio-service 9000:9000

포트 포워딩이 실행되면, 다음과 같은 결과를 확인 할 수 있습니다.

Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000

웹브라이저를 실행시켜서 http://localhost:9000/ 으로 접속합니다.

정상적으로 접속되면, 로그인 화면을 확인 할 수 있습니다.

AccessKey 와 Secret Key 를 입력합니다. 기본 값을 minio / minio123 입니다.

로그인 되면 다음과 같은 화면을 볼 수 있습니다.

화면 오른쪽 하단의 + 버튼을 누른 후, “Create bucket”을 눌러서 버킷을 생성합니다.

예제서 사용할 버컷의 이름은 tensorboard 입니다.

나. 텐서보드가 s3에 접근할 수 있도록 인증 정보를 설정하겠습니다.

s3에 접근 하기위한 AccessKey와 SecretKey 정보를 쿠버네티스의 Secret 리소스로 저장하겠습니다.

다음 명령어를 실행하면 시크릿 리소스가 생성됩니다.

export AWS_ACCESS_KEY_ID=minio
export AWS_SECRET_ACCESS_KEY=minio123

kubectl -n kubeflow create secret generic ml-pipeline-aws-secret \\
    --from-literal=accesskey=$AWS_ACCESS_KEY_ID \\
    --from-literal=secretkey=$AWS_SECRET_ACCESS_KEY

텐서보드가 실행될때 s3에 접근할 수 있도록, s3 설정 정보를 쿠버네티스 ConfigMap 리소스로 저장하겠습니다. 중요한 정보인 AWS_ACCESS_KEY_ID 와 AWS_SECRET_ACCESS_KEY 는 앞서 생성한 Secret 리소스에서 가져오게 되어있습니다.

viewer-tensorboard-template-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: ml-pipeline-ui-viewer-template
data:
  viewer-tensorboard-template.json: |
    {
        "spec": {
            "containers": [
                {
                    "env": [
                        {
                            "name": "AWS_ACCESS_KEY_ID",
                            "valueFrom": {
                                "secretKeyRef": {
                                    "name": "ml-pipeline-aws-secret",
                                    "key": "accesskey"
                                }
                            }
                        },
                        {
                            "name": "AWS_SECRET_ACCESS_KEY",
                            "valueFrom": {
                                "secretKeyRef": {
                                    "name": "ml-pipeline-aws-secret",
                                    "key": "secretkey"
                                }
                            }
                        },
                        {
                            "name": "S3_ENDPOINT",
                            "value": "minio-service.kubeflow.svc.cluster.local:9000"
                        },
                        {
                            "name": "AWS_ENDPOINT_URL",
                            "value": "<http://minio-service.kubeflow.svc.cluster.local:9000>"
                        },
                        {
                            "name": "AWS_REGION",
                            "value": "us-east-1"
                        },
                        {
                            "name": "S3_USE_HTTPS",
                            "value": "0"
                        },
                        {
                            "name": "S3_VERIFY_SSL",
                            "value": "0"
                        }
                    ]
                }
            ]
        }
    }

다음 명령어를 실행하여, ml-pipeline-ui-viewer-template ConfigMap을 생성합니다.

kubectl -n kubeflow create -f viewer-tensorboard-template-configmap.yaml

다. 이제 생성한 ConfigMap을 사용할 수 있도록, ml-pipeline-ui 의 설정 정보를 변경하도록 하겠습니다.

다음 명령어를 실행하여 ml-pipeline-ui 디플로이먼트를 수정합니다.

kubectl -n kubeflow edit deployment ml-pipeline-ui

생성한 ConfigMap 을 볼륨으로 마운트 해 줍니다.

...
        volumeMounts:
        - mountPath: /etc/config
          name: config-volume
...
     volumes:
      - configMap:
          defaultMode: 420
          name: ml-pipeline-ui-viewer-template
        name: config-volume

마운트한 볼륨에 있는 viewer-tensorboard-template.json 파일을 VIEWER_TENSORBOARD_POD_TEMPLATE_SPEC_PATH 라는 환경 변수를 지정해 줍니다.

      containers:
      - env:
        - name: VIEWER_TENSORBOARD_POD_TEMPLATE_SPEC_PATH
          value: /etc/config/viewer-tensorboard-template.json

다음은 변경한 ml-pipeline-ui 디플로이먼트 매니페스트의 일부분 입니다.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
...
  name: ml-pipeline-ui
  namespace: kubeflow
...
spec:
...
  template:
...
    spec:
      containers:
      - env:
        - name: VIEWER_TENSORBOARD_POD_TEMPLATE_SPEC_PATH
          value: /etc/config/viewer-tensorboard-template.json
...
        image: gcr.io/ml-pipeline/frontend:0.3.0
        imagePullPolicy: IfNotPresent
        name: ml-pipeline-ui
...
        volumeMounts:
        - mountPath: /etc/config
          name: config-volume
...
      dnsPolicy: ClusterFirst
...
      volumes:
      - configMap:
          defaultMode: 420
          name: ml-pipeline-ui-viewer-template
        name: config-volume
...

변경한 내용을 저장하면, 새로운 설정이 적용된 포드가 실행됩니다.

파이프 라인을 구성하고 실행하기

텐서보드 뷰어를 사용하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, 텐서플로우 로그 데이터를 저장하는 프로그램 코드를 작성합니다. 텐서플로우 케라스를 이용하여 mnist 이미지를 식별하는 모델을 생성합니다. 그리고 tf.keras.callbacks.TensorBoard 를 사용하여 학습할때 로그를 남깁니다. 그리고 Kubeflow Pipelines 에서 텐서보드 뷰어를 사용할 수 있도록 /mlpipeline-ui-metadata.json 파일에 메타데이터를 저장합니다.

다음은 프로그램의 전체 코드입니다.

src/tensorflow_mnist.py

from __future__ import absolute_import, division, print_function, unicode_literals

import argparse
import json

import tensorflow as tf


def train():
    parser = argparse.ArgumentParser()
    parser.add_argument('--tb_log_dir', default='./data/logs', type=str)
    args = parser.parse_args()

    tb_log_dir = args.tb_log_dir

    print("TensorFlow version: ", tf.__version__)

    mnist = tf.keras.datasets.mnist

    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    x_train, x_test = x_train / 255.0, x_test / 255.0

    model = tf.keras.models.Sequential([
        tf.keras.layers.Flatten(input_shape=(28, 28)),
        tf.keras.layers.Dense(128, activation='relu'),
        tf.keras.layers.Dropout(0.2),
        tf.keras.layers.Dense(10, activation='softmax')
    ])

    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

    model.summary()

    callbacks = [tf.keras.callbacks.TensorBoard(log_dir=tb_log_dir)]

    print("Training...")
    model.fit(x_train, y_train, epochs=5, validation_split=0.2, callbacks=callbacks)

    score = model.evaluate(x_test, y_test, batch_size=128)
    print('Test accuracy: ', score[1])

    metadata = {
        'outputs': [{
            'type': 'tensorboard',
            'source': tb_log_dir,
        }]
    }
    with open('/mlpipeline-ui-metadata.json', 'w') as f:
        json.dump(metadata, f)


if __name__ == '__main__':
    train()

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM tensorflow/tensorflow:2.1.0-py3

COPY ./src /app
WORKDIR /app


ENTRYPOINT ["python", "/app/tensorflow_mnist.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-tensorboard:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-tensorboard:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

텐서플로우가 실행되는 컴포트넌트에서 s3에 접근할 수 있도록, s3 설정 정보를 환경 변수로 넘겨 주었습니다.

s3_endpoint = 'minio-service.kubeflow.svc.cluster.local:9000'
    minio_endpoint = "http://" + s3_endpoint
    minio_username = "minio"
    minio_key = "minio123"
    minio_region = "us-east-1"

    dsl.ContainerOp(
        name='tensorboard',
        image='kangwoo/kfp-tensorboard:0.0.1',
        arguments=['--tb_log_dir', tb_log_dir],
        output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
    ).add_env_variable(V1EnvVar(name='S3_ENDPOINT', value=s3_endpoint)) \\
        .add_env_variable(V1EnvVar(name='AWS_ENDPOINT_URL', value=minio_endpoint)) \\
        .add_env_variable(V1EnvVar(name='AWS_ACCESS_KEY_ID', value=minio_username)) \\
        .add_env_variable(V1EnvVar(name='AWS_SECRET_ACCESS_KEY', value=minio_key)) \\
        .add_env_variable(V1EnvVar(name='AWS_REGION', value=minio_region)) \\
        .add_env_variable(V1EnvVar(name='S3_USE_HTTPS', value='0')) \\
        .add_env_variable(V1EnvVar(name='S3_VERIFY_SSL', value='0'))

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl

from kubernetes.client.models import V1EnvVar


def tensorboard_pipeline(tb_log_dir):
    s3_endpoint = 'minio-service.kubeflow.svc.cluster.local:9000'
    minio_endpoint = "http://" + s3_endpoint
    minio_username = "minio"
    minio_key = "minio123"
    minio_region = "us-east-1"

    dsl.ContainerOp(
        name='tensorboard',
        image='kangwoo/kfp-tensorboard:0.0.1',
        arguments=['--tb_log_dir', tb_log_dir],
        output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
    ).add_env_variable(V1EnvVar(name='S3_ENDPOINT', value=s3_endpoint)) \\
        .add_env_variable(V1EnvVar(name='AWS_ENDPOINT_URL', value=minio_endpoint)) \\
        .add_env_variable(V1EnvVar(name='AWS_ACCESS_KEY_ID', value=minio_username)) \\
        .add_env_variable(V1EnvVar(name='AWS_SECRET_ACCESS_KEY', value=minio_key)) \\
        .add_env_variable(V1EnvVar(name='AWS_REGION', value=minio_region)) \\
        .add_env_variable(V1EnvVar(name='S3_USE_HTTPS', value='0')) \\
        .add_env_variable(V1EnvVar(name='S3_VERIFY_SSL', value='0'))


if __name__ == '__main__':
    arguments = {'tb_log_dir': 's3://tensorboard/mnist'}
    my_run = kfp.Client().create_run_from_pipeline_func(tensorboard_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 tensorboard 화면입니다.

구동하면 싶은 텐서보드의 버전을 선택할 수 있습니다. “Start Tensorboard”를 클릭하면 텐서보드가 실행됩니다.

텐서보드가 실행되면 버튼이 “Open Tensorboard”로 바뀝니다. “Open Tensorboard” 버튼을 클릭하면 텐서보드 화면으로 접속할 수 있습니다.

다음은 텐서보드 접속 화면입니다.


Web app

web-app 뷰어는 사용자 정의 출력을 렌더링 할 수있는 유연성을 제공합니다.

타입 : web-app

메타 데이터 필수 필드 :

  • source

메타 데이터 선택 필드 :

  • storage

뷰어는 다음 위치에서 데이터를 읽을 수 있습니다

  • source 필드에 포함 된 데이터 문자열입니다. storage 필드의 값은 inline 이어야 합니다.
  • source 필드에 지정한 경로의 원격 파일에 분류 결과를 읽어옵니다. storage 필드는 비어 있거나 inline을 제외한 모든 값을 포함 할 수 있습니다.

컴포넌트가 생성하는 HTML 파일을 지정할 수 있습니다. Kubeflow Pipelines UI는 해당 HTML을 출력 페이지에서 렌더링합니다. HTML 파일은 파일 시스템의 다른 파일에 대한 참조가 없어야 합니다. HTML 파일에는 웹 파일에 대한 절대 참조가 포함될 수 있습니다. web-app 내에서 실행되는 콘텐츠는 iframe에서 샌드박스 처리되며 Kubeflow Pipelines UI와 통신 할 수 없습니다.

Example:

static_html_path = os.path.join(output_dir, _OUTPUT_HTML_FILE)
  file_io.write_string_to_file(static_html_path, rendered_template)

  metadata = {
    'outputs' : [
    # Web app that is hardcoded inline
    {
      'type': 'web-app',
      'storage': 'inline',
      'source': <STATIC_HTML_INLINE>,
    },
    # Web app  that is read from a file
		{
      '
      'type': 'web-app',
      'source': <STATIC_HTML_PATH>,
    }]
  }
  with file_io.FileIO('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

파이프 라인을 구성하고 실행하기

web-app을 출력하는 파이프 라인을 만들어 보겠습니다.

가. 프로그램 코드를 작성합니다.

컴포넌트를 만들기 위하여, HTML 생성하는 프로그램 코드를 작성합니다. 예제에서는 데이터를 외부 저장소에 저장하지 않고 inline 으로 사용하기 위해서, 저장한 csv 데이터를 다시 문자열로 읽어온 후, 메타데이터의 source 의 필드에 저장합니다. 만약 외부 저장소를 사용하고 싶으면, storage 필드를 삭제하고, source 필드에 저장할 곳의 위치를 지정하면 됩니다.

다음은 프로그램의 전체 코드입니다.

src/webapp.py

import json

metadata = {
    'outputs': [{
        'type': 'web-app',
        'storage': 'inline',
        'source': '<p><strong>Kubeflow pipelines</strong> are reusable end-to-end ML workflows built using the Kubeflow Pipelines SDK.</p>',
    }]
}

with open('/mlpipeline-ui-metadata.json', 'w') as f:
    json.dump(metadata, f)

나. 프로그램 코드가 포함된 컨테이너 이미지를 생성하고, 컨테이너 이미지 레지스트리에 업로드 합니다.

Dockerfile을 생성합니다.

Dockerfile

FROM python:3.6.10-slim

COPY ./src /app
WORKDIR /app

CMD ["python", "/app/webapp.py"]

컨테이너 이미지를 빌드하겠습니다.

docker build -t kangwoo/kfp-webapp:0.0.1 .

빌드한 컨테이너 이미지를 컨테이너 이미지 레지스트리에 업로드 합니다.

docker push kangwoo/kfp-webapp:0.0.1

다. Kubeflow Pipelines DSL을 사용하여 컴포넌트를 작성합니다. 컴포넌트에서 사용하는 컨테이너 이미지를 정의합니다. 그리고 output_artifact_paths 파라미터를 사용하여, 메트릭 파일이 저장된 경로를 지정해 줍니다.

  dsl.ContainerOp(
    name='webapp',
    image='kangwoo/kfp-webapp:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )

라. Kubeflow Pipelines DSL을 사용하여 파이프 라인 함수를 작성합니다. 파이프 라인을 정의하고 사용하는 컴포넌트들을 추가합니다. Kubeflow Pipelines SDK 를 사용하여 파이프라인을 빌드 한 후, 업로드하고 실행합니다.

import kfp
from kfp import dsl


def webapp_pipeline():
  dsl.ContainerOp(
    name='webapp',
    image='kangwoo/kfp-webapp:0.0.1',
    output_artifact_paths={'mlpipeline-ui-metadata': '/mlpipeline-ui-metadata.json'}
  )


if __name__ == '__main__':
    arguments = {}
    my_run = kfp.Client().create_run_from_pipeline_func(webapp_pipeline,
                                                        arguments=arguments,
                                                        experiment_name='Sample Experiment')

다음은 Kubeflow 파이프 라인 UI의 web-app 화면입니다.

“Kubeflow Pipelines – 파이프 라인 UI에서 결과 시각화”에 대한 3개의 댓글

  1. 제일 첫번째 파이프 라인 UI의 confusion_matrix 화면( MarkDown 바로위 화면) 의 artifact는 즉시 보이나요? 추가 설정이 필요한가요? 로딩이미지만 돌고 있어 문의드립니다.

    1. 바로 보이는게 맞습니다. inline 을 사용했는데도 로딩이미지만 돌고 있다면, KFP를 0.3으로 업그레이드 해 보시길 추천드립니다. 외부 저장소를 사용했을 경우에는 KFP의 UI에 접근 정보를 추가로 해 주셔야합니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다