Some checks failed
Windows / verify (push) Has been cancelled
Systran/faster-whisper-large-v3-turbo 는 Hugging Face 에 없는 저장소라 번역 시작 시 401 Repository Not Found 로 바로 실패했다. faster-whisper 가 'turbo' 로 공식 매핑하는 저장소 (mobiuslabsgmbh → 현재 dropbox-dash/faster-whisper-large-v3-turbo)로 바꾼다. 티어의 모든 ASR/MT 저장소가 로그인 없이 공개돼 있고 가중치가 있는지 확인하는 테스트를 추가했다 (오프라인이면 건너뜀). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
210 lines
6.0 KiB
Python
210 lines
6.0 KiB
Python
"""모델 품질 티어 정의.
|
|
|
|
사용자에게는 실제 모델 이름 대신 5단계 티어(속도우선 → 품질우선)로 노출한다.
|
|
각 티어는 ASR(음성인식) 1개 + MT(번역) 1개의 조합이다.
|
|
|
|
선정 근거는 docs/MODELS.md 참고.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
|
|
from ..constants import DEFAULT_TIER
|
|
|
|
|
|
class MTBackend(str, Enum):
|
|
"""번역 모델 실행 백엔드."""
|
|
|
|
CTRANSLATE2 = "ctranslate2" # NLLB 계열 seq2seq
|
|
TRANSFORMERS = "transformers" # LLM 계열 (Seed-X / Qwen3)
|
|
|
|
|
|
class PromptStyle(str, Enum):
|
|
"""LLM 백엔드의 프롬프트 형식. 모델 계열마다 요구사항이 다르다."""
|
|
|
|
#: 해당 없음 (seq2seq)
|
|
NONE = "none"
|
|
#: Seed-X 전용. chat template 이 없는 번역 전용 completion 모델이라
|
|
#: 모델 카드에 적힌 고정 형식 + 끝의 `<언어코드>` 태그를 그대로 지켜야 한다.
|
|
SEEDX = "seedx"
|
|
#: Qwen3 등 일반 instruct 모델. chat template + 자유 지시문 사용 가능.
|
|
INSTRUCT = "instruct"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AsrSpec:
|
|
repo: str
|
|
compute_type: str
|
|
beam_size: int = 1
|
|
vram_mb: int = 0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MTSpec:
|
|
repo: str
|
|
backend: MTBackend
|
|
compute_type: str = "float16"
|
|
vram_mb: int = 0
|
|
prompt_style: PromptStyle = PromptStyle.NONE
|
|
#: LoRA 추가학습 난이도 1(쉬움) ~ 3(까다로움)
|
|
finetune_ease: int = 2
|
|
|
|
@property
|
|
def supports_prompt_glossary(self) -> bool:
|
|
"""프롬프트로 용어집을 지시할 수 있는가.
|
|
|
|
지시문을 이해하는 instruct 모델만 가능하다. Seed-X 는 번역만 하도록
|
|
학습된 completion 모델이라 "이 용어는 이렇게 옮겨라" 같은 문장을
|
|
넣으면 학습 분포를 벗어나 오히려 번역이 망가진다. seq2seq 도 마찬가지다.
|
|
이 둘은 플레이스홀더 치환 방식으로 용어를 보호한다.
|
|
"""
|
|
return self.prompt_style is PromptStyle.INSTRUCT
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Tier:
|
|
key: str
|
|
order: int
|
|
name: str
|
|
tagline: str
|
|
asr: AsrSpec
|
|
mt: MTSpec
|
|
approx_latency_s: float
|
|
min_vram_gb: float
|
|
notes: str = ""
|
|
recommended: bool = False
|
|
best_after_finetune: bool = False
|
|
|
|
@property
|
|
def total_vram_mb(self) -> int:
|
|
return self.asr.vram_mb + self.mt.vram_mb
|
|
|
|
@property
|
|
def download_gb(self) -> float:
|
|
return round(self.total_vram_mb / 1024 * 1.25, 1)
|
|
|
|
|
|
TIERS: dict[str, Tier] = {}
|
|
|
|
|
|
def _register(tier: Tier) -> Tier:
|
|
TIERS[tier.key] = tier
|
|
return tier
|
|
|
|
|
|
LIGHTNING = _register(
|
|
Tier(
|
|
key="lightning",
|
|
order=1,
|
|
name="번개",
|
|
tagline="속도 최우선 · 저사양 GPU",
|
|
asr=AsrSpec("Systran/faster-whisper-small", "int8_float16", 1, 700),
|
|
mt=MTSpec(
|
|
"entai2965/nllb-200-distilled-600M-ctranslate2",
|
|
MTBackend.CTRANSLATE2,
|
|
"int8_float16",
|
|
800,
|
|
finetune_ease=1,
|
|
),
|
|
approx_latency_s=0.6,
|
|
min_vram_gb=2,
|
|
notes="짧은 대사·게임 음성에 충분. 긴 문장이나 전문용어는 품질이 떨어질 수 있습니다.",
|
|
)
|
|
)
|
|
|
|
SWIFT = _register(
|
|
Tier(
|
|
key="swift",
|
|
order=2,
|
|
name="신속",
|
|
tagline="빠르면서 인식률은 최상급",
|
|
asr=AsrSpec("dropbox-dash/faster-whisper-large-v3-turbo", "int8_float16", 1, 1600),
|
|
mt=MTSpec(
|
|
"entai2965/nllb-200-distilled-600M-ctranslate2",
|
|
MTBackend.CTRANSLATE2,
|
|
"float16",
|
|
1400,
|
|
finetune_ease=1,
|
|
),
|
|
approx_latency_s=0.9,
|
|
min_vram_gb=4,
|
|
notes="음성인식을 최상급으로 올리고 번역만 경량으로 유지한 구성. 가성비가 가장 좋습니다.",
|
|
)
|
|
)
|
|
|
|
BALANCE = _register(
|
|
Tier(
|
|
key="balance",
|
|
order=3,
|
|
name="균형",
|
|
tagline="기본값 · 속도와 품질의 중간",
|
|
asr=AsrSpec("dropbox-dash/faster-whisper-large-v3-turbo", "float16", 2, 2400),
|
|
mt=MTSpec(
|
|
"entai2965/nllb-200-distilled-1.3B-ctranslate2",
|
|
MTBackend.CTRANSLATE2,
|
|
"float16",
|
|
2900,
|
|
finetune_ease=2,
|
|
),
|
|
approx_latency_s=1.2,
|
|
min_vram_gb=6,
|
|
notes="8GB VRAM 환경에서 가장 무난한 선택.",
|
|
)
|
|
)
|
|
|
|
PRECISION = _register(
|
|
Tier(
|
|
key="precision",
|
|
order=4,
|
|
name="정밀",
|
|
tagline="추천 · 현 시점 최고 번역 품질",
|
|
asr=AsrSpec("dropbox-dash/faster-whisper-large-v3-turbo", "float16", 2, 2400),
|
|
mt=MTSpec(
|
|
"ByteDance-Seed/Seed-X-PPO-7B-AWQ-Int4",
|
|
MTBackend.TRANSFORMERS,
|
|
"int4",
|
|
5600,
|
|
prompt_style=PromptStyle.SEEDX,
|
|
finetune_ease=3,
|
|
),
|
|
approx_latency_s=2.0,
|
|
min_vram_gb=10,
|
|
notes="번역 전용으로 학습된 7B 모델. 한/영/일/중 구어체와 문맥 처리가 확연히 좋습니다.",
|
|
recommended=True,
|
|
)
|
|
)
|
|
|
|
ULTIMATE = _register(
|
|
Tier(
|
|
key="ultimate",
|
|
order=5,
|
|
name="극한",
|
|
tagline="품질 최우선 · 추가학습(LoRA)에 최적",
|
|
asr=AsrSpec("Systran/faster-whisper-large-v3", "float16", 5, 3100),
|
|
mt=MTSpec(
|
|
"Qwen/Qwen3-8B",
|
|
MTBackend.TRANSFORMERS,
|
|
"float16",
|
|
11000,
|
|
prompt_style=PromptStyle.INSTRUCT,
|
|
finetune_ease=1,
|
|
),
|
|
approx_latency_s=3.0,
|
|
min_vram_gb=16,
|
|
notes="게임·방송 용어를 LoRA로 추가학습해 붙일 때 가장 잘 먹히는 구성입니다.",
|
|
best_after_finetune=True,
|
|
)
|
|
)
|
|
|
|
assert DEFAULT_TIER in TIERS, f"constants.DEFAULT_TIER({DEFAULT_TIER}) 가 티어 목록에 없습니다"
|
|
|
|
|
|
def ordered_tiers() -> list[Tier]:
|
|
return sorted(TIERS.values(), key=lambda t: t.order)
|
|
|
|
|
|
def get_tier(key: str) -> Tier:
|
|
return TIERS.get(key, TIERS[DEFAULT_TIER])
|