- FastAPI 백엔드 (audio-studio-api) - Next.js 프론트엔드 (audio-studio-ui) - Qwen3-TTS 엔진 (audio-studio-tts) - MusicGen 서비스 (audio-studio-musicgen) - Docker Compose 개발/운영 환경 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
214 lines
4.9 KiB
Markdown
214 lines
4.9 KiB
Markdown
# GPU 로컬 모델 인프라 (GPU Local Models)
|
||
|
||
로컬 LLM/ML 모델 서빙을 위한 GPU 인프라 가이드입니다.
|
||
|
||
## GPU 인벤토리
|
||
|
||
| GPU | VRAM | 수량 | 용도 |
|
||
|-----|------|------|------|
|
||
| NVIDIA V100 | 16GB | 8 | 중형 모델, 병렬 추론 |
|
||
| NVIDIA V100 | 32GB | 4 | 대형 모델, 파인튜닝 |
|
||
| NVIDIA RTX 3090 | 24GB | 2 | 개발/테스트, 중형 모델 |
|
||
|
||
**총 VRAM**: 16×8 + 32×4 + 24×2 = 128 + 128 + 48 = **304GB**
|
||
|
||
## VRAM별 모델 가이드
|
||
|
||
### 16GB (V100 16GB, 단일)
|
||
- Llama 3.1 8B (Q4 양자화)
|
||
- Mistral 7B
|
||
- Phi-3 Medium
|
||
- Gemma 2 9B
|
||
|
||
### 24GB (RTX 3090)
|
||
- Llama 3.1 8B (FP16)
|
||
- Qwen2.5 14B (Q4)
|
||
- CodeLlama 13B
|
||
|
||
### 32GB (V100 32GB, 단일)
|
||
- Llama 3.1 70B (Q4 양자화)
|
||
- Qwen2.5 32B
|
||
- DeepSeek Coder 33B
|
||
|
||
### 멀티 GPU (텐서 병렬)
|
||
- V100 32GB × 2 (64GB): Llama 3.1 70B (FP16)
|
||
- V100 32GB × 4 (128GB): Llama 3.1 70B + 여유 / 대형 모델
|
||
- V100 16GB × 8 (128GB): 대규모 배치 추론
|
||
|
||
## 모델 서빙 프레임워크
|
||
|
||
### vLLM (권장)
|
||
```bash
|
||
# Docker 실행
|
||
docker run --gpus all -p 8000:8000 \
|
||
-v ~/.cache/huggingface:/root/.cache/huggingface \
|
||
vllm/vllm-openai:latest \
|
||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||
--tensor-parallel-size 1
|
||
```
|
||
|
||
### Text Generation Inference (TGI)
|
||
```bash
|
||
docker run --gpus all -p 8080:80 \
|
||
-v ~/.cache/huggingface:/data \
|
||
ghcr.io/huggingface/text-generation-inference:latest \
|
||
--model-id meta-llama/Llama-3.1-8B-Instruct
|
||
```
|
||
|
||
### Ollama (개발/테스트용)
|
||
```bash
|
||
# 설치
|
||
curl -fsSL https://ollama.com/install.sh | sh
|
||
|
||
# 모델 실행
|
||
ollama run llama3.1:8b
|
||
```
|
||
|
||
## Docker Compose GPU 패턴
|
||
|
||
### 단일 GPU 서비스
|
||
```yaml
|
||
services:
|
||
llm-server:
|
||
image: vllm/vllm-openai:latest
|
||
container_name: {프로젝트}-llm
|
||
restart: unless-stopped
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: 1
|
||
capabilities: [gpu]
|
||
environment:
|
||
- HUGGING_FACE_HUB_TOKEN=${HF_TOKEN}
|
||
volumes:
|
||
- ~/.cache/huggingface:/root/.cache/huggingface
|
||
ports:
|
||
- "8000:8000"
|
||
command: >
|
||
--model meta-llama/Llama-3.1-8B-Instruct
|
||
--max-model-len 8192
|
||
networks:
|
||
- {프로젝트}-network
|
||
```
|
||
|
||
### 멀티 GPU 텐서 병렬
|
||
```yaml
|
||
services:
|
||
llm-large:
|
||
image: vllm/vllm-openai:latest
|
||
container_name: {프로젝트}-llm-large
|
||
restart: unless-stopped
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: 4
|
||
capabilities: [gpu]
|
||
environment:
|
||
- HUGGING_FACE_HUB_TOKEN=${HF_TOKEN}
|
||
- CUDA_VISIBLE_DEVICES=0,1,2,3
|
||
volumes:
|
||
- ~/.cache/huggingface:/root/.cache/huggingface
|
||
ports:
|
||
- "8001:8000"
|
||
command: >
|
||
--model meta-llama/Llama-3.1-70B-Instruct
|
||
--tensor-parallel-size 4
|
||
--max-model-len 4096
|
||
networks:
|
||
- {프로젝트}-network
|
||
```
|
||
|
||
### 특정 GPU 지정
|
||
```yaml
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
device_ids: ['0', '1'] # GPU 0, 1 지정
|
||
capabilities: [gpu]
|
||
```
|
||
|
||
## API 통합 패턴
|
||
|
||
### OpenAI 호환 클라이언트 (vLLM)
|
||
```python
|
||
from openai import AsyncOpenAI
|
||
|
||
client = AsyncOpenAI(
|
||
base_url="http://llm-server:8000/v1",
|
||
api_key="not-needed" # 로컬은 API 키 불필요
|
||
)
|
||
|
||
response = await client.chat.completions.create(
|
||
model="meta-llama/Llama-3.1-8B-Instruct",
|
||
messages=[{"role": "user", "content": prompt}],
|
||
max_tokens=2048,
|
||
temperature=0.7
|
||
)
|
||
```
|
||
|
||
### 로컬/원격 전환 패턴
|
||
```python
|
||
import os
|
||
from openai import AsyncOpenAI
|
||
|
||
def get_llm_client():
|
||
"""환경에 따라 로컬 또는 원격 LLM 클라이언트 반환"""
|
||
if os.getenv("USE_LOCAL_LLM", "false").lower() == "true":
|
||
return AsyncOpenAI(
|
||
base_url=os.getenv("LOCAL_LLM_URL", "http://llm-server:8000/v1"),
|
||
api_key="not-needed"
|
||
)
|
||
else:
|
||
return AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||
```
|
||
|
||
## 환경 변수
|
||
|
||
```bash
|
||
# .env 추가 항목
|
||
HF_TOKEN=hf_... # Hugging Face 토큰
|
||
USE_LOCAL_LLM=true # 로컬 LLM 사용 여부
|
||
LOCAL_LLM_URL=http://llm-server:8000/v1 # 로컬 LLM 엔드포인트
|
||
LOCAL_MODEL_NAME=meta-llama/Llama-3.1-8B-Instruct
|
||
```
|
||
|
||
## GPU 모니터링
|
||
|
||
### nvidia-smi
|
||
```bash
|
||
# 실시간 모니터링
|
||
watch -n 1 nvidia-smi
|
||
|
||
# 특정 정보만
|
||
nvidia-smi --query-gpu=index,name,memory.used,memory.total,utilization.gpu --format=csv
|
||
```
|
||
|
||
### Docker 내부에서
|
||
```bash
|
||
docker exec {컨테이너명} nvidia-smi
|
||
```
|
||
|
||
## 헬스체크
|
||
|
||
```yaml
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||
interval: 30s
|
||
timeout: 30s
|
||
retries: 3
|
||
start_period: 120s # 모델 로딩 시간 고려
|
||
```
|
||
|
||
## 주의사항
|
||
|
||
- 모델 첫 로딩 시 시간 소요 (수 분)
|
||
- VRAM 부족 시 OOM 에러 → 양자화 또는 GPU 추가
|
||
- Hugging Face 게이트 모델은 토큰 및 동의 필요
|
||
- 멀티 GPU 사용 시 NVLink 유무에 따라 성능 차이
|