sLLM과 vLLM 완벽 설치 가이드 – CPU/GPU 환경별 설치부터 FastAPI 배포까지

대화형 AI 모델을 로컬에서 실행하고 싶지만 어떤 도구를 선택해야 할지 고민이신가요? sLLM과 vLLM은 각각 다른 장점을 가진 훌륭한 LLM 추론 도구입니다. 이 가이드에서는 두 도구의 차이점부터 다양한 설치 방법, 그리고 FastAPI를 통한 서비스 배포까지 모든 과정을 상세하게 다뤄보겠습니다.

sLLM vs vLLM: 핵심 차이점 이해하기

sLLM (Small Language Model Manager)의 특징

sLLM은 작은 규모의 언어 모델들을 효율적으로 관리하고 실행하는 데 특화된 도구입니다. 이름에서 알 수 있듯이 ‘Small’ 언어 모델에 최적화되어 있어 리소스가 제한적인 환경에서도 잘 작동합니다.

주요 장점으로는 낮은 메모리 사용량, 빠른 모델 로딩 시간, 간단한 설정 과정이 있습니다. 특히 CPU 환경에서도 합리적인 성능을 제공하여 GPU가 없는 개발 환경에서도 충분히 활용할 수 있습니다.

적합한 용도는 프로토타이핑, 개발 단계에서의 테스트, 소규모 서비스, 그리고 교육 목적의 실험 등입니다. 또한 여러 모델을 번갈아가며 테스트해야 하는 연구 환경에서도 유용합니다.

vLLM (Very Large Language Model)의 특징

vLLM은 대규모 언어 모델의 추론 성능을 극대화하는 데 집중한 고성능 추론 엔진입니다. Meta의 연구진이 개발한 이 도구는 특히 처리량(throughput) 최적화에 뛰어납니다.

핵심 기술로는 PagedAttention이라는 혁신적인 메모리 관리 기법을 사용합니다. 이는 GPU 메모리를 더 효율적으로 활용하여 동시에 더 많은 요청을 처리할 수 있게 해줍니다. 또한 연속 배치 처리(Continuous Batching)를 통해 지연 시간을 최소화합니다.

성능 특징으로는 기존 HuggingFace Transformers 대비 최대 24배 빠른 처리 속도와 더 높은 처리량을 자랑합니다. 특히 상용 서비스 환경에서 그 진가를 발휘합니다.

적합한 용도는 프로덕션 환경에서의 대규모 서비스, 높은 동시 접속이 예상되는 애플리케이션, 그리고 응답 속도가 중요한 실시간 서비스 등입니다.

CPU 환경에서의 설치 방법

sLLM CPU 설치

CPU 환경에서 sLLM을 설치하는 것은 비교적 간단합니다. 먼저 Python 3.8 이상의 환경이 필요합니다.

가상환경 생성 및 활성화부터 시작합니다:

python -m venv sllm_env
source sllm_env/bin/activate  # Windows: sllm_env\Scripts\activate

pip를 통한 기본 설치:

pip install --upgrade pip
pip install sllm

의존성 패키지 설치도 필요합니다:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install transformers accelerate

설치 후 정상 작동 여부를 확인하려면 간단한 테스트를 해보세요:

from sllm import SLLM
model = SLLM("microsoft/DialoGPT-small")
response = model.generate("Hello, how are you?")
print(response)

vLLM CPU 설치

vLLM은 기본적으로 GPU에 최적화되어 있지만 CPU 환경에서도 실행할 수 있습니다. 다만 성능은 제한적입니다.

CPU 전용 설치:

pip install vllm-cpu

또는 소스에서 CPU 빌드:

export VLLM_TARGET_DEVICE=cpu
pip install vllm

CPU 환경에서의 사용 예시:

from vllm import LLM, SamplingParams

llm = LLM(model="facebook/opt-125m", device="cpu")
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
outputs = llm.generate(["Hello, my name is"], sampling_params)

참고로 CPU 환경에서는 vLLM의 고성능 기능들이 제한적으로 동작하므로, CPU 환경이라면 sLLM을 사용하는 것이 더 효율적일 수 있습니다.

GPU 환경에서의 설치 방법

GPU 환경 준비사항

GPU 설치 전에 CUDA 환경이 제대로 설정되어 있는지 확인해야 합니다. NVIDIA 드라이버와 CUDA Toolkit이 설치되어 있어야 합니다.

현재 CUDA 버전 확인:

nvidia-smi
nvcc --version

권장 환경은 CUDA 11.8 이상, GPU 메모리 8GB 이상입니다. 더 큰 모델을 사용하려면 16GB 이상의 GPU 메모리가 필요합니다.

