플러팅 AI/Flask Server

서버 Docker 시작전에 모델 로드하기

Solo.dev 2024. 11. 20. 17:35

Docker 컨테이너 실행 시 머신러닝/딥러닝 모델을 미리 로드하여

애플리케이션 초기화 시간을 줄이고, 런타임 성능을 최적화하는 방법에 대해 알아보겠습니다.

 

1. 모델 관리 클래스 작성 (ModelManager)

  • 싱글톤 패턴을 사용하여 모델 로드와 재사용을 관리합니다.
  • 모델 로드를 병렬로 처리해 초기화 시간을 단축합니다.
from gevent.pool import Pool
from gevent import lock

class ModelManager:
    _instance = None
    _lock = lock.Semaphore()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(ModelManager, cls).__new__(cls)
                    cls._instance.initialize_models()
        return cls._instance

    def initialize_models(self):
        """모델을 병렬로 로드합니다."""
        pool = Pool(4)  # 최대 4개의 병렬 작업
        pool.spawn(self.load_ocr_model)
        pool.spawn(self.load_yolo_model)
        pool.spawn(self.load_openai_client)
        pool.spawn(self.load_onnx_model)
        pool.join()
        print("모든 모델 로드 완료.")

    def load_ocr_model(self):
        print("OCR 모델 로드 중...")
        # OCR 모델 로드 로직

    def load_yolo_model(self):
        print("YOLO 모델 로드 중...")
        # YOLO 모델 로드 로직

    def load_openai_client(self):
        print("OpenAI 클라이언트 초기화 중...")
        # OpenAI API 클라이언트 초기화

    def load_onnx_model(self):
        print("ONNX 모델 로드 중...")
        # ONNX 모델 로드 로직

정리: 왜 모델 로드가 되는가?

  1. __new__ 메서드: 인스턴스 생성 시 initialize_models가 호출되도록 설계되어 있음.
  2. 싱글톤 패턴: 모델 로드는 최초 인스턴스 생성 시 한 번만 수행되며, 이후에는 동일한 인스턴스를 재사용.

 

2. 초기화 함수 작성 (initialize_server)

  • Flask 서버가 시작되기 전에 모델을 로드합니다.
def initialize_server():

    try:
        logger.info("서버 초기화를 시작합니다.")
        model_manager = ModelManager()
        logger.info("모델 초기화 완료.")
    except Exception as e:
        logger.error(f"서버 초기화 중 오류 발생: {e}")
        logger.error(traceback.format_exc())
        raise

 

3. Docker에서 실행

  • Docker 컨테이너의 CMD를 설정하여 서버 시작 전에 initialize_server를 호출합니다.
  • docker file에 작성 해서 빌드  
    gunicorn --workers=1 --threads=2 --timeout=120 \
    --worker-class=geventwebsocket.gunicorn.workers.GeventWebSocketWorker \
     
    --bind=0.0.0.0:8080 flask_server:app"]
  • CMD ["bash", "-c", "python -c 'from flask_server import initialize_server; initialize_server()' && \