FastAPI를 이용한 추론 모델 배포 (feat.docker)
.py 파일을 통해 분류를 수행하는데, 인코더 모델의 경우 매번 .py 파일을 실행할 때마다 메모리에 로드되었고, 이로 인해 결과값을 받아보는데 생각보다 시간이 소요되었다. 이를 해결하기 위해 다음과 같은 방법들을 고려할 수 있는데, 여기서는 이 중 FastAPI를 이용해 예측을 수행하는 과정에 대해 다뤄보고자 한다.
1. Hugging Face 캐싱 확인
2. 모델 캐시 파일 재사용
3. 웹 프레임워크(Flask, FastAPI)를 사용해 모델을 서버 형태로 배포
- 서버 형태로 배포할 경우 예측 요청이 들어올 때마다 이미 로드된 모델로 예측을 수행하게 할 수 있다.
Method 1. classifier = pipeline("sentiment-analysis", model="microsoft/deberta-base", device=0)
* 모델을 로컬 디렉토리에 저장한 경우 캐싱이 제대로 동작하지 않을 수 있음
Method 2. model = AutoModelForSequenceClassification.from_pretrained('path_to_cache', cache_dir="/your/cache/dir")
Step 0. 기본 설정
개발은 모두 도커 환경에서 진행한다. 처음에는 하나의 도커 컨테이너 내에서 FastAPI 웹 서버도 띄우고, 모델 학습 및 추론 등과 같은 작업을 수행하려 했다. 그런데 이러한 방식으로 진행할 경우 당장에는 무리가 없지만 점점 규모가 커지면 독립성 부재로 인한 문제가 발생할 수 있을 것 같았고, FastAPI 웹 서버용 컨테이너 하나, 모델 학습 및 추론용 컨테이너 하나로 개발을 진행하기로 했다. (도커를 분리해서 진행하다보니, 하나로 퉁쳐서 진행할 때에는 없었던 문제 - 네트워크 연결 등 - 들이 여럿 발생하였고 이 과정 또한 여기서 다뤄보고자 한다)
FastAPI Container
FastAPI를 빌드하기 위한 Dockerfile은 다음과 같이 작성했다. 아직 .yaml 파일은 미숙해서 웬만한 세팅은 Dockerfile로 하고 있다.
FROM pytorch/pytorch:latest
WORKDIR /fastapi
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
# 패키지 설치 (한글 입력을 위한 locale)
ENV LC_ALL ko_KR.UTF-8
RUN apt-get update && apt-get install -y locales
RUN locale-gen ko_KR.UTF-8
RUN apt-get update && apt-get install git -y
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
requirements.txt 내용은 더보기에서 확인할 수 있다.
fastapi
uvicorn
transformers
sentence-transformers
openai
pandas
numpy
load_dotenv
spacy
tqdm
datasets
huggingface-hub
ipykernel
evaluate
python-multipart
.Dockerfile, requirements.txt, main.py 파일이 있는 곳에서 도커 이미지를 빌드하고, 실행해보자.
docker build -t fastapi-image .
docker run -d --gpus all --network cori_network -it -v [local dir]:[container dir] --name fastapi-cori -p 8000:8000 fastapi-cori
빌드가 잘 되었다면 다행인데, 오류가 발생할 수 있다. 실제로 빌드가 잘 된 것처럼 보였지만, fastapi 웹 서버가 동작하지 않고 있는 경우도 있었고, 빌드 부분에서부터 막힌적도 있었다. 에러들을 디버깅하기 위해, 다음 명령어들을 남발했다.
docker logs fastapi-cori # 컨테이너 관련 로그들을 찍어볼 수 있음
docker stop fastapi-cori
docker rm fastapi-cori
docker exec -it fastapi-cori /bin/bash # 실행중인 fastapi 컨테이너 접속
apt-get update -y
apt-get install curl -y # curl http://localhost:8000 명령어를 통해 연결 확인
docker exec -it fastpi-cori /bin bash 명령어를 통해 해당 컨테이너에 들어가서 직접 내부 구조를 살펴볼 수 있었기에 많은 도움이 되었다. 최종적으로 잘 동작하는 것을 확인하려면, 컨테이너 내에서 다음과 같이 입력했을 때 제대로 나오면 된다.
ps aux | grep uvicorn # uvicorn process 확인
uvicorn main:app --host 0.0.0.0 --port 8000 --reload # 없을 경우
curl http://fastapi-cori:8000
* Application startup complete 까지 나와야 함 !!
모델 학습 및 추론 도커 설정은 각기 다르므로 여기서는 생략한다.
Step 1. 도커 간 연결 확인 (네트워크 설정)
남은 작업은, 모델 학습 및 추론용 컨테이너에 대한 설정이다. 해당 컨테이너에서 Fastapi 컨테이너에서 띄운 웹서비스에 접근하기 위해서는 두 컨테이너가 동일한 네트워크를 사용하고 있어야 한다. 컨테이너가 기본적으로 같은 네트워크에 있지 않으면 서로 통신할 수 없다 !!
통신을 위한 네트워크를 생성해서, 두 컨테이너가 해당 네트워크를 사용하도록 설정해주자.
docker network create cori_network
# fastapi 컨테이너
docker run --gpus all -d --network cori_network ... (생략) --name fastapi-cori [image id]
# 모델 학습 및 추론 컨테이너
docker run --gpus all --network cori_network ... (생략) [image id]
이제 두 컨테이너는 cori_network라는 동일한 네트워크에서 실행되며, fastapi-cori 라는 이름을 사용하여 다른 컨테이너에서 FastAPI 서버에 접근할 수 있다.
# 모델 학습 및 추론 컨테이너에서 다음 명령어 입력
curl http://fastapi-cori:8000
여기서 주의할 점은, 이제는 http://localhost:8000 혹은 http://127.0.01:8000 같은 방식으로는 FastAPI 컨테이너에 접근할 수 없다는 것이다. localhost 부분에 FastAPI 컨테이너 이름을 지정해서 접근해줘야 한다. 다음 명령어를 사용하면 도커 컨테이너들이 동일한 네트워크에 연결되어 있는지 알 수 있다.
docker network inspect cori_network
이를 통해 FastAPI 컨테이너의 ip 주소 또한 얻을 수 있는데, fastapi-cori 대신 해당 컨테이너의 ip address를 사용하여 접근해도 된다.
Step 2. Curl 명령어를 이용한 모델 추론
여기부터는 main.py 파일에서 추론 코드를 조금씩 입맞에 맞게 작성해주면 된다. main.py 파일에 predict() 함수를 정의하고, 입력으로 텍스트 또는 csv 파일이 들어온 경우 이에 대한 예측을 하도록 코드를 구성했다. 학습 및 추론 컨테이너에서 다음과 같이 curl 명령어를 던져주면 추론이 진행되며, 한번 모델을 로드하면 더 이상 모델 로드를 하지 않기에 추론 속도가 상당히 향상된다.
curl -X POST "http://localhost:8000/predict" -H "Content-Type: multipart/form-data" -F "file=@data/predict/mini-pred-error.csv" -o test.csv
curl -X POST "http://localhost:8000/predict" -H "Content-Type: application/json" -d '{"text": "OO전자 상향가야 ?"}'
Step 3. 컨테이너 배포
도커 컨테이너를 배포하는 여러 방식이 있으나, 여기서는 간단하게 docker hub에 배포를 해본다.
우선, docker hub에 로그인을 한다.
docker login
docker hub에 푸시하기 전에 이미지를 태깅하고, 태깅된 이미지를 푸시한다.
docker tag fastapi-cori [docker hub user id]/fastapi-cori
docker push [docker hub user id]/fastapi-cori
허브에 업로드 된 이미지는 다른 서버나 클라우드 서비스에서 다음 명령어로 이미지를 가져와 실행할 수 있다.
docker pull [docker hub user id]/fastapi-cori