Skip to main content
Version: 1.3

Pipeline 컨테이너 컴포넌트

시작하면서#

이번 장에서는 파이프라인 SDK에서 제공하는 ContainerOp 클래스를 활용하여 컨테이너 이미지를 컴포넌트로 만들고 컴포넌트에서 볼륨을 사용하는 방법에 대해 알아보도록 하겠습니다.

info

사용되는 코드는 아래 링크에서 보실 수 있습니다.
14.pipeline_container.ipynb


Goal#

  • 파이프라인 컨테이너 컴포넌트 사용법 숙지하기
  • 컴포넌트에서 볼륨 사용하기

컨테이너 컴포넌트#

파이프라인 SDK에서는 컨테이너 이미지를 이용해 컴포넌트를 만들 수 있는 kfp.dsl.ContainerOp 클래스를 제공합니다. 이를 이용하면 기존에 빌드되어 있는 컨테이너 이미지를 컴포넌트로 만들 수 있습니다.

앞선 튜토리얼에서 만들었던 fashion mnist 모델의 컨테이너 이미지를 컴포넌트로 만들어 보겠습니다. 이미지는 노트북의 모델을 컨테이너 이미지로 빌드하기에서 사용된 yourID/fashion-mnist-tuner:yourTAG 를 사용하겠습니다. 태그는 입력받을 수 있게 정의하겠습니다.

pipeline_container.ipynb
# pipeline_container.ipynb from kfp import dsl
@dsl.pipeline(name='fashion mnist train')def fashion_mnist_pipeline(tag: str):
    train_op = dsl.ContainerOp(name='fashion-mnist',                      image=f'yourID/fashion-mnist-tuner:{tag}') #자신의 이미지로 변경    arguments = {'tag': 'yourTAG'}client.create_run_from_pipeline_func(fashion_mnist_pipeline,                                      arguments=arguments)  

코드가 완성되면 RUN으로 실행합니다.

fashion_mnist_pipeline

Logs 탭에서 정상적으로 학습이 진행되는 것을 알 수 있습니다.
자, 이제 좀 더 쓸모있는 컴포넌트가 되기 위해 컴포넌트에 텐서보드 로그 볼륨을 붙여보도록 하겠습니다.


컴포넌트 볼륨#

기존의 볼륨을 붙여보기#

파이프라인 SDK에서는 기존에 생성된 볼륨을 사용할 수 있게 kfp.dsl.PipelineVolume 클래스를 제공합니다.

pipeline_container.ipynb
# pipeline_container.ipynb def fashion_mnist_pipeline(tag: str):notebook_vol = dsl.PipelineVolume(pvc="workspace-handson")...
  • pvc="workspace-handson" : 볼륨의 이름을 입력합니다. 여기서는 노트북서버의 볼륨인 handson의 볼륨을 입력하였습니다.
pipeline_container.ipynb
# pipeline_container.ipynb def fashion_mnist_pipeline(tag: str):train_op = dsl.ContainerOp(name="fashion-mnist",                image=f"yourID/fashion-mnist-tuner:{tag}", #자신의 이미지로 변경                pvolumes={"/notebook": notebook_vol})

이전 단계에서 만들었던 dsl.ContainerOp 에 방금 생성한 볼륨을 붙인 코드입니다.

  • pvolumes : 컨테이너 컴포넌트에서 해당 볼륨을 사용하기 위해서 pvolumes 라는 파라미터를 사용하며 dict 형태로 넣어주어야 합니다. 노트북의 볼륨이 train_op 의 /notebook에 마운트되어 실행됩니다.

아래는 전체 코드입니다.

pipeline_container.ipynb
# pipeline_container.ipynb import kfpfrom kfp import dsl
client=kfp.Client()
@dsl.pipeline(name="fashion mnist train")def fashion_mnist_pipeline(tag: str):    notebook_vol = dsl.PipelineVolume(pvc="workspace-handson")    train_op = dsl.ContainerOp(name="fashion-mnist",                  image=f"yourID/fashion-mnist-tuner:{tag}",                  pvolumes={"/notebook": notebook_vol})    arguments = {"tag": "yourTAG"}client.create_run_from_pipeline_func(fashion_mnist_pipeline,                                       arguments=arguments)     

실행하면, Volumes 탭에서 방금 추가한 볼륨의 정보를 확인 할 수 있습니다. fashion_mnist_pipeline_volume


VolumeOP로 볼륨 생성하기#

kfp.dsl.VolumeOp를 통해 볼륨 생성도 가능합니다.

볼륨은 하나의 컴포넌트로 생성됩니다. 아래는 1기가 용량의 볼륨을 생성하는 컴포넌트입니다.

pipeline_container.ipynb
# pipeline_container.ipynb @dsl.pipeline(name="fashion mnist train")def fashion_mnist_pipeline(tag: str):    notebook_vol = dsl.PipelineVolume(pvc="workspace-handson")    vop = dsl.VolumeOp(        name="volume_creation",        resource_name="mypvc",        size="1Gi"    )

train_op의 /result 라는 폴더로 마운트해보겠습니다. VolumeOp는 volume이라는 Attribute를 통해서 생성한 볼륨에 접근할 수 있습니다.

pipeline_container.ipynb
# pipeline_container.ipynb @dsl.pipeline(name="fashion mnist train")def fashion_mnist_pipeline(tag: str):    ...    train_op = dsl.ContainerOp(name="fashion-mnist",                   image=f"yourID/fashion-mnist-tuner:{tag}", #자신의 이미지로 변경                   pvolumes={"/notebook": notebook_vol,                                "/result": vop.volume})

코드를 실행하고 파이프라인 UI를 확인합니다.

fashion_mnist_pipeline

총 2개의 컴포넌트가 그래프로 연결됐으며 생성된 볼륨의 사이즈와 이름을 확인할 수 있습니다.


Caching#

caching_graph

컴포넌트를 실행시키면 완료 아이콘 ✅ 밑에 리로드 처럼 보이는 아이콘 🔄 이 있는 경우가 있습니다.
마우스를 올려보면 cache로 인해 실행이 무시되고 아웃풋도 cache에서 가져왔다고 메시지가 떠 있습니다.

output_from_cache

실제로 파이프라인의 아이디는 fashion-mnist-pipeline-cvfrp-623197360 이지만
Output artifacts의 main-logs의 파이프라인 실행 아이디는 fashion-mnist-pipeline-qh8lr-556903874 로 이전 파이프라인의 실행 결과를 보여주고 있습니다.

파이프라인이 아웃풋이 cache를 제공하기 때문에 컴포넌트가 이전 실행과 똑같은 설정(같은 베이스 이미지, 커맨드, 코드 등)을 가지고 실행된다면 해당 컴포넌트는 caching 되어 실행을 건너 뜁니다. 컴포넌트별 caching 정책에 맞게 실행 옵션애서 caching의 생명주기를 결정할 수 있습니다.

만약 caching의 생명주기를 30일로 하고싶다면 P30D라는 값으로 설정을 합니다.
caching이 필요없다면 P0D로 설정하면 됩니다.

examples
def some_pipeline():      # task is a target step in a pipeline      task = some_op()      task.execution_options.caching_strategy.max_cache_staleness = "P30D"

튜토리얼에서는 caching을 모두 제거하기로 합니다.

pipeline_container.ipynb
    train_op = dsl.ContainerOp(name="fashion-mnist:",                      image=f"yourID/fashion-mnist-tuner:{tag}", #자신의 이미지로 변경                      pvolumes={"/notebook": notebook_vol,                                 "/result": vop.volume})    train_op.execution_options.caching_strategy.max_cache_staleness = "P0D"    

컴포넌트 리소스 할당#

컴포넌트의 리소스를 할당하여 컴포넌트 실행시 cpu, memory, gpu의 사용량을 정할 수 있습니다.
아래는 fashion mnist를 학습하는 컴포넌트에 cpu 2개, 메모리 4기가를 할당하는 예입니다.

resource_example
    train_op = dsl.ContainerOp(name='fashion-mnist',                      image=f'yourID/fashion-mnist-tuner:{tag}', #자신의 이미지로 변경                      pvolumes={"/notebook": notebook_vol,                                 "/result": vop.volume})    train_op.set_cpu_request("2") \        .set_memory_request("4G")   
  • set_xxx_request() : 컴포넌트 실행되기 위한 최소 리소스를 설정합니다.
  • set_xxx_limit() : 컴포넌트 사용할 수 있는 최대 리소스를 설정합니다.

request 만 설정할 경우엔 컨테이너가 사용할 수 있는 최대 리소스에 대한 제한이 없기 때문에 컨테이너가 실행되는 노드의 모든 리소스를 다 사용합니다. 단 gpu는 limit만 허용됩니다.

example_gpu
.set_gpu_limit("1")