DOCS/journey/ideas/250804_로빙_임베딩_모델_경량화_최적화_가이드.md
Claude-51124 22557e7132 docs: 오래된 트러블슈팅 아카이브 및 구조 정리
- 7-8월 초기 구축 문서 12개를 _archive/troubleshooting/2025_07-08_initial_setup/로 이동
- book/300_architecture/390_human_in_the_loop_intent_learning.md를 journey/research/intent_classification/로 이동 (개발 여정 문서)
- 빈 폴더 제거 (journey/assets/*)
2025-11-17 14:06:05 +09:00

6.3 KiB

로빙 임베딩 모델 경량화 및 최적화 가이드

작성일: 2025년 8월 4일 작성자: Claude (51124 서버)

배경

rb10508_micro 경량화 과정에서 ONNX 기반 임베딩 모델로 전환했으나, 예상보다 높은 메모리 사용량(987.9MB)을 보이고 있다. 이미지 크기는 6.19GB → 1.16GB로 경량화했지만, 런타임 메모리는 여전히 1GB에 가깝다.

현재 상황 분석

현재 사용 모델

  • 모델: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
  • 크기: 449MB ONNX 파일
  • 차원: 384
  • 메모리 사용량: 987.9MB (런타임)

성능 벤치마크 (한국어)

1. 동일 의미, 다른 표현: 0.949 (매우 좋음)
   "안녕하세요, 오늘 날씨가 좋네요." ↔ "안녕, 오늘 날씨 정말 좋다."

2. 감정 표현 유사: 0.818 (좋음)
   "오늘 기분이 좋아요." ↔ "기분이 매우 좋습니다."

3. 연관 의미: 0.317 (보통)
   "배가 고파요." ↔ "밥 먹고 싶어요."

4. 시간-음식 연관: 0.622 (괜찮음)
   "점심 시간이 되었네요." ↔ "밥 먹고 싶어요."

5. 무관한 문장 (기준): 0.334
   "컴퓨터가 고장났어요." ↔ "배가 고파요."

메모리 사용량 높은 원인

메모리 분석 결과

  • Python process RSS: 1.06GB
  • ONNX 모델 파일: 449MB (메모리 상주)
  • ONNX Runtime: 모델 실행용 추가 메모리
  • transformers 토크나이저: 14MB+ 토크나이저 파일들
  • ChromaDB: 벡터 데이터베이스 메모리 사용
  • Python + FastAPI: 기본 웹 프레임워크 오버헤드

벡터 DB 필요성

일반 DB(PostgreSQL/NoSQL) 대신 벡터 DB를 사용해야 하는 이유:

벡터 DB의 핵심 기능:

  • 의미적 유사도 검색: "배고프다" ↔ "밥 먹고 싶다" 연결
  • 코사인 유사도: 벡터 간 거리로 관련성 측정
  • 임베딩 기반: 문맥과 의미를 고차원 벡터로 표현

일반 DB 사용 시 문제점:

  • 의미적 검색 불가능 (키워드 매칭만)
  • 컨텍스트 이해 부족
  • 기억 패턴 인식 실패

대안 임베딩 모델 비교

1. 기준 조건

  • 한국어 지원
  • 임베딩 차원 수 (낮을수록 경량)
  • 모델 크기 (작을수록 좋음)
  • 성능 (Semantic Search 기준)
  • 로컬 실행 가능 여부

2. 모델 후보군

모델명 크기 차원 한국어 지원 특징 / 장단점
paraphrase-multilingual-MiniLM-L12-v2 449MB 384 O 현재 사용 중. 균형형
paraphrase-multilingual-MiniLM-L6-v2 120MB 384 O 가장 가벼운 multilingual 모델 중 하나
intfloat/multilingual-e5-small 175MB 384 O E5 시리즈. 검색 최적화. "query: …" 문맥 활용 필요
intfloat/multilingual-e5-base 440MB 768 O 성능 ↑, 경량 ↓. MTEB 성능 상위권
jinaai/jina-embeddings-v2-base-ko 약 400MB 768 O (한국어 특화) 한국어 전용. 문맥 이해 성능 우수
LaBSE (Google) 약 500MB 768 O 대규모 언어 간 의미 정렬. 성능은 뛰어나나 무겁고 느림
bge-m3 (BAAI) 약 360MB 1024 O (다국어) RAG + 검색 최적화. 문서용. 다소 무거움
nomic-ai/nomic-embed-text-v1.5 120MB 768 제한적 (한국어 일부) 최신 경량 + 빠름. 고속 의미 검색용

3. L12 vs L6 성능 차이 예상

L6 모델 예상 성능 (L12 대비):

  • 전체 성능: 5-10% 저하
  • 한국어 특화: 10-15% 저하 (다국어 모델 특성상)

구체적 예상:

  • 동일 의미: 0.949 → 0.850-0.900 (-5~10%)
  • 감정 표현: 0.818 → 0.720-0.780 (-5~12%)
  • 연관 의미: 0.317 → 0.250-0.300 (-5~20%)

실용적 영향:

  • 크게 문제없는 경우: 직접적 대화 기억, 명확한 감정 표현
  • 문제가 될 수 있는 경우: 미묘한 연관성, 한국어 관용어, 복합 감정

권장 전략

1. 단계별 경량화 접근

Phase 1: 즉시 적용 가능

# L6 모델로 교체 (330MB 메모리 절약)
model: paraphrase-multilingual-MiniLM-L6-v2
예상 메모리: 987MB → 650-700MB
성능 저하: 10-15%

Phase 2: 성능 최적화

# E5-small 모델 (검색 특화)
model: intfloat/multilingual-e5-small
크기: 175MB
특징: "query: " prefix 활용으로 성능 보완

Phase 3: 한국어 특화

# 한국어 전용 고성능
model: jinaai/jina-embeddings-v2-base-ko
크기: 400MB
차원: 768 (정확도 최우선 시)

2. 하이브리드 아키텍처

메모리 효율적 접근:

# 핵심 기억만 벡터 DB (최근 100개)
recent_memories = ChromaDB(embedding_function=ONNX_Light)

# 오래된 기억은 PostgreSQL (키워드 기반)
old_memories = PostgreSQL(full_text_search=True)

# 검색 시 두 단계로 진행
1. 벡터 검색 (의미적 유사도)
2. 키워드 검색 (보완)

3. 운영 최적화

메모리 내 벡터 제한:

# 메모리에 최근 50개 임베딩만 유지
# 나머지는 디스크 저장 후 필요시 로딩
MAX_MEMORY_EMBEDDINGS = 50

모델 지연 로딩:

# 앱 시작 시 모델 로딩하지 않고 첫 요청 시 로딩
lazy_load = True

구체적 추천

메모리 절약 우선

  • 1순위: paraphrase-multilingual-MiniLM-L6-v2 (120MB)
  • 2순위: multilingual-e5-small (175MB)

성능 우선 (한국어)

  • 1순위: jina-embeddings-v2-base-ko (400MB, 768차원)
  • 2순위: multilingual-e5-base (440MB, 768차원)

균형형 (현재 유지)

  • 현재: paraphrase-multilingual-MiniLM-L12-v2 (449MB, 384차원)

결론

  1. 즉시 적용: L6 모델로 변경하여 330MB 메모리 절약
  2. 장기 계획: 하이브리드 구조로 메모리와 성능 모두 최적화
  3. 성능 모니터링: 실제 사용자 피드백 기반으로 모델 선택

로빙의 정확한 용도(검색/요약/의미 연결 중 어디에 중점?)에 따라 최적 조합을 조정할 수 있다.

다음 단계

  1. L6 모델 성능 테스트: 실제 한국어 데이터로 A/B 테스트
  2. 메모리 프로파일링: 각 모델별 정확한 메모리 사용량 측정
  3. 사용자 피드백: 실제 대화에서 의미 연결 정확도 비교
  4. 하이브리드 아키텍처 설계: ChromaDB + PostgreSQL 통합 방안