반응형

최근 AI 분야가 각광을 받고, 다양한 ML 기반 서비스들이 제공되면서, MLops라는 용어가 널리 알려지게 되었다. 과거에는 AI 연구 영역과 엔지니어링 영역이 너무 멀게만 느껴져서, MLops에 그렇게 주목하지 않았지만, 실제 머신러닝 코드들을 개발하고, 배포하다 보니, MLops가 왜 필요하고, 어떤 기능을 포함해야 하는지에 대해 공감하게 되었다. 오늘 리뷰할 논문은 MLops의 시작이라고 할 수 있는 2015년 Google에서 발표한  "Hidden Technical Debt in Machine Learning Systems"이라는 논문이다. 사실, 머신러닝이 본격적으로 서비스로 제공되기 한참 이전의 논문이라, 현재의 MLops의 모습과 많이 달라져있을 수 있지만, 어떻게 MLops가 논의되기 시작했는지에 대해서는 알아두고 가야 할 것 같아서 논문을 읽어보았다.

Abstract

  • 머신러닝은 복잡한 예측을 빠른 시간 안에 가능하게 하지만, 빠른 성과를 얻는 것이 무조건 좋은 것은 아니다.
  • 소프트웨어 엔지니어링 공학의 "기술부채" 개념에서 실생활에서 머신러닝 도입은 크고, 지속적인 유지보수 비용을 부담하게 될 것이다.
  • 이 논문에서는 시스템 디자인에서 머신러닝에서 발생할 수 있는 특정 리스크 요인(boundry erosion, entanglement, hiddden feedback loop, undeclared consumers, data dependency 등) 들을 살펴본다.

 

Introduction

  • 머신러닝에 대한 개념과 경험이 쌓여가면서, ML 개발과 배포는 빠르고 쉽지만, 유지보수가 어렵다는 인식이 번져가기 시작했다.
  • 이러한 유지보수의 어려움에는 코드 리팩토링, unit test 개발, 코드 정리, 의존성 제거, 문서 정리 등 기술부채를 해결을 위한 비용을 포함한다. 
  • 이 논문에서는 ML에 특화된 기술부채들에 대해서 다룬다.
  • ML에서의 부채들은 코드 레벨이 아닌, 시스템 레벨에 포함되어 찾기 어려울 수 있다. 특히, 데이터가 머신러닝 시스템의 동작에 영향을 미치기 때문에, 전통적인 코드 레벨에서의 해결 방법은 ML 특화적 기술부채들을 다루기에 충분치 않다.
  • 이 논문에서는 ML 기술적 부채가 쉽게 커지는, 시스템 레벨에서의 interaction과 interface에 집중한다. 

 

Complex Models Erode Boundaries

  • 전통적 소프트웨어 엔지니어링에서는 캡슐화와 모듈화 디자인을 통해, 추상화 경계를 명확하게 나누어, 다른 모듈이나 캡슐의 변화에 영향을 받지 않도록 설계한다.
  • 이러한 분리 속에서는 각 모듈이 input과 output이 명확하기 때문에, 기능적 일관성을 유지할 수 있었다. (예를 들어, Interface 모듈은 Interface 기능만 담당함)
  • 하지만, ML에서는 목적 단위로 명확한 추상화 경계를 나누는 것이 어렵다. 실제로 ML의 서비스에서 외부 데이터에 의존하지 않는 깔끔한 캡슐화는 어렵다. 

[Entanglement]

  • 머신러닝은 여러 signal들을 혼합하여 활용하는데, 각 signal들의 효과를 분리하면서 성능 향상을 하는 것은 어렵다. 
  • 예를 들어, N개의 feature가 있을 때, 한 개의 feature가 변화하게 되면, importance나 weights, 다른 feature들의 필요성등 모든 것들이 변화한다. 이런 경우는 Batch 단위의 학습이든, 온라인 학습이든 모두 적용된다.
  • 새로운 feature를 추가하는 것이나, 특정 feature를 지우는 것도 비슷하다. 
  • 즉, 모든 Input들이 독립적이지 않다는 것이고, 이 논문에서는 이 현상을 CACE(Changing Anything Changes Everything pipeline으로 명명한다.
  • CACE는 input 뿐 아니라, hyper-parameter에도 적용된다. 
  • 이러한 현상을 완화하기 위한 방법으로는 model을 분리하고, 앙상블 형태로 serving 하는 것이다.
  • 이러한 접근 방법은 전체 문제를 sub problem으로 쪼갤 수 있는 경우에는 효과적일 수 있다. 하지만, 많은 경우에서 앙상블이 효과적인 이유는 각 모델에 속한 오류가 상관관계가 없기 때문인데, 결합에 의존하게 되면 오히려 각 모델의 성능을 향상하는 것이, 전체 앙상블 모델 성능을 떨어뜨릴 수 있다.
  • 두 번째 전략으로는 prediction behavior의 변화를 감지하는 것에 초점을 맞추는 것이다. 시각화 도구등을 활용하거나, 각 단계 별로 작동하는 metrics 등이 효과적일 수 있다.

 
[Correction Cascades]

  • 문제 A에 대한 model이 존재할 때, 살짝 다른 문제 A'를 풀기 위해, 두 문제 간의 차이를 빨리 학습하는 것이 필요하다. (예를 들어, pre-weight에 대한 Fine tuning)
  • 하지만, 이런 문제가 계속 생긴다고 하였을 때, 시스템 종속성이 계속 연결되어 발생하고, 큰 비용이 발생한다. 
  • 완화전략으로는 동일 모델에서 casecade가 아닌, 직접 correction을 학습하던지, 별도의 모델을 만드는 것이다.

 
[Undeclared Consumers]

  • 머신러닝 시스템의 예측은 runtime에 광범위하게 접근 가능하게 되거나, 다른 시스템에 소비될 파일이나 로그 형태로 생성된다.
  • access control이 없으면, 이러한 결과는 다른 시스템의 입력으로 충분한 공유 없이 사용할 수 있다. 이러한 문제를 전통 소프트웨어 엔지니어링에서는 visibility debt라고 한다. (의존성의 부채)
  • 이러한 문제는 구성 요소간의 상화 작용과 의존성을 파악하지 못해서, 예측 불가능한 문제를 발생시킬 수 있다.
  • Undeclared Consumer를 고려하기 위해서, 방화벽이나 access 제한 등의 접근을 제한할 수 있는 방법을 검토해야 한다.

 

Data Dependencies Cost More than Code Dependencies

  • 전통 소프트웨어에서는 의존성에 대한 cost가 기술 부채의 주요 요인으로 꼽힌다. 
  • ML에서는 data dependency가 주요 기술 부채 요인이 되지만, 오히려 감지는 더 어렵다.
  • Code 의존성등은 컴파일러 등을 통한 정적 분석으로 어느 정도 확인이 가능하다. data dependency도 비슷한 tool이 없다면, 데이터 의존성을 풀기 어렵다. 

[Unstable Data Dependecies]

  • 빠른 학습을 위해, 다른 시스템에서 생성된 Feature 등을 활용하는 것이 일반적이다. (pre-weight 등) 
  • 하지만, 몇몇의 input signal들은 질적 또는 양적으로 행동이 변화하는 불안정한 특성을 가질 수 있다. 
  • input signal을 제공하는 머신러닝 시스템 자체가 학습된 경우나, TF/IDF 같은 데이터 종속적 데이터들은 데이터 변화에 따라 변화한다.
  • 특히, 데이터와 모델의 ownership이 분리된 경우 많이 발생한다. 이 경우 input signal의 개선조차도, 사용하는 시스템에서는 업데이트에 대한 비용이 많이 발생한다. 
  • 완화를 위한 방법으로는 주어진 signal에 대한 버전 관리(DVC 같은)이다. 예를 들어, 시간에 따라 변화하는 input을 사용하는 것이 아니라, input을 특정 버전으로 freeze 하여 사용한다. 
  • 이러한 버전관리는 그 자체의 cost를 발생하지만, 아무도 모르게 모델 성능에 영향을 미치는 일은 일어나지 않을 것이다.

→ 이 부분은 Database에서의 Data Dependency와 비슷하다. 일반적으로 ML은 앞선 매우 많은 종류의 원천 데이터들을 ETL 하여 활용하기 때문에, Data Dependency에 대한 cost를 계속 안고 가야 한다. 사실 이 부분이 ML serving을 쉽게 하는 tool이 많이 만들어져도, ML engineer의 비중이 점점 더 커지고 있는 요인 아닐까 싶다. 
 
 
[Underutilized Data Dependencies]

  • Code에서의 불필요한 의존성은 보통 필요하지 않은 패키지들로 발생한다.
  • 비슷하게, underutilized data dependencies는 model 성능에 더 이상 이점을 제공하지 못하는 data들을 의미한다. 
  • 이러한 요소들은 ML 시스템을 불필요하게 변화에 취약하게 할 수 있다. 
    • Legacy Features: 시간에 변화에 따라 Feature 특징이 바뀌었는데, 필요 없지만 그것을 감지하지 못하는 경우
    • Bundled Features: bundle 형태로 제공되는 Feature 들 중, 필요성이 떨어지거나, 없는 Feature들이 포함된 경우
    • Epsilon-Features: 연구자들이 성능 향상을 위해, 성능에 미치는 영향이 미미하지만, 복잡한 데이터들을 포함해 놓은 경우
    • Correlated Features: 종종 두 개의 Feature들이 큰 상관관계를 가지고, 하나의 Feature가 다른 것의 원인인 경우. 많은 ML 방법들은 두 Feature가 의미적으로 동일하다는 것을 감지하지 못하거나, 원인이 아닌 결과를 선택하기도 한다. 
  • 적게 활용되는 종속성은 철저한 leave-one-feature-out 평가를 통해 감지될 수 있다. 이러한 평가를 정기적으로 실행하여, 불필요한 특징을 식별하고 제거하는 데 사용되어야 한다. 

→ 과거, 8개의 view를 활용하여 Object Detection을 진행하는 과제를 진행한 적이 있다. 중간에 2개 view를 더이상 evaluation 단에서 활용할 수 없는 경우가 발생하였고, 이에 따라, 데이터를 필터링하고 재학습하는 과정을 거쳤다. 당시 단일 모델을 많은 researcher들이 다루고 있어, 금방 해결했지만, 대규모 시스템에서는 데이터를 제외하고 재학습해야 하는 매우 큰 cost가 발생할 수 있을 것이다.
 
 
[Static Analysis of Data Dependencies]

  • 전통적인(머신러닝이 아닌) 코드 들은 컴파일러와 빌드 시스템이 종속성에 대한 정적 분석을 실행해 준다.
  • Data dependencies들에 대한 정적 분석 툴은 흔하지는 않지만, error checking이나, 마이그레이션, 업데이트 등에 중요한 요소이다. 
  • Ad Click Prediction 논문에서 소개한 자동 기능 관리 시스템은 이러한 작업을 가능하게 해준다. 자동 체크는 데이터 소스와 기능에 annotation을 달게 하여, 이를 자동으로 체크해 준다. 

→ 데이터 의존성을 정적 분석하기에는 모든 데이터를 cover하기 어려울 것이다. 그나마, 중간 단 feature의 visualization이나 통계값들을을 쉽게 뽑을 수 있는 tool을 활용하는 것이 최선이 아닐까 싶다.
 

Feedback Loop

  • ML 시스템의 특징 중 하나는 시간에 따라 업데이트가 진행되면서, 모델 자체 행동에 영향을 미칠 수 있다는 것이다. 이로 인해, 특정 모델의 행동을 예측하기 어려워지는 "anaylisis debt"가 발생한다.
  • 이러한 Feedback loop는 다양한 형태로 발생하지만, 시간에 따라 점진적으로 발생할 경우, 감지와 해결이 더 어렵다.

[Direct Feedback Loops]

  • 모델이 직접적으로 미래 training data 선택에 영향을 미치는 현상이다. 
  • 이는 bandit 알고리즘을 사용하여 해결가능하다.(무작위성 등을 이용하여, 공간을 줄임)

[Hidden Feedback Loops]

  • Direct feedback loops는 분석에 cost가 많이 들지만, ML 연구자들이 통계적으로 풀어낼 수 있을 것이다.
  • 더 어려운 케이스는 두 시스템이 서로에게 영향을 미치는 hidden feedback loops이다. 
  • 예를 들어, 두 다른 투자 회사에서 나온 주식 시장 예측 모델의 경우, 하나의 모델을 개선하면, 다른 모델의 입찰과 매수에 영향을 미칠 수 있다.

 

ML-System Anti-Patterns

  • 실제 ML 코드를 보면, 학습과 분석에 해당하는 코드는 전체 코드의 아주 일부분 만을 차지한다. 이러한 ML을 포함한 시스템에서 high-debt 디자인 패턴을 가지는 것이 흔한 현상이다. 
  • ML 시스템에서 발생할 수 있는 시스템 디자인 안티패턴들은 다음과 같다. 

[Glue Code]

  • 일반적으로 ML 코드 개발을 위해, 미리 만들어진 package를 사용하는 경우가 많다. 
  • 이러한 package들은 다양한 범위를 커버하기 위해 만들어졌기 때문에, 실제 package의 일부만 사용하더라도 대량의 코드를 import 하는 glue code가 발생한다. 
  • Glue code는 특정 버전의 패키지로 시스템을 고정하여, 개선을 어렵게 하는 등 장기적으로 비용이 많이 발생한다.
  • 이를 해결하기 위해, 블랙박스 패키지를 공통 API로 wrapping 하는 방법들이 있다. 이렇게 하면, 재사용성 향상과, package 변경에 따른 비용으로 절감할 수 있다.

 
[Pipeline Jungles]

  • glue code의 특별한 케이스로 발생하는 pipeline jungles는 data를 전처리할 때 자주 발생한다.
  • 이러한 경향은 새로운 signal과 source가 점진적으로 추가됨에 따라 발생하는데, 주의를 기울이지 않으면 ML 전처리 단에서 스크랩, 조인, 샘플링 단계등이 남발하는 정글이 발생할 수 있다.
  • 이런 pipleline을 관리하고, 에러를 발견하여 해결하는 것은 어렵고, 많은 비용이 든다. 예를 들어, pipeline 테스트를 위해서는 비용이 많이 드는 end-to-end 통합 테스트가 필요한데, 이런 테스트를 관리하는 것들이 기술적 부채를 발생시킨다.
  • Pipeline jungle은 데이터 수집 및 Feature 추출에 대해 종합적으로 생각해야만 피할 수 있다. 
  • Pipeline jungle을 제거하고, 처음부터 다시 디자인하는 것들은 공수가 많이 발생하지만, 비용 감소와 발전의 속도 측면에서 효과적일 수 있다. 
  • Glue Code와 Pipeline Jungle은 Research 영역과 Engineering 역할을 지나치게 분리되어 있어 발생하는 현상이기도 하다. 
  • Engineer와 Researcher를 동일 팀에서 편입시키는(혹은 동일한 사람이) 하이브리드 연구 방식은 이런 갈등의 근본 원인을 제거할 수 있다. 

 
[Dead Experimental Codepaths]

  • Glue code나 Pipeline jungle의 흔한 결과 중 하나는, 대체 방법 실험을 진행하는 것이다. 빠른 실험을 위해,  Production code 내에 조건부 브랜치를 만들어, 실험비용을 줄이기도 한다.
  • 하지만, 시간이 갈수록, 이런 codepath들은 쌓이게 되고, 역호환성을 유지하기 어려워지며, 순환 복잡성이 매우 증가하게 된다. 
  • 전통적 소프트웨어에서의 dead flag와 마찬가지로, 주기적으로 각 실험용 브랜치를 재조사하여, 제거하는 것이 해결 방법이 될 수 있다.

 
[Abstraction Debt]

  • 최근에는 머신러닝의 추상화에 대한 올바른 Reference가 없음에 대한 문제가 지적되고 있다.
  • 표준 추상화의 부재로 구성요소 간의 경계가 흐릿해지기 쉽게 된다.

[Common Smells]

  • Plain-Old Data Type Smell : ML 시스템에서 사용되는 많은 정보(hyper parameter 등)가 코드에 그대로 들어가 있는 경우가 있다. 
  • Multiple-Language Smell : 특정 부분을 특정 언어로 작성하는 것이 해당 작업에 적합한 경우가 있다. 하지만, 여러 언어를 사용하면, 효과적인 테스트 비용이 증가하게 된다.
  • Prototype Smell : 적은 양의 데이터로 프로토타입을 테스트하는 것이 유용하지만, 유지보수 측면에서는 별도의 cost가 발생한다는 점, 시스템의 복잡성이 증가한다는 점 등의 문제가 발생할 수 있다.

 
 

Cofiguration Debt

  • ML에서는 configuration으로 인한 부채가 발생할 수 있다. 
  • 대규모 시스템은 다양한 범위의 configuration 옵션 등을 포함하는데, researcher와 engineer 모두 이런 configuration을 을 고려하고 개발하지 않는다. 
  • 실제로, configuration을 확인이나 테스트도 중요하게 여겨지지 않는다. 
  • ML 시스템에서는 configuration을 위한 ocde line이 traditional code의 line 수를 훨씬 초과할 수 있다. 이런 configuration은 실수를 발생할 수 있는 여지가 있다.
  • 이러 configuration에서의 실수들은 시간, 컴퓨팅 리소스 등의 낭비나 production 레벨에서의 문제로 이어질 수 있다. 
  • 이를 고려한 좋은 configutaiton 시스템의 원칙은 다음과 같다.
    • 이전 configuration에서 작은 변경을 하는 것이 쉬워야 한다.
    • 수동 오류, 누락 또는 간과를 어렵게 해야 한다.
    • 두 모델 간의 configuration의 차이를 시각적으로 쉽게 파악할 수 있어야 한다.
    • configuration에 대해 자동 검증이 쉬워야 한다.
    • 사용하지 않거나, 중복된 설정을 감지하는 것이 가능해야 한다.
    • configuration을 전체 코드 검토를 거치고, 저장소에 올라가야 한다. 

 

Dealing with Changes in the External World

  • ML의 특징 중하나는, External World와 직접 상호 작용한다는 것이다. 하지만, External World는 일반적으로 안정되어 있지 않다. 계속된 변화들은 추가적인 유지보수 비용을 발생시킨다.

[Fixed Thresholds in Dynamic Systems]

  • 모델의 prediction을 위해, decision threshold를 선택하는 경우가 있다. ML에서 전형적인 접근 방법으로는 precision과 recall 등의 trade-off인 지표 들 사이에서 균형점을 찾는 것이다. 
  • 하지만, 이러한 Threshold는 종종 manual 하게 지정되기도 한다.
  • 이런 경우, 모델이 새로운 데이터로 업데이트되면, 예전에 manual로 지정한 threshold는 무효화된다. 
  • 여러 모델에 걸쳐 많은 threshold는 manual로 업데이트하는 것은 매우 번거롭고, 관리가 어렵다.
  • 이를 완화할 수 있는 방법으로는 threshold를 validation data에서 평가를 통해 뽑는 것이다.

[Monitoring and Testing]

  • 각 요소들의 unit test와 end-to-end test 모두 가치 있지만, 변화하는 환경에 대응하기 에는 충분치 않다.
  • 실시간으로 시스템의 동작을 모니터링하고, 이를 이용한 대응을 하는 것이 장기적 시스템 신뢰성 관점에서 중요하다.
  • 이때, 어떤 것을 모니터링해야 하는지에 대해 명확하지 않다. 모니터링을 위한 몇 가지 부분을 소개한다.
    • Prediction Bias : 의도된 대로 작동하는 시스템에서는 예측의 분포가 실제 분포와 일치해야 한다. 이는 종합적인 테스트는 아니지만, 입력과 관계없이 레이블 발생의 평균값을 예측하는 단순한 모델에 의해 확인될 수 있다. 이 방법은 종종 현재 현실을 반영하지 않는 과거 데이터로부터 추출된 훈련 분포가 갑자기 변경된 경우와 같은 문제를 신속하게 감지할 수 있다.
    • Action Limits : 실제 예측에 대한 Action을 진행하는 시스템들의 경우, action에 대해 합리적인 limit을 설정하고, 이를 강제하는 것이 유용하다. 
    • Up-Stream Producers : 데이터를 생성하는 Producer에 대해 정기적인 모니터링이 필요하다. 

 

그 밖에 ML 관련 부채

  • Data Testing Debt : 입력 데이터에 대한 어느 정도의 테스트가 필수 적이다. 입력 분포의 변화 등을 모니터링하는 테스트도 필요하다.
  • Reproducibility Debt: 실험을 재현하는 것이 난수 알고리즘, 병렬 학습에서의 결정 불가능 성, 초기 조건 등 매우 어렵다.
  • Process Management Debt : 실제 시스템에서는 단일 모델이 아닌 많은 모델을 유지보수 할 텐데, 비즈니스 우선순위가 다른 모델 간에 리소스를 어떻게 관리하고 할당할 것인지 등에 대한 고려도 필요하다. 또한, 프로더션 사고로부터 복구하기 위한 도구를 개발하는 것도 중요하다.
  • Cultural Debt: 때로 ML reseach와 Engineering 단에 경계가 존재하는데, 이런 경계는 시스템 건강에 역효과를 낼 수 있다. 

 

총평

  • 사실 MLops를 처음 접하고, 사용해보았을때에는 기술적 부채와 소프트웨어 공학적 이해가 부족하여, Bash Shell로 가능한 기능들을 이쁘게 만들어놓았구나라는 생각에 그쳤다. 
  • 이 논문은 실제 ML이 본격적으로 service 단에 오르기 전에 작성되었지만, 이 논문에서 말하는 MLops가 필요한 이유와 발생할 수 있는 문제들이 실제 service 단에서 많이 발생하고 있는 것들을 보면서 매우 신기하고, 대단하게 느껴졌다. 
  • 현재 존재하는 MLops 관련 tool들이 이 논문에서 제기한 문제들 중 매우 일부만 해결할 수 있다는 점 때문에 아직 MLops가 가야 할 길이 멀구나 하는 생각을 갖게 되었다. 

 

Reference

Sculley, David, et al. "Hidden technical debt in machine learning systems." Advances in neural information processing systems 28 (2015).

'MLops' 카테고리의 다른 글

Kubeflow (2) - Katlib  (1) 2023.04.11
Kubeflow (1) - 설치 (Windows 11 - WSL로 설치)  (3) 2023.03.28
Kubeflow (0) - 소개  (1) 2023.03.26
반응형

지난 장에서 Kubeflow를 겨우 설치하는 데 성공하였다. 아무래도 로컬 환경에서 자원을 쪼개서, Kubeflow를 돌리다 보니 조금 버벅거리는 감이 있지만, Kubeflow의 각 기능을 조금 더 자세히 알아보자. 가장 먼저 알아볼 기능은 Katlib이다. 사실, 클라우드 환경이 아니라 로컬에서 Kubeflow를 실행하다보니, Kubeflow UI에서 지원해 주는 Notebooks나 Tensorboard 기능은 사실 잘 와닿지 않았다. (로컬에서 실행하면 되기 때문에) 하지만, Katlib은 평소 네트워크 학습 과정에서 걸리던 하이퍼파리미터 튜닝등의 문제에 유용하게 사용할 수 있을 것 같아, Katlib부터 소개하기로 한다.  
 


Katlib

  • Katlib은 앞선 장에서  설명했듯, 하이퍼파라미터 최적화 & 뉴럴 아키텍쳐 탐색을 지원해 주는 프레임워크이다. (개인적으로 Katlib은 머신러닝 워크플로우를 쿠버네티스 환경에서 실행하는 가장 큰 강점을 보여주는 프레임워크라고 생각한다.)
  • Katlib는 각기  다른 하이퍼파라미터 설정이나, 아키텍쳐 탐색을 분산된 머신에서 동시에 실행하여, 최적의 값을 탐색한다. 
  • 쉽게 말하면, Katlib은 한번에 여러 머신에서 실험 가능하고, 사용하기 쉬운 머신러닝 모델 탐색용 Cron Job이라고 생각한다.   
  • Katlib은 아래와 같은 장점을 갖는다.
    • 자동화된 하이퍼 파라미터 튜닝 : 하이퍼 파라미터를 튜닝하는 일은 모델 개발자들에게는 번거로운 일이고, 서비스 제공자에게는 어느 정도 난이도가 필요한 일이다. Katlib에서 제공하는 자동화된 하이퍼 파라미터 튜닝은 머신러닝이나 Batch 프로그램에 대한 전문 지식이 없더라도 쉽게 사용 가능하다.
    • 분산 머신러닝 지원 : 머신러닝 연구자라면 가장 스트레스 받는 일 중 하나가 환경을 세팅하는 일이다. 머신 여러 개로 하이퍼파라미터를 각기 달리 실험할 때, 여러 개에 동일한 개발 환경을 세팅하는 것은 굉장히 번거롭고, 어려운 일이다. 특히, 소스 상에서 변경점이 생길 때마다, 모든 머신에서 반영이 필요하다. Katlib은 쿠버네티스를 이용하여, 클러스터 내의 여러 머신에서 모델 훈련이 실행되므로, 효율성을 높일 수 있다.  

 

Katlib 사용법

  • Katlib을 실행하기 위해서는 "Experiment" CRD(Custom Resource Definition)을 사용하여, 작업을 정의하고, 실행해야한다. 
  • 앞서 말한대로, Katlib은 Kubeflow 환경 하에서 뿐만 아니라, 그 자체로 독립적으로 실행할 수 있다. 하지만, Kubeflow하에서 사용하면 더욱 쉽게 사용할 수 있다.
  • Kubeflow 환경 하에서 Katlib은 Experiments(AutoML) 메뉴에서 사용 가능하다. 
  • "Experiment" CRD를 직접 작성하여 작업을 정의할 수도 있고, UI를 이용하여 쉽게 CRD를 작성 가능하다. 
Kubeflow UI 내, Katlib
  • Kubeflow UI에서 Experiments(AutoML)를 실행했을때, 총 8개의 설정이 필요하다. 
  • 첫 번째는, Metadata이다. 현재 수행에 대한 Job 명을 정할 수 있다.
  • 두 번째는, Trial Thresholds이다. 실험에 대한 분산처리를 지정해 줄 수 있다. 각 Parameter는 다음의 의미를 갖는다.
    • Parallel Trials : 동시에 몇개의 실험을 진행할 것인지를 정해줌(H/W의 리소스를 효율적으로 사용하기 위해 정해줌, 분산처리)
    • Max Trials : 최대 몇번의 학습을 진행할지를 정해줌(과도한 H/W 리소스 사용을 방지)
    • Max failed Trials : 최대 몇 번까지 실패한 학습을 용인할지를 결정해 줌. Katlib의 수행 자동화 기능을 지원하기 위해 들어간 파라미터로, 실험 세팅의 실수 등의 이유로 정상적인 실험이 진행되지 않았지만, 인간이 바로 인지하지 못하는 경우 무의미한 실험들이 H/W를 점유하고 있을 수 있어서, 이러한 무의미한 실험등을 방지하기 위해, 최대 실패 횟수를 정해서, 이를 초과한 실험 실패가 발생했을 시, 실험을 중단함.
    • Resume Policy : 실험이 중단되었을때, 다시 시장하는 방법을 지정해 줌. ('Never' : 실험이 중단되었을 때, 재개하지 않음. 'Long Running': 실험이 종료된 뒤에서 Pod 및 리소스를 유지하여, 데이터를 유지하고 실험 결과를 확인 가능함. 'From Volume' : 실험이 종료된 후, 해당 실험에 필요한 볼륨이 자동으로 마운트 되어, 실험에서 생성된 데이터나 파일을 계속 사용하여 실험을 재개함.)
  • 세 번째는, Objective이다. 모델 학습을 최적화하기 위한 최종목표를 정의 가능하다. Metric을 통해서, 여러개 Objective를 설정할 수 있고, 각 Metics에 대해, "Maximaze"와 "Minimize"를 정해, 탐색 목표를 정할 수 있다. 
  • 네 번째는, Search Algorithm이다. 모델 탐색 과정의 알고리즘을 선택할 수 있다. 크게 Hyper Parameter tuning과 neural Architecture Search에 대한 알고리즘을 제공한다.
  • Hyper Parameter tuning은 총 9개의 알고리즘을 제공한다. 그중 많이 사용하는 알고리즘은 아래와 같다.  
    • Grid : Grid Search(가능한 모든 조합 시도)
    • Random : Random Search(임의로 Hyper parameter 선택)
    • Bayesian Optimization : 후보 모델을 사용하여, Hyper parameter 조합을 평가하고, 그 Hyper parameter로 후보 모델을 업데이트하는 과정을 반복. 
  • Neural Artchitecture Search는 크게 2가지의 알고리즘을 제공한다.
    • Efficient Neural Architecture Search(ENAS) : 하나의 모델을 학습시켜, 새로운 모델을 생성하는 방식을 사용함. 파라미터 공유 및 Weight Sharing 기술을 사용해서, 여러 작업을 수행하고 구성요소를 동시에 학습 및 업데이트함.
    • Differentiable Architecture Search(DARTS) : 아키텍쳐 검색과 학습을 동시에 수행하는 end-to-end 학습 방법. 알고리즘이 다양한 아키텍처를 조합하는 데 사용되는 가중치를 학습함. 
  • 다섯 번째는, Neural Architecture Graph는 네트워크의 구성을 정의하기 위한, Input, Output 사이즈 및 Layer 갯수등을 지정한다. 
  • 여섯 번째는, Neural Architecture Operations이다. NAS에서 사용되는 기본 연산을 위한, 네트워크 구조 생성 및 변경에 사용된다. 모델의 구조를 생성하기 위한 파라미터등의 가능한 후보를 정의해서, NAS에서 모델을 찾는데 활용할 수 있다.  
  • 일곱 번째는, Metrics Collector이다. Metrics Collector는 각 실험들의 결과를 어떻게 수집하고, 측정할 것인지를 정의한다. Stdout처럼 단순 출력으로 받을 수도 있고, File이나, Prometheus 등을 통해서 수집 가능하다. 
  • 마지막으로, trial의 환경을 정해줄 수 있는 Trial Template이다. 이 메뉴를 활용하여, Trial에서 사용할 수 있는 도커 이미지나 하이퍼파라미터 설정, 리소스 제한 등을 정의할 수 있다. Template를 제공하기 때문에 해당 Template을 수정하는 구조로 실험을 진행할 수도 있다. 

 

  • 마지막 옵션까지 모두 설정하고, 아래 Edit 버튼을 누르면, 1~8까지 설정한 내용을 기반으로 "Experiment" CRD가 작성되어 있는 것을 확인할 수 있다. 
  • 설정이 제대로 들어가있는지 확인하고, 변경도 가능하다. 설정이 제대로 진행되었으면, CREATE를 통해 실험을 실행한다. 
 
  • 실험 결과는 아래와 같이 보인다. (로컬에서는 H/W 리소스 문제로 실행이 정상적으로 되지 않아서, Kubeflow 홈페이지의 이미지 활용)
  • Experiments에서 생성한 실험들에 대한 성공 횟수와 진행 중인 횟수, 실패한 횟수를 확인할 수 있다. 
Experiments 결과 (출처 : https://www.kubeflow.org/docs/components/katib/hyperparameter/)
  • 각 실험을 클릭해보면, Hyper Paramter 조합과 가장 최적의 Hyper Parameter 조합에 대한 정보를 얻을 수 있다. 
실험 세부 결과 (출처 : https://www.kubeflow.org/docs/components/katib/hyperparameter/)

사실, Katlib은 매우 유용한 툴이지만, H/W 리소스가 분산 처리를 할 수 있을 정도로 많은 양이 필요하기 때문에, 사용이 제한적이다. 아무래도 개인의 경우에는 많은 자원을 동시에 활용하는 일이 적기 때문에, Katlib보다는 Bash를 이용한 Batch Job 등을 이용하는 게 좋을 것 같다. 하지만, 사내등의 하드웨어 환경이 풍부한 상황에서는 요긴하게 활용할 수 있을 것 같다. 

반응형

회사에서는 ML Ops 환경이 어느 정도 갖춰져 있어서, Kubeflow를 직접 설치하지 않았다. Local에서 Kubeflow를 설치하려고 하니, 생각보다 쉽지 않았다.  시간은 조금 걸렸지만, 설치하는 과정을 적어보고자 한다.


WSL 설치

  • Window에서 Kubernetes를 설치하기 위해서는, WSL(Windows Subsystem for Linux) 환경을 구성해야한다.
  • 먼저, Windows 검색 창에 Windows 기능 켜기/끄기를 검색하여 실행한다.
  • Windows 기능 켜기/끄기 List들에서 Linux용 Windows 하위 시스템을 체크해 준다. Windows Powershell을 관리자 권한으로 실행한 뒤,  wsl이 설치되어 있는지 확인한다. (보통 설치되어 있을 가능성이 높아서 확인)

wsl -l -v
  • 아래와 같이, list에 WSL 항목이 뜨고, VERSION이 '2' 이면, Docker Desktop 설치로 넘어간다. 

 

  • 만약 버전이 '1'일시에는, 아래 명령어로 버전을 바꿔준다.  Powershell에서 아래 명령어를 입력해 준다.
wsl --set-version {Name} 2  # Name에 현재 사용중인, wsl 버전 입력
wsl -l -v  # 적용 확인
wsl # wsl 환경으로 진입
  • 만약 wsl 목록에 존재하지 않는다면, Microsoft Store에서 "Ubuntu" 검색 후, 원하는 버전을 설치해 준다.

 

Docker Desktop 설치

  • Kubeflow는 Kubernetes 환경 하에서 돌아간다. 따라서, Kubeflow 설치 전에 Kubernetes 환경을 먼저 구성해야 한다.
  • Window에서 가장 쉽게 Kubernetes를 설치하는 방법은 Docker Desktop을 통해, 설치하는 것이다. 
  • 우선, 아래 Link에서 Docker Desktop을 설치한다.
Docker Desktop 설치
https://www.docker.com/products/docker-desktop/

Docker Desktop 설치 화면 (출처: https://www.docker.com/products/docker-desktop/)

  • 설치 후, Docker Desktop을 켜고, Setting > Kubernetes > Enable Kubernetes > Apply & restart를 눌러준다.

 

Kubectl 설치

  • Kubectl은 Kubernetes 클러스터를 관리하기 위한 CLI 도구로, 아래의 명령어를 통해 설치한다. 
sudo apt-get update && sudo apt-get install -y kubectl
kubectl version

 

Minikube 설치 & 실행

  • H/W 자원이 만약 풍부하다면, 일반의 Kubernetes Cluster 구성(마스터와 노드를 포함)이 가능하겠지만, 로컬 환경에서는 대체로 H/W 자원이 그리 풍부하지 않다.
  • Minikube는 로컬에서도 개발 & 테스트를 용이하게 하기 위해, 단일 노드로 구성된 Kubernetes Cluster를 생성할 수 있도록 하는 도구이다. 
  • 아래 명령어로, minikube를 설치한다.
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb && sudo dpkg -i minikube_latest_amd64.deb
  • minikube를 설치했으면, 아래 명령어를 통해, Kubernetes Cluster를 실행해 준다. (memory와 cpu, disk 등은 현재 사용 가능한 리소스 내에서 적당히 설정해 준다. 너무 많이 설정하면, Local 환경이 제대로 동작하지 않는다.)
  • 현재(23/03) 기준으로 Kubeflow가 지원하는 가장 높은 수준의 Kubernetes 버전은 1.25.0이다. 
minikube start --driver=docker --memory=4g --cpus=2 --disk-size 20GB --kubernetes-version=1.25.0

※ 주의 : kubernetes 버전에 따라, 사용 가능한, kubeflow 버전이 달라진다. 

 

Kustomize 설치 (Optional)

  • Kustomize는 원본 yaml 파일의 변경 없이, yaml 파일을 변경할 수 있도록 하여, 환경에 맞는 설치를 가능하도록 도와주는 도구이다.
  • 사실, Kubectl 설치 시, Kustomize는 자동으로 설치된다. (Kustomize 버전을 업그레이드하기 위해서는, Kubectl 버전을 업그레이드해야 한다.) 
  • 다만, Kustomize와 minikube의 Kubernetes 버전이 호환이 안 되는 경우, Kustomize만 따로, 설치하여, 적용 가능하다. 
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo cp kustomize /usr/local/bin/
kustomize version

 

Kubeflow 설치

  • 드디어, 대망의 Kubeflow를 설치한다.
  • Kubeflow 설치는 Kustomize를 이용하여, Kubernetes 버전에 존재하는 각 Component 들의 yaml 파일을 변경하여, 설치하는 구조이기 때문에, 1) Kubernetes 버전 2) Kustomize 버전과 호환성을 맞춰줘야 한다. 
  • 계속, Kubeflow 버전이 나오고 있기 때문에, 명령어 입력 전, https://github.com/kubeflow/manifests#installation 에 접속하여, 버전을 확인해 보기 바란다.

23/03/27 기준 prerequisites

  • 내가 설정한 버전은 다음과 같다.
kubernetes = 1.25
kustomize = 5.0.0
kubeflow = v1.7

 

git clone --branch v1.7-branch https://github.com/kubeflow/manifests.git
cd manifests
# 버전 변경이 필요 시 : git checkout (branch 명)
while ! kustomize build example | awk '!/well-defined/' | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done

※ 설정한 H/W 리소스에 따라 다르겠지만, 설치까지 정말 오래 걸린다. 터미널 문구에 Warning이 뜨는 것은 상관없는데, Error가 뜬다면, Kubernetes 버전이나, Kustomize 버전과 호환이 안되었을 확률이 높다. 그런 경우 Kubernetes 버전과 Kustomize 버전을 바꿔주던, Kubeflow 버전을 바꿔주던 해야 한다.

 

  • 아무래도, Kubeflow가 특정 Kubernetes 버전에 맞춰서 개발되었을 것이므로, Kubernetes 버전을 바꿔주는 것이 좋다고 느껴진다. 
  • Kubernetes 버전은 아래 명령어로 다시 설정해 준다.
minikube delete
minikube start --driver=docker --memory=4g --cpus=2 --disk-size 20GB --kubernetes-version={새로운 버전}

 

Kubeflow 접속

  • 로컬 컴퓨터의 8080 포트와 쿠버네티스 내부의 80 포트를 연결해 줘서, UI에 접근할 수 있도록 해준다. 
  • 이 명령어를 실행하면 로컬 컴퓨터의 8080 포트를 통해 쿠버네티스 내부의 istio-ingressgateway 서비스에 접근할 수 있다.  
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80
  • 명령어 실행 후, 브라우저에서 http://127.0.0.1:8080에 접근하면 Kubeflow UI에 접근 가능하다. 

 


Kubeflow 설치는 시간도 오래 걸리고, 각 도구들의 버전 호환성 때문에, 설치가 어려웠다. 하지만, 천천히 하나하나 진행하다 보면, 대략적으로 Kubeflow가 어떻게 구성되는지 보이는 것 같다. 다음 장부터 Kubeflow 각 component를 파봐야겠다.  

'MLops' 카테고리의 다른 글

MLops 등장: Hidden Technical Debt in Machine Learning Systems 논문 리뷰  (17) 2024.02.18
Kubeflow (2) - Katlib  (1) 2023.04.11
Kubeflow (0) - 소개  (1) 2023.03.26
반응형

AI가 연구의 영역에서 실용 영역으로 침투하기 시작하면서, AI로 구성된 서비스를 어떻게 잘 제공할 것인지에 대한 수요가 높아지고 있다. 특히, chat-gpt로 AI 영역에서 엔지니어링의 중요성이 대두된 만큼, AI 서비스의 수집부터, 제공까지의 워크플로우를 어떻게 관리할 것인지에 대한 관심이 높아졌다. Kubeflow는 이런 상황 속에서 등장하고 발전했다. (처음 등장한 지는 조금 오래됐다 - 2018년)


ML workflow 란?

  • Kubeflow를 알기 위해서는 ML workflow를 이해할 필요가 있다. ML workflow는 머신러닝 알고리즘을 개발하고, 이를 통해 만든 서비스를 배포하기까지의 일련의 과정들을 모두 포함한다. (사실, 머신러닝 & 딥러닝을 구분해야하지만, 해당 글에서는 머신러닝으로 줄여서 이야기한다.)
  •  일반적으로 ML workflow는 다음과 같은 단계로 나뉜다. 
    1. 데이터 수집 : DB or Online 등에서 데이터를 수집한다.
    2. 데이터 검증 : 수집한 데이터를 검증한다.
    3. 데이터 전처리 : 수집한 데이터에서 노이즈 제거 & 결측치 대체 & 스케일링, Normalization & Augmentation 등을 수행한다.
    4. 모델 학습 : 머신러닝 알고리즘을 선택하고, 전처리된 데이터를 사용하여 모델을 학습한다. 
    5. 배포 : 모델을 실제 운영 환경에 배포하고 사용한다.

 

Kubeflow 란?

  • Kubeflow의 시작은 구글에서 머신러닝에 사용되는 리소스를 효율적으로 관리하기 위해, Tensorflow Extended(TFX)을 사용하면서 처음으로 시작되었다. 후에 여러 개발자들이 모여서, 오픈소스 프로젝트로 공개되었다. 
  • Kubeflow는 이름에서 알 수 있듯, Kubernetes에서 동작하는 ML 워크플로우 툴이다. Kubernetes는 머신러닝 Job에 굉장히 적합한 플랫폼인데, 이유는 다음과 같다.  
    • 머신러닝의 학습 및 배포에는 다른 서비스에 비해, 리소스 자원의 활용이 크다. 따라서, 리소스를 어떻게 잘 컨트롤하여, 학습하고 배포할 것인지가 중요하다. → Kubernetes의 유연성 컨트롤
    • 머신러닝 & 딥러닝은 환경 구축이 H/W나 OS, 라이브러리 버전 등에 따라 다 다르다. (머신러닝, 딥러닝 학습을 해본 사람들이면, 환경 구축에 정말 많은 시간이 소요된다는 것을 알 수 있을 것이다.) Kubernetes의 장점인 확장성 & 유연성
  • Kubeflow는 그 자체가 새로운 서비스라기보다는, Kubernetes 플랫폼 위에서 동작하기 위한, ML workflow에 필요한 여러 오픈소스 툴들을 모아놓은 것이다.
  • 내가 생각하는 Kubeflow의 가장 큰 장점은, 서비스 구성 및 엔지니어링등에 상대적으로 약한 AI researcher들의 부담을 줄여주는 것이라고 생각한다. (운영단에 제공하는 서비스가 아니라면, Kubeflow의 필요성은 조금 약하다고 생각한다. 다만, Kubernetes 환경에서 모델을 학습하는 경우에는 쓰지 않을 이유가 없다.)

 

Kubeflow의 구조

  • 아래 그림은 Kuberflow 홈페이지에 있는 Kuberflow 아키텍처에 대한 Conceptual Overview이다. 
  • 맨 아래, 어떤 플랫폼에서든 Kubernetes를 활용할 수 있다는 것을 강조하고, 그 위에 Kubeflow가 올라가 있다는 것을 보여준다.
  • 즉, Kubernetes 환경 위에서 여러 ML workflow component 들을 묶어서, Kubeflow로 제공해 주고, 그 위에 Pytorch나 Tensorflow등 다양한 언어를 활용해서 Kubeflow를 운영할 수 있다는 것을 강조하고 있다.
  • 그림의 우측에 Istio(트래픽 관리, 보안 등), Argo(워크플로우 관리), Prometheus(모니터링), Spartakus(사용자 데이터 수집) 등을 함께 활용하여, 운영 환경의 안정성을 높일 수 있다는 것을 보여준다.

Kubeflow 아키텍쳐 (출처 : https://www.kubeflow.org/docs/started/architecture/)

 
 

Kubeflow의 Component

  • Kubeflow는 여러 ML workflow 툴들의 집합이라고 위에서 소개했다. 어떤 것이 있는지 알아보자.
  • 우선, ML workflow를 크게 2개로 분류할 수 있다. 알맞는 모델을 찾기 위한 실험 단계와, 선택된 모델을 가지고 서비스를 운영하는 단계이다.
  • 실험 단계에서는 다음과 같은 Component 들을 제공한다.
    • Jupyter Notebook : Kubernetes 위에서 Jupyter Notebook을 사용해서, 모델을 개발 & 실험해볼 수 있게 해준다. 
    • Fairing : 모델의 생성 & 학습 & 배포등을 Kubernetes Cluster로 쉽게 요청할 수 있게 해준다. (즉, 모델을 Docker Image 형태로 Kubernetes에 뿌려준다.)
    • Katlib : 하이퍼파라미터 최적화 & 뉴럴 아키텍쳐 탐색을 지원함. (각기 다른, 하이퍼파라미터와 아키텍쳐를 설정해서, 원하는 결과가 나올때까지 실험해 볼 수 있음)
  • 운영 단계에서는 다음과 같은 Component들을 제한다.
    • Pipelines : ML workflow(수집 & 검증 & 전처리 & 학습 & 배포)를 end-to-end로 만들어 주는 툴 (Argo를 사용한다.)
    • Metadata : Kubeflow Pipelines에서 실행되는 ML workflow에 대한 metadata를 관리하는 서비스
    • KFServing : Kubernetes 위에서 머신러닝 서빙(Serving)을 위해 사용하는 툴
    • TensorRT : 미리 학습된 모델의 정확도를 유지하면서, Inference 속도를 최적화해주는 툴
    • Pytorch : 파이토치
    • TFServing : Tensorflow 모델의 서빙(Serving)을 위해 사용하는 툴
    • Seldon : 머신러닝 모델의 배포 및 관리를 위한 툴
    • Tensorboard : 머신러닝 모델 디버깅 & 시각화 툴

Kubeflow의 Component들 (출처: https://www.kubeflow.org/docs/started/architecture/)

 

Kubeflow의 UI

  • Kubeflow는 Command 명령어로 구동 가능하다. 하지만, Command 명령어로 Kubeflow 내에 있는 기능을 각각 사용할 것이라면, Kubeflow를 사용하는 의미(통합성 & 편의성 등...)가 덜하다고 생각한다.
  • Kubeflow의 UI는 편하면서, 불편하다. 메뉴에 있는 각 Component들을 각각 사용하기에는 편한데, 그 사이에 어떠한 연관성이 있는지 등등은 드러나지 않는다. (어느 메뉴들은 같이 사용해야하고, 어느 메뉴는 독립적이고...)
  • Kuberflow는 "Central Dashboard"라는 UI를 통해, 각 component를 쉽게 접근 할 수 있도록 해준다.  
    • Home: Home이다. 
    • Notebook Servers: Jupyter Notebook 서버를 사용할 수 있게 해준다. 
    • TensorBoards: Tensorboard를 쉽게 사용 할 수 있게해준다.
    • Models: 배포된 KFServing 모델들을 관리한다.
    • Volumes: Cluster의 저장소를 관리한다.
    • Experiments (AutoML): Katlib(하이퍼파라미터 튜닝 등)을 사용할 수 있게 해준다. 
    • Experiments (KFP): 실험용 Kuberflow Pipeline(KFP)을 사용할 수 있게 해준다. 
    • Pipelines: end-to-end Kuberflow Pipeline(KFP)을 사용할 수 있게 해준다. 
    • Runs: Kuberflow Pipeline(KFP)의 실행을 관리한다.
    • Recurring Runs: Kuberflow Pipeline(KFP)의 반복적 실행을 관리한다. 
    • Artifacts: Metadata를 확인 할 수 있게 해준다. 

Kubeflow Central Dashboard (출처 : https://www.kubeflow.org/docs/components/central-dash/overview/)

 


Kubeflow를 보면서, 느낀 것은 아직은 ML workflow의 end-to-end를 책임지기에는 역부족이지만, 앞으로 발전해 간다면 정말 유용하게 사용될 것 같다. 아무래도, 각 Component가 독립적으로 개발되어서, Component 간에 연결이 완벽하지 않다는 느낌을 자주 받았다. Component 간의 연결성이나, kubeflow 자체의 서비스 등을 제공한다면 더 좋을 것 같다. 우선, 다음 장부터 Kubeflow를 설치해 보기로 한다.  

+ Recent posts