Closed mh3ong closed 1 year ago
다시 확인해보니, Python 3.10에서 사용가능한 tensorflow 최신버전은 2.12.0이어서 변경 후, cold start 시간 (model loading time) 을 측정해보았습니다. Python 3.10, tf 2.12.0 기준 mobilenet_v1의 model loading 시간이 47초 가량으로 측정되었습니다. Python 3.11, tf 2.13.0 기준 mobilenet_v1의 model loading 시간이 36초 가량으로 측정되었습니다. -> 현재 달라진 요인이 2가지가 있어 추가적인 분석이 필요할 것 같습니다. (기존에는 왜 바로 첫번째 요청도 성공했는지) 달라진 부분 1) Python, tf version 2) Lambda Function도 tfserving과 마찬가지로 API를 통해 tensor값 return (이 영향도 있을 수 있다고 생각합니다.) -> 만약 2번 요소가 많은 영향을 끼친다면 yolo_v5처럼 lambda에서는 모두 s3를 통해 확인해야할 것 같은데, 이렇게 되면 REST vs gRPC의 의미가 퇴색되는 부분이 없지않아 있는거 같아 고민이됩니다.
tensorflow를 lambda에서 사용하는 예제입니다. imagenet 기반 resnet을 사용하며, S3를 사용하는 모습을 보여줍니다. (물론 preprocessing도 lambda에서 진행하기 때문인것같기도합니다.) AWS Blog
무현아 만약에 cold-start 가 문제라면 미리 한번 pre-warming 을 해두고 작업을 하면 어떨까? cold-start 는 지금 우리가 고려하고 있는 부분이 아니아서 해당 변수까지 넣어서 생각하면 문제가 너무 어려워질것 같아. 실험을 할때 미리 많은 요청을 해서 여러 런타임을 warm 해둔 상태에서 측정을 한다면 위에서 이야기한 부분의 염려가 없을까? 파이썬 버전은 통일을 하는게 좋을것 같기는 한데.. 만약 어렵다면 그냥 아마존은 3.11 azure 는 3.10 로 해도 괜찮을것 같아. 이에 대한 충분한 설명만 있으면 괜찮을것 같아. 마찬가지로 파이썬 버전에 따른 성능 측정을 하는게 아닌, 새로운 컨테이너 실행 모델 및 api endpoint 타입에 따른 성능을 비교하는거니까.
현재 진행 상황 알려드립니다. Docker Container image size를 1GB 가량 최적화 하였습니다. (cache, 불필요 dependency 등 여러가지 삭제) 또한, Lambda의 경우 확인해보니, 최초에 실행하면 Lambda에서 ECR에서 가져오고, Lambda에 맞게 이미지를 최적화한다고 합니다. 그래서 완전 최초 실행의 경우, 60초 이상 소요되는 것을 확인 하였고, 그 이후 새롭게 시작되는 Instance는 cold start가 6~9가량만 소요되는 것을 확인했습니다. 그래서 만약 실험환경을 구성한다면 맨 처음만 실행해서 Lambda가 Container image를 optimize할 수 있도록 한뒤 실험 진행하면 될 것 같습니다. 아직 조금 더 최적화 할 수 있는 요소가 남아있어 몇가지만 더 최적화 해보겠습니다. (function code에서 tensorflow import 시, 필요한 부분만 import하는 것 시도)
100개 요청을 보냈을 때, 대략적인 cold start 시간입니다. (mobilenet_v1 기준)
9.490157127380371 6.322850227355957 6.322850227355957 9.490157127380371 6.322850227355957 76.20196437835693 63.576107025146484 6.322850227355957 9.481465339660645 9.490157127380371 63.576107025146484 76.20196437835693 9.481465339660645 9.490157127380371 6.322850227355957 63.576107025146484 9.481465339660645 76.20196437835693 6.322850227355957 63.576107025146484 9.490157127380371 76.20196437835693 63.576107025146484 9.481465339660645 6.322850227355957 9.490157127380371 9.481465339660645 6.322850227355957 76.20196437835693 63.576107025146484 6.322850227355957 9.490157127380371 76.20196437835693 63.576107025146484 9.481465339660645 9.490157127380371 6.322850227355957 76.20196437835693 9.481465339660645 9.490157127380371 63.576107025146484 6.322850227355957 76.20196437835693 9.481465339660645 9.490157127380371 6.578476190567017 6.720191478729248 6.732844591140747 6.541731357574463 5.807072401046753 6.504401922225952 6.7856128215789795 6.727407693862915 6.334392070770264 6.911748647689819 6.753042221069336 6.95327615737915 6.661570310592651 6.726925849914551 6.882930517196655 6.606353998184204 6.77880072593689 6.838823318481445 6.68741250038147 6.736119031906128 6.607654571533203 6.360771179199219 6.723068714141846 6.804444074630737 6.596765995025635 6.764508962631226 6.507267713546753 6.705890893936157 6.579082012176514 6.842588901519775 6.563562393188477 6.955254793167114 6.607333421707153 6.8558995723724365 6.97793436050415 6.812344551086426 6.648237705230713 6.711645841598511 6.709664344787598 6.5743536949157715 6.638768911361694 7.107967138290405 6.681656837463379 6.878461837768555 7.008384943008423 6.7360382080078125 6.739152669906616 6.818785190582275 6.813144683837891 6.816616058349609 6.83118200302124 6.8795623779296875 6.924665212631226 7.119152784347534 7.38456916809082
최초 (1\~2개 정도 제외하고[이미지 최적화 전 하나를 더돌려서 2가지가 60초 이상으로 나타납니다.] 모두 6~9초 사이에 Cold Start가 끝나는 것을 확인할 수 있습니다.)
faas code에서 (app.py, init.py) 에서 import tensorflow as tf 대신 from tensorflow.keras.models import load_model 로 변경하는 것을 통해 최초 실행도 15초 내로 단축하였습니다. (그 이후 optimized 된 이미지로 실행되는 cold start는 6~7초 대로 큰 차이를 보이진 않습니다.)
Lambda Function 생성 후 최초 실행 (Lambda 자체적인 Container Image Optimize 전(추정)) mobilenet_v1 : 14.212881803512573 mobilenet_v2 : 16.50628972053528 inception_v3 : 35.05376696586609 yolo_v5 : 14.783098936080933 bert_imdb : 95.6385338306427
Lambda Container Image Optimized (추정) 후 cold start 최소 시간 mobilenet_v1 : 6.554165840148926 mobilenet_v2 : 6.402066469192505 inception_v3 : 10.428669929504395
yolo_v5 : 3.562103509902954 bert_imdb : 9.686630964279175
추가적인 사항으로, 300번의 request를 전송할 때, 예전 tfserving rest에서 경험했던 것처럼 queue에 쌓이는 느낌이 들었습니다. (한번에 출력되지 않는 현상) python code문제인지 API Gateway에서 한번에 수용할 수 있는 요청의 개수가 있는지 알아보도록 하겠습니다.
이야 무현아 잘했다. 1G 를 줄였다면 지금 사이즈는 2GB 정도 되는거지? 어떤 부분에서 줄일수있었는지 궁금하다. 그리고 위의 코멘트 중에 "Lambda가 Container image를 optimize" 이건 나도 처음 들어보는 이야기인데, 근거가 되는 자료가 있을까? 보여준 데이터에 기반하면 해당 언급이 설득력이 있는것 같아. 논문에서 언급하려면 정확안 문서 혹은 논문들이 있다면 좋을것 같아.
"import tensorflow as tf 대신 from tensorflow.keras.models import load_model" 이 부분도 나이스.
대략적인 시간을 봤을대 이정도라면 cloud run 과 충분히 비교가 가능하겠다는 생각이 드네. 시도하고자 하는 최적화 단계가 조금 더 있다면 조금 더 시도해보고 실험을 시작해보자.
사이즈 최적화의 경우 아래 내용을 사용했습니다.
최적화 내용의 경우, ChatGPT가 살짝 언급하길래 AWS Docs 다 뒤져보았는데 자세한 내용은 없었습니다. 그러나 AWS 공식 블로그에서 아래와 같은 내용을 볼 수 있었습니다. (물론 여기도 그렇다고만 나와있고 상세한 내용은 없습니다.)
When creating or updating the code of a function, the Lambda platform optimizes new and updated container images to prepare them to receive invocations. This optimization takes a few seconds or minutes, depending on the size of the image. After that, the function is ready to be invoked. I test the function in the console.
AWS Blog - New for AWS Lambda – Container Image Support
Azure Function은 어떤 원리로 Containerized FaaS가 실행되는지 모르겠지만, Lambda에서 적용한 방법을 적용하였을 때 개선이 있었는지 확인해보겠습니다.
영어 Blog (Container Image Support in AWS Lambda Deep Dive) 이 글에서는 최적화된 Lambda Container Image가 cache로 14일간 저장된다고 나와있습니다. (물론 공식자료가 아니기 때문에 검증해볼 필요는 있습니다.)
Lambda의 State에 대한 AWS Blog도 봐볼만 한 것 같습니다. (Active 상태가 되면 Container Image를 쓰는 경우 최적화 된 상태가 유지되었다 라고 보면 될 것 같습니다.) AWS Blog - tracking-the-state-of-lambda-functions
Python version을 downgrade하면서 tensorflow version에 한가지 issue가 추가되었습니다.
Exception: ImportError: cannot import name 'builder' from 'google.protobuf.internal' (/azure-functions-host/workers/python/3.10/LINUX/X64/google/protobuf/internal/init.py). Please check the requirements.txt file for the missing module. For more info, please refer the troubleshooting guide: https://aka.ms/functions-modulenotfound
-> 모든 tensorflow 버전을 다시 2.11.1로 downgrade (tfserving 포함) 및 grpc에도 영향이 있을 수 있기 때문에 protobuf version을 3.19.6으로 fix할 예정입니다. (다시 내린다 해도 큰 issue는 없을 것으로 보입니다.) tf version downgrade에 따른 lambda 영향 간단히 check 후 Azure Function Cold Start check 해보겠습니다.
오케이. 무현아. 블로그라도 aws 에서 나온 내용이라면 그래도 신빙성은 있어보인다. 그리고 azure 때문에 그런 문제가 생긴다면 전체적으로 다운그레이드 하는건 반대. main 은 대표 FaaS (aws lambda) 및 대표 SCS (gcp cloud run) 인 만큼 azure 때문에 일정이 딜레이 되는건 피하고 싶어. azure 는 되면 좋지만 안되면 어쩔수 없는 정도로 보면 어떨까 싶어.
다운그레이드 후 테스트하는데는 작업 시작 후 30분~1시간 내로 마무리 될 것 같습니다. 만약 다운그레이드 했을 때, 다시 추가적인 issue가(Cold Start시간 배로 걸린다던지)하나라도 발생한다면 Azure는 제외하고 진행하는 방향으로 진행하겠습니다. 13시부터 진행해보도록 하겠습니다.
오케이, 그렇게 해보자. 람다 이미지 런타임 최적화의 경우 아래 링크가 공식 document 여서 논문에서 참조할만 하겠다. 명시적으로 Active state 가 되기 전에 optimize 한다는 말이 있네.
https://docs.aws.amazon.com/lambda/latest/dg/invocation-images.html
Tensorflow version downgrade에 따른 문제는 AWS Lambda에서 특별하게 발생하지 않았으며, Azure Function에서도 AWS Lambda와 유사하게 Optimize 되는 과정이 있는지 최초 실행은 상당히 느리지만 한번 실행만 하면 이후 Cold Start에서도 그 상태가 지속적으로 유지되는 것 같습니다. 실험을 하면서 더 지켜봐야하겠지만 당장은 큰 문제가 없다고 판단되어 issue close 하겠습니다.
Azure Function의 경우, Runtime이 Python 3.10 까지 밖에 지원하지 않아,
실험의 일관성을 위해 다른 환경의 Python version을 3.10(기존 : 3.11)으로 변경하고 이에 다라 Tensorflow 버전도 호환 가능하도록 downgrade (변경 : 2.11.1, 기존 : 2.13.0) 하였는데, tfserving이야 원래 C++으로 작성되어 큰 문제가 없으나,
Python Code로 작성된 Lambda의 경우 Cold Start 시간이 API Gateway의 Max timeout인 30초를 넘어가버려 첫 번째 호출에서 오류가 무조건 발생하게 됩니다. (기존 3.11.3에서 작업할 때는 30초 내에 model loading이 완료되어 큰 문제가 없었습니다.)
이는 Python 3.11에서 있었던 속도 향상 (약50% 증가)로 인한 문제인것 같습니다.
현재 지원되는 범위는 아래와 같습니다. AWS : 3.11 (preview) GCP : 3.11 (prod) Azure : 3.11 (not available, 3.10 is newest version)