sLLM GPU 설치

GPU 환경에서 sLLM 설치는 CUDA 지원 PyTorch와 함께 설치해야 합니다:

# CUDA 11.8 환경
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install sllm

# CUDA 12.1 환경
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install sllm

GPU 사용 확인:

import torch
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"GPU count: {torch.cuda.device_count()}")

from sllm import SLLM
model = SLLM("microsoft/DialoGPT-medium", device="cuda")

vLLM GPU 설치

vLLM의 GPU 설치는 매우 간단합니다:

pip install vllm

고급 설치 옵션으로 특정 CUDA 버전 지정:

# CUDA 11.8
pip install vllm --extra-index-url https://download.pytorch.org/whl/cu118

# CUDA 12.1  
pip install vllm --extra-index-url https://download.pytorch.org/whl/cu121

멀티 GPU 설정:

from vllm import LLM, SamplingParams

# 모든 가용 GPU 사용
llm = LLM(model="meta-llama/Llama-2-7b-hf", tensor_parallel_size=2)

# 특정 GPU만 사용
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"
llm = LLM(model="meta-llama/Llama-2-7b-hf")

Python -m을 통한 설치 방법

Python 모듈 방식의 장점

-m 플래그를 사용한 설치 방법은 현재 Python 환경과의 호환성을 보장하고, 경로 문제를 방지할 수 있습니다.

sLLM 모듈 설치:

python -m pip install sllm
python -m pip install torch torchvision torchaudio

vLLM 모듈 설치:

python -m pip install vllm

개발 환경 설정을 위한 추가 패키지:

python -m pip install jupyter notebook ipython
python -m pip install fastapi uvicorn
python -m pip install requests aiohttp

가상환경과 함께 사용하기

프로젝트별 환경 분리가 중요합니다:

# sLLM 전용 환경
python -m venv sllm_project
source sllm_project/bin/activate
python -m pip install sllm transformers

# vLLM 전용 환경  
python -m venv vllm_project
source vllm_project/bin/activate
python -m pip install vllm

requirements.txt 활용:

# sllm_requirements.txt
sllm>=1.0.0
transformers>=4.21.0
torch>=2.0.0
fastapi>=0.104.0
uvicorn>=0.24.0

# vllm_requirements.txt
vllm>=0.2.0
fastapi>=0.104.0
uvicorn>=0.24.0

설치 실행:

python -m pip install -r sllm_requirements.txt

Docker를 통한 설치 방법

vLLM 공식 Docker 이미지 사용

Docker를 사용하면 환경 설정의 복잡함 없이 바로 사용할 수 있습니다.

기본 vLLM 이미지 실행:

docker pull vllm/vllm-openai:latest
docker run --runtime nvidia --gpus all \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    -p 8000:8000 \
    --ipc=host \
    vllm/vllm-openai:latest \
    --model facebook/opt-125m

환경 변수와 함께 실행:

docker run --runtime nvidia --gpus all \
    -e HUGGING_FACE_HUB_TOKEN=your_token_here \
    -e VLLM_WORKER_MULTIPROC_METHOD=spawn \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    -p 8000:8000 \
    vllm/vllm-openai:latest \
    --model meta-llama/Llama-2-7b-chat-hf \
    --tensor-parallel-size 2

커스텀 Docker 이미지 생성

sLLM용 Dockerfile:

FROM python:3.10-slim

WORKDIR /app

# 시스템 의존성 설치
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# Python 패키지 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 코드 복사
COPY . .

EXPOSE 8000

CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

빌드 및 실행:

docker build -t my-sllm-app .
docker run -p 8000:8000 my-sllm-app

Docker Compose 설정

docker-compose.yml:

version: '3.8'

services:
  vllm-service:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
    volumes:
      - ~/.cache/huggingface:/root/.cache/huggingface
    ports:
      - "8000:8000"
    command: ["--model", "facebook/opt-125m", "--host", "0.0.0.0"]
    
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - vllm-service

실행:

docker-compose up -d

FastAPI + Uvicorn으로 임시 서비스 구축

sLLM FastAPI 서비스

기본 FastAPI 애플리케이션 구조:

# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sllm import SLLM
import asyncio
from typing import Optional

app = FastAPI(title="sLLM API Service", version="1.0.0")

# 모델 전역 변수
model = None

class ChatRequest(BaseModel):
    message: str
    max_length: Optional[int] = 100
    temperature: Optional[float] = 0.8

class ChatResponse(BaseModel):
    response: str
    model_name: str

@app.on_event("startup")
async def startup_event():
    global model
    print("Loading sLLM model...")
    model = SLLM("microsoft/DialoGPT-medium")
    print("Model loaded successfully!")

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    if model is None:
        raise HTTPException(status_code=503, detail="Model not loaded")
    
    try:
        # 비동기 처리를 위한 executor 사용
        loop = asyncio.get_event_loop()
        response = await loop.run_in_executor(
            None, 
            lambda: model.generate(
                request.message,
                max_length=request.max_length,
                temperature=request.temperature
            )
        )
        
        return ChatResponse(
            response=response,
            model_name="microsoft/DialoGPT-medium"
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
async def health_check():
    return {"status": "healthy", "model_loaded": model is not None}

vLLM FastAPI 서비스

vLLM 통합 서비스:

# vllm_main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from vllm import LLM, SamplingParams
from typing import Optional, List
import asyncio

app = FastAPI(title="vLLM API Service", version="1.0.0")

# vLLM 모델 전역 변수
vllm_model = None

class GenerateRequest(BaseModel):
    prompt: str
    max_tokens: Optional[int] = 100
    temperature: Optional[float] = 0.8
    top_p: Optional[float] = 0.95
    n: Optional[int] = 1

class GenerateResponse(BaseModel):
    generated_text: List[str]
    model_name: str

@app.on_event("startup")
async def startup_event():
    global vllm_model
    print("Loading vLLM model...")
    # GPU 메모리에 따라 모델 선택
    vllm_model = LLM(
        model="facebook/opt-1.3b",
        tensor_parallel_size=1,  # GPU 수에 따라 조정
        gpu_memory_utilization=0.9
    )
    print("vLLM model loaded successfully!")

@app.post("/generate", response_model=GenerateResponse)
async def generate(request: GenerateRequest):
    if vllm_model is None:
        raise HTTPException(status_code=503, detail="Model not loaded")
    
    try:
        sampling_params = SamplingParams(
            temperature=request.temperature,
            top_p=request.top_p,
            max_tokens=request.max_tokens,
            n=request.n
        )
        
        # vLLM은 배치 처리를 지원하므로 리스트로 전달
        outputs = vllm_model.generate([request.prompt], sampling_params)
        
        generated_texts = []
        for output in outputs:
            for generated_output in output.outputs:
                generated_texts.append(generated_output.text)
        
        return GenerateResponse(
            generated_text=generated_texts,
            model_name="facebook/opt-1.3b"
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/models")
async def list_models():
    return {"available_models": ["facebook/opt-1.3b"]}

서비스 실행 및 테스트

개발 서버 실행:

# sLLM 서비스
uvicorn main:app --reload --host 0.0.0.0 --port 8000

# vLLM 서비스  
uvicorn vllm_main:app --reload --host 0.0.0.0 --port 8001

프로덕션 환경 실행:

# 멀티 워커로 실행
uvicorn main:app --workers 4 --host 0.0.0.0 --port 8000

# Gunicorn과 함께 사용
pip install gunicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

API 테스트:

import requests

# sLLM 테스트
response = requests.post(
    "http://localhost:8000/chat",
    json={"message": "Hello, how are you?", "temperature": 0.7}
)
print(response.json())

# vLLM 테스트
response = requests.post(
    "http://localhost:8001/generate",
    json={"prompt": "The future of AI is", "max_tokens": 50}
)
print(response.json())

성능 최적화 및 운영 팁

메모리 관리

GPU 메모리 최적화를 위해서는 모델 크기에 맞는 배치 크기 조정이 중요합니다. vLLM의 경우 gpu_memory_utilization 파라미터를 0.8-0.9 정도로 설정하여 OOM을 방지하세요.

CPU 메모리 관리도 중요합니다. 특히 sLLM에서는 모델 로딩 시 충분한 시스템 메모리가 있는지 확인하고, 필요시 스왑 메모리를 활용하세요.

모니터링 및 로깅

애플리케이션 로깅:

import logging
from fastapi import FastAPI

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@app.middleware("http")
async def log_requests(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    logger.info(f"Path: {request.url.path}, Time: {process_time:.4f}s")
    return response

에러 처리 및 복구

견고한 에러 처리를 구현하여 서비스 안정성을 확보하세요:

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    logger.error(f"Global exception: {str(exc)}")
    return JSONResponse(
        status_code=500,
        content={"detail": "Internal server error", "error": str(exc)}
    )

이제 sLLM과 vLLM 모두를 자유자재로 설치하고 운영할 수 있는 기반을 갖추셨습니다. 프로젝트의 규모와 요구사항에 맞는 도구를 선택하여 효율적인 LLM 서비스를 구축해보세요!

Leave a Comment