furiosa-ai / furiosa-models

FuriosaAI Model Zoo Project
https://furiosa-ai.github.io/furiosa-models/
Apache License 2.0
10 stars 6 forks source link

Module 구조 및 export 구조 논의 #1

Closed hyunsik closed 2 years ago

hyunsik commented 2 years ago

@furiosamg @ileixe @hyeokjunejeon @sukyoungjeong-furiosa

기존 것을 최대한 참고하여 제안 드려봅니다. 어떤 면에서는 큰 차이는 없습니다만, 지난 주에 논의되었던 pre/post process 함수 재활용을 위해 노출을 고려하였습니다. 의견 편하게 주시면 감사하겠습니다.

또한 지난 주에 모두 동의하였던 내용을 간단히 정리 해봤습니다. 차이가 있으면 의견 부탁드립니다.

(참고로 모델 개발 중에는 furiosa-models에서 furiosa-artifacts metadata의 local file path를 입력해서 개발할 수 있도록 고려 필요)

최상단 모델 reexport 형태의 예

from furiosa.models.vision import Resnet50v2
from furiosa.models.vision import EfficientNetv2
from furiosa.models.vision import EfficientDet
from furiosa.models.vision import YOLOv5M

실제 구현 위치의 예

furiosamg commented 2 years ago

깔끔하게 정리해주셔서 감사합니다! 저는 한가지만 헷갈립니다. 적어주신 YOLOv5L (function)는 같은 모델에 여러 family가 있는 경우에 한가지를 정해서 class로 만들고 나머지는 function으로 일부 attribute 만 수정해서 노출하는 것이 맞나요?

hyunsik commented 2 years ago

필요에 따라 공통으로 담을 수 있는 코드가 있다면 한 모듈을 share 할 수 있음을 예로 표현한 것입니다. 실제 yolov5가 그런지는 저도 확인이 필요합니다.

hyunsik commented 2 years ago

기존에 작업하셨던 내용 디테일을 아실 것이라 다양한 의견 주시면 감사하겠습니다. 반영하고 수정해서 프로젝트 layout을 잡겠습니다.

hyeokjunejeon commented 2 years ago

네, 전 초안은 좋은 것 같습니다. 진행하면서 구체적으로 더 찾아보고 제안해 보겠습니다. 감사합니다.

ileixe commented 2 years ago

기존에는 furiosa-artifacts에서 SDK (최하단 furiosa-registry를 제외하곤)에 대한 의존성없이 e2e 테스트를 하는걸 염두에 두고 있었는데요, furiosa-models에 pre/postprocess가 있고 furiosa-artifacts에 이미지가 있다면 모델 개발자분들이 두 군데 작업을 해야되는걸 의미해서 좀 고민이 되는 부분이 있습니다.

최초 의도만 공유드리면 furiosa-artifacts에 제안주신 구조가 그대로 있고 preprocess / postprocess가 의존하는 native코드만 의존성으로 표현되서 runtime에 build되길 바랬었습니다. (참고: https://github.com/furiosa-ai/furiosa-artifacts/pull/40)

furiosamg commented 2 years ago

기존에는 furiosa-artifacts에서 SDK (최하단 furiosa-registry를 제외하곤)에 대한 의존성없이 e2e 테스트를 하는걸 염두에 두고 있었는데요, furiosa-models에 pre/postprocess가 있고 furiosa-artifacts에 이미지가 있다면 모델 개발자분들이 두 군데 작업을 해야되는걸 의미해서 좀 고민이 되는 부분이 있습니다.

최초 의도만 공유드리면 furiosa-artifacts에 제안주신 구조가 그대로 있고 preprocess / postprocess가 의존하는 native코드만 의존성으로 표현되서 runtime에 build되길 바랬었습니다. (참고: furiosa-ai/furiosa-artifacts#40)

생각해보니 모델 개발자가 모델 하나를 배포하기 위해 내용을 나누어 두 레포에 각각 전/후처리, 모델 바이너리를 배포하는것이 이상하긴 하네요. https://github.com/furiosa-ai/furiosa-sdk-private/pull/346 에서 모델 개발자가 furiosa-artifacts만 바라보게 변경했었기도 하고요.

그럼 furiosa-models는 지금처럼 바인딩만 제공하고 furiosa-artifacts에 아래와 같이 들어가면 될까요?

Github                                                                            DVC backend (s3)
 artifacts.py
 furiosa
     |- artifacts
             |- vision
                   |- resnet50v2
                          |- Resnet50v2.dvc                                 <-        (model)
                          |- Resnet50v2 (class)
                          |- utils (Name can be changed later)
                              |- preprocess (function)
                              |- postprocess (function)
                   |- yolov5
                          |- YOLOv5M.dvc                                    <-        (model)
                          |- YOLOv5M (class)
                          |- YOLOv5L.dvc                                    <-        (model)
                          |- YOLOv5L (function)
                          |- utils (Name can be changed later)
                              |- preprocess (function)
                              |- postprocess (function)
                    |- utils
                          |- resize (function)
                          |- crop (function)
                          |-  ...
hyeokjunejeon commented 2 years ago
hyunsik commented 2 years ago

사용자 입장에서는 코드를 포함한 모듈에 직접 접근하게 하면 저희도 고민했던 의존성 문제나 코드 접근성 면에서 더 좋지 않을까요. 개발자 관점에서는 furiosa-artifacts의 local path를 넣어도 잘 동작하게 하는 것으로 충분하지 않을까요?

분리를 왜 해야 하는지는 최초에 저희가 furiosa-artifacts와 furiosa-models를 분리한 동기가 여전히 유효하다고 생각합니다. 이미지와 코드의 lifecycle이 다르기도 할 뿐 아니라, 대용량 파일을 git에 넣는 것이 여러 관점에서 비효율적이라 분리한 것이 최초 동기로 기억하고 있는데요. npu-models repository 도 관련 문제로 오랫동안 고생 해 왔고요. git은 임시 저장소이며 s3나 대용량 이미지 저장이 용이한 곳으로 최종 변경할 것으로 이해하고 있습니다. 추가로 transfomer로 가면 모델 각각이 수 기가 이상이 됩니다.

furiosamg commented 2 years ago

@hyunsik 제가 그림을 잘못 그려서 혼란을 가져온 것 같은데요, furiosa-artifacts에 모델 이미지를 직접 저장하는 것을 말한 것은 아니었습니다. DVC로 따로 관리하는 걸 생각하고 있었습니다. 그림 수정했습니다. 나중에는 DVC를 떼고 s3를 직접 사용할 수도 있겠지만 지금은 전/후처리 함수를 furiosa-artifacts에 넣는 것이 좋을지, models에 넣는 것이 좋을 지 의논하는게 먼저일 것 같습니다.. 제가 생각한 각각의 장점은 아래와 같습니다.

furiosa-models에 넣었을 때

furiosa-artifacts에 넣었을 때

hyunsik commented 2 years ago

furiosa-models에 넣었을 때

  • furiosa-artifacts는 사용자가 로컬에 설치하는 패키지가 아닌데 models는 직접 설치하기때문에 전/후처리 코드를 보기 편함
  • 모델 이미지/ 코드의 분리가 명확해짐 (artifacts는 모델 이미지+메타데이터, models는 코드)

furiosa-artifacts에 넣었을 때

  • 모델 개발자가 furiosa-artifacts 만 바라보고 개발할 수 있음 (furiosa-models는 건드리지 않아도 됨)

네 저도 동의합니다. 추가로 furiosa-models로 코드를 옮기면 복잡도 (native 바이너리의 dynamic fetching 고려 x)를 낮추고 현재 artifacts의 dependency를 임의로 furiosa-models 쪽에 설정해 놓은 것으로 알고 있는데요. 이런 부자연스러움도 해결된다고 봅니다.

모델 개발자가 furiosa-artifacts 만 바라보고 개발할 수 있는 장점도 좋지만, 현재로는 이 개발자가 우리 회사 구성원들이기 때문에 이 걱정은 너무 앞서 하지 않아도 좋지 않을까 생각하네요.

여러 trade off를 고려하면 furiosa-models에 코드를 담는 것이 저는 좋은 선택인 것 같습니다. 저희가 일정이 급하기 때문에 하루 정도만 이 이슈를 오픈해 놓고 그 사이에 특별한 반론이 없으면 결정 하도록 하겠습니다.

furiosamg commented 2 years ago

@ileixe 님이랑 잠시 얘기 나눈 내용 정리해보겠습니다. 말이 매끄럽지 못한 점 미리 양해 부탁드립니다. 제가 생각하는 artifacts와 models이 다른 점은 artifacts에는 모델에 관련된 정보가 있고, models는 furiosa-registry에서 정의한 spec에 입각해 furiosa-artifacts를 바라보는 클라이언트로서의 기능하는 것입니다. 단순히 모델 개발자가 한 레포지토리를 바라보고 개발 가능한 장점이라기보다 전/후처리가 모델 클라이언트에 관련된 게 아니라 모델에 종속된 정보이기 때문에 furiosa-artifacts에 들어가는것이 어떨까 합니다.

모델 이미지 / 코드의 분리와 이 분리는 좀 다른 것 같습니다. 모델 이미지 / 코드가 분리되어야 하는 이유는 코드를 관리하는 git에서 모델 이미지같이 큰 파일을 저장하는 게 올바르지 않아서이지 개념적으로 두 개가 다른 것이라서가 아니라고 생각합니다. 그래서 꼭 다른 곳에 위치할 필요는 없을 것 같습니다. 그리고 그 분리는 이미 DVC를 통해 이룬 게 아닌가 합니다.

또, native 바이너리의 dynamic fetching 하는 어려움 을 제가 잘 이해한 것인지 모르겠지만, furiosa-artifacts에 러스트 코드가 존재한다고 딱히 더 어려워지지 않을 것 같습니다. rust로 쓰인 전/후처리 코드가 furiosa-artifacts 안의 subdirectory에서 package로 따로 관리하면 furiosa-models에서 관리하는것과 크게 다르지 않을 것 같습니다.

즉, 아래와 같이 운영하면 models와 artifacts를 각각 클라이언트, 모델 저장소로 분리하면서 native 바이너리 문제도 괜찮게 해결할 수 있을 것 같습니다.

furiosa-artifacts
|- artifacts.py
|- furiosa
  |- artifacts
    |- vision
      |- ResNet
        |- ResNet.py  (python class) 
        |- ResNet.dvc                                 <- ResNet.onnx (model binary in s3, DVC)
        |- ResNetPrePostProcess  (PyO3 managed python package directory)
          |- preprocess.rs
            ...
      |- Yolov5
         ...
      |- utils  # common vision utilities (PyO3 managed python package directory)
        |- crop.rs
        |- resize.rs

사용자는 furiosa-models만 깔고 furiosa-artifacts에 딸려 있는 종속성들 (PyO3 managed python package directory) 등등은 알아서 resolve.

hyunsik commented 2 years ago

우선 의견 주셔서 감사합니다.

DVC 관련은 제가 follow up을 완전히 못했어서 aritfacts에서 이미지를 fetch 해 오자고 말씀 드렸는데요. 이미 public에서 fetch 해 오고 있다면 더 단순해 질 수 있을 것 같네요.

제 의견을 보다 직설적으로 표현해보면요. furiosa-artifacts와 models의 분리와 정의를 논하고 싶은 것은 아니고요. 그 분리가 애초에 필요한지 묻고 싶은 것입니다. artifacts와 models로 나누고 패키지로 분리하고, client를 사용해서 code를 dynamic fetching을 하고, 비직관적인 의존성 해결도 해야 하는데요. DVC로 모델 이미지가 분리된 상황에서 이렇게 해야 하는 이유가 있는지가 의문입니다. 현재의 furiosa-artifacts 위치가 furiosa-models가 되면 구조가 훨씬 단순해지고 앞서 언급한 여러 복잡성과 문제가 쉽게 해소되는 것은 아닐까요?

예를 들면, 위에 예로 들어주신 source tree에 rust 소스코드가 포함되어 있는데요. 제 이해대로라면 models는 artifacts를 의존하지 않고 fetch를 해오고 있습니다 (혹시 의존성 추가할 것을 염두하신 거라면 furiosa-models와 artifacts의 분리는 더더욱 불필요해집니다). native code의 dynamic fetching이 어려운 이유는 사용자 단에서 rust 소스 코드를 fetching 해서 쓰는 것은 challenge가 정말 많다고 보고요 (native code를 공개 해도 되는지는 추가적인 고민거리 입니다). 사용자의 배포판에 맞는 shared object를 fetching 해와야 하기 때문입니다. manylinux 바이너리를 빌드하는 배포판들은 기본적으로 버전이 매우 낮아서 제약이 상당히 큽니다. quantizer-experimental 프로젝트도 이 문제로 manylinux에서 배포판별 패키징으로 최근에 변경을 진행했습니다. 반면, models에 native code가 있으면 models를 배포판별로 컴파일하여 native wheel 패키지로 만들면 됩니다. 사실 시간과 노력을 들이면 native code도 dynamic fetching을 할 수 있을텐데요. 현 시점에 굳이 복잡도를 높이면서 시간과 리소스를 쏟을 필요가 있는가 있을까요?

다시 말씀 드리면, 단순한 프로젝트의 복잡성을 굳이 높이면서 어떤 가치가 있는지가 의문인데요. 혹시 이유가 있다면, 설명해 주시면 감사하겠습니다.

furiosamg commented 2 years ago

furiosa-artifacts가 models와 분리되어있고 패키징, 설치하지 않는 이유는 모든 모델의 의존성을 해결하지 않고 원하는 모델(들)의 의존성만 dynamic하게 해결하기 위해서인 것으로 알고 있는데요. (전/후처리도 비슷할 것 같습니다) 저는 rust+python 패키지를 패키징하는데 어디에 있든 비슷한 품이 들 것으로 생각했는데 models에 두는 것이 훨씬 손이 덜 간다면 그렇게 하는것이 합리적일 것 같습니다. 상세히 설명해주셔서 감사합니다.

hyunsik commented 2 years ago

최초의 motivation 은 모델 이미지의 동적 로딩이었던 것으로 기억하고 있습니다. 사실 S3를 backend로 쓰면서 motivation 은 의미가 없어졌다고 봐야 할 것 같고요.

의존성의 dynamic한 해결은 커뮤니티 기반의 다양한 사람이 올리는 상황이라면 고려할만하다고 생각합니다. 그런데 model zoo는 우리가 fully managed 하는 상황으로 봐야 할 것 같은데요. 현재 quantizer-experimental 에서도 pytorch 기반 코드를 numpy 로 포팅하고 있거든요. 저희도 이 결과물을 활용하고 이런 방향으로 진행하면 딱히 모델 마다 의존성이 커질 이유는 없는 것 같습니다. 제 예상으로는 pre/post processing에서는 주로 PIL 이나 numpy 정도만 요구되게 될 것 같습니다.

furiosamg commented 2 years ago

저도 그럼 furiosa-models에 두는 게 좋을 것 같아보입니다. 감사합니다!