새 모델 지원 방법
새 모델 지원 방법 (How to Support New Models)
SGLang에서 새 언어 모델과 멀티모달 대규모 언어 모델(MLLM)을 지원하는 방법을 설명합니다. 새 모델 테스트와 외부 구현 등록도 다룹니다.
출처: 문서
본문
새 언어 모델 지원 방법 (How to Support a New Language Model)
SGLang에서 새 모델을 지원하려면 SGLang Models 디렉터리 아래에 단일 파일만 추가하면 됩니다. 기존 모델 구현에서 배우고 모델용 새 파일을 만들 수 있습니다. 대부분의 모델에 대해 비슷한 모델(Llama에서 시작하는 등)을 찾아 시작하면 됩니다. 또한 vLLM 모델을 SGLang으로 포팅하는 방법도 참조하세요.
NPU 적응은 _is_npu 조건 분기를 통해 기존 모델 파일(예: llama.py, qwen3_vl.py)에 내장됩니다. NPU 하드웨어 백엔드는 sglang/srt/hardware_backend/npu/에 있습니다. 일부 연산은 CUDA 대응물 대신 torch_npu API를 사용해야 할 수 있습니다.
새 멀티모달 대규모 언어 모델 지원 방법 (How to Support a New Multimodal Large Language Model)
SGLang에서 새 멀티모달 대규모 언어 모델(MLLM)을 지원하려면 표준 LLM 지원 외에 몇 가지 핵심 구성 요소가 있습니다:
-
새 모델을 멀티모달로 등록: model_config.py의
is_multimodal_model을 확장해 모델에 대해True를 반환하게 합니다. -
새 chat-template 등록: 기본 chat-template이 이미지를 입력으로 받지 못할 때만: conversation.py에 새 chat template과 해당 매칭 함수를 등록합니다.
-
멀티모달 데이터 프로세서:
BaseMultimodalProcessor를 상속하는 새Processor클래스를 정의하고 이 프로세서를 모델 전용 프로세서로 등록합니다. 자세한 내용은 Multimodal Processors를 참조하세요. -
멀티모달 토큰 처리: 새 모델의
pad_input_ids함수를 구현합니다. 이 함수에서 프롬프트의 멀티모달 토큰을 확장하고(필요하면) 멀티모달 데이터 해시로 패딩해 SGLang이RadixAttention으로 서로 다른 멀티모달 데이터를 인식할 수 있게 합니다. -
이미지 특징 추출 처리: 원시 이미지 데이터에서 이미지 특징을 추출해 언어 모델이 사용하는 임베딩으로 변환하는 새 모델의
get_image_feature함수를 구현합니다. -
비전 어텐션 적응: ViT의 다중 헤드
Attention을 SGLang의VisionAttention으로 적응시킵니다.
Qwen2VL 또는 다른 mllm 구현을 참조할 수 있습니다. 이 모델들은 멀티모달·텍스트 입력을 모두 올바르게 처리하는 방법을 보여줍니다.
테스트와 디버깅 (Testing and Debugging)
테스트·벤치마킹 결과를 모두 PR 설명에 기록하세요.
벤치마크 (Benchmark)
- (필수) MMMU: MMMU 벤치마크 README.md에 따라 SGLang vs. HF Transformer 정확도 비교를 얻습니다. SGLang 실행의 정확도 점수는 HF Transformer 실행보다 훨씬 낮아서는 안 됩니다. 마찬가지로 벤치마크 및 프로파일링 가이드에 따라 성능 비교(TTFT와 처리량)를 얻으며, 이는 베이스라인(예: HF Transformer)을 충족하거나 초과해야 합니다.
- (선택) 기타 평가: 다른 평가를 실행했다면 PR 설명에 결과를 기록하세요.
vLLM에서 SGLang으로 모델 포팅 (Port a Model from vLLM to SGLang)
vLLM Models 디렉터리는 많은 모델을 다루므로 가치 있는 자원입니다. SGLang은 vLLM의 인터페이스와 일부 레이어를 재사용해 vLLM에서 SGLang으로 모델을 쉽게 포팅할 수 있게 합니다.
vLLM에서 SGLang으로 모델을 포팅하려면:
- 지침으로 이 두 파일을 비교하세요:
- 주요 차이점:
- vLLM의
Attention을RadixAttention으로 교체(layer_id를RadixAttention에 전달해야 함). - vLLM의
LogitsProcessor를 SGLang의LogitsProcessor로 교체. - (멀티모달 모델) ViT의 다중 헤드
Attention을 SGLang의VisionAttention으로 교체. - 다른 vLLM 레이어(
RMSNorm,SiluAndMul등)를 SGLang 레이어로 교체. forward()함수 변경: 전체 배치 상태(positions,input_ids, KV cache indices, sampling info 등)를 담는forward_batch: ForwardBatch인자를 받도록 합니다. SGLang의 최상위 모델forward()는 엔트리 포인트이며 최종LogitsProcessorOutput을 직접 반환합니다. vLLM처럼 이것을forward()+compute_logits()로 나누지 않고 백본 forward와 logits 계산을 모두 수행합니다.- 마지막에
EntryClass추가. - 새 구현이 SGLang 컴포넌트만 사용하고 vLLM 컴포넌트에 의존하지 않는지 확인.
- Ascend NPU의 경우: CUDA 커널을
torch_npu대응물로 교체하는 등 NPU 특정 패턴을 위해 기존 NPU 적응 모델(예:llama.py,deepseek_v2.py)을 참조하세요. NPU 백엔드는sglang/srt/hardware_backend/npu/에 있습니다.
- vLLM의
참고: 지원 모델 문서의 지원 모델 목록에 새 모델을 추가해야 합니다.
외부 모델 구현 등록 (Registering an External Model Implementation)
위 방법 외에도 서버 시작 전에 ModelRegistry에 새 모델을 등록할 수 있습니다. 이렇게 하면 소스 코드를 수정하지 않고 모델을 통합할 수 있습니다.
예:
from sglang.srt.models.registry import ModelRegistry
from sglang.srt.entrypoints.http_server import launch_server
# For a single model, add it to the registry:
ModelRegistry.models[model_name] = model_class
# For multiple models, you can imitate the import_model_classes() function:
from functools import lru_cache
@lru_cache()
def import_new_model_classes():
model_arch_name_to_cls = {}
# Populate model_arch_name_to_cls with your new model classes.
...
return model_arch_name_to_cls
ModelRegistry.models.update(import_new_model_classes())
# Launch the server with your server arguments:
launch_server(server_args)
예시: Llama 래퍼 모델 구현·서빙 (Example: Implementing and Serving a Llama Wrapper Model)
아래는 SGLang에서 새 모델을 종단 간 구현한 다음 오프라인 엔진으로 실행하는 입문용 단계별 설명입니다.
모델 구현 (Implementing Our Model)
간단히 하기 위해 이 새 모델은 Llama 3.1-8B-Instruct의 단순 래퍼가 되며, 목표는 각 forward 호출에서 각 logit의 제곱근을 취해 출력 logits에 바이어스를 주는 것입니다.
llama_wrapper.py라는 파일에 모델을 정의하는 것으로 시작합시다. 첫 단계는 SGLang의 내부 백엔드인 SRT의 필요한 라이브러리를 임포트하는 것입니다.
# In the file `llama_wrapper.py`
import torch
from transformers import LlamaConfig
from typing import Optional
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
from sglang.srt.layers.quantization.base_config import QuantizationConfig
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
from sglang.srt.models.llama import LlamaForCausalLM
다음으로 모델의 새 class를 선언하고 LlamaForCausalLM에서 상속하게 합니다. 그러면 모델이 LlamaAttention, LlamaMLP 같은 LlamaForCausalLM의 사전 정의된 모듈·레이어에 접근할 수 있습니다. 거의 모든 모델 구현이 __init__ 메서드의 인자로 config와 quant_config를 받는 점에 주의하세요. config와 quant_config는 model_loader/loader.py를 통해 전달됩니다. LlamaForCausalLM에서 상속했으므로 파라미터를 생성자에 직접 전달할 수 있으며, 생성자가 멤버 변수를 설정해 줍니다.
class LlamaWrapper(LlamaForCausalLM):
def __init__(
self,
config: LlamaConfig,
quant_config: Optional[QuantizationConfig] = None,
prefix: str = "",
) -> None:
super().__init__(config=config, quant_config=quant_config, prefix=prefix)
이제 추론 시 호출되는 forward 메서드를 정의하려고 합니다. forward의 시그니처는 어떤 모델이든 본질적으로 동일합니다. 참조를 위해 models 디렉터리에 정의된 다른 모델을 살펴볼 수 있습니다. SGLang 런타임 내부에서 forward가 정확히 어디에서 호출되는지 보려면 ModelRunner 클래스의 forward_decode와 forward_extend를 살펴보세요.
@torch.no_grad()
def forward(
self,
input_ids: torch.Tensor,
positions: torch.Tensor,
forward_batch: ForwardBatch,
pp_proxy_tensors: Optional[PPProxyTensors] = None,
input_embeds: Optional[torch.Tensor] = None,
get_embedding: bool = False,
) -> LogitsProcessorOutput:
이제 self.model(이것은 LlamaForCausalLM이 __init__ 메서드에서 정의하는 멤버 변수)의 __call__ 메서드를 호출하며, 이는 결국 LlamaForCausalLM의 forward 메서드를 호출합니다. 그 후 hidden_states를 모델의 LogitsProcessor(LlamaForCausalLM에서도 정의)에 공급합니다.
hidden_states = self.model(
input_ids,
positions,
forward_batch,
input_embeds,
pp_proxy_tensors=pp_proxy_tensors,
)
res: LogitsProcessorOutput = self.logits_processor(
input_ids,
hidden_states,
self.lm_head,
forward_batch,
)
다음 토큰의 logits를 받으면 마침내 바이어싱 단계를 수행할 수 있습니다.
orig_logits = res.next_token_logits
res.next_token_logits = torch.where(
orig_logits > 0,
orig_logits.sqrt(),
orig_logits
)
return res
이제 LlamaWrapper 모델이 생성되어 서빙할 준비가 되었습니다!
SGLang 오프라인 엔진으로 모델 서빙 (Serving Our Model Via SGLang's Offline Engine)
이 설명의 다음 단계는 새 모델을 오프라인으로 호스팅해 HTTP 서버 없이 로컬에서 서빙하는 것입니다.
먼저 run.py라는 새 파일을 만듭니다. 이제 SGLang의 ModelRegistry가 모델을 찾을 수 있도록 해야 합니다. 이를 위해 먼저 Huggingface에서 모델의 구성과 가중치를 다운로드합니다.
# In the file `run.py`
import asyncio
from functools import lru_cache
from huggingface_hub import snapshot_download
from llama_wrapper import LlamaWrapper # Make sure to import our new model!
import sglang as sgl
from sglang.srt.models.registry import ModelRegistry
# Make sure to request access to this model on Huggingface, then export your
# `HF_TOKEN` to download the model snapshot
llama_dir = snapshot_download(
repo_id="meta-llama/Llama-3.1-8B-Instruct",
local_dir="./llama_ckpt",
)
이제 모델이 디스크에 있으므로 ./llama_ckpt/config.json의 architectures 필드를 LlamaWrapper로 바꿔 LlamaWrapper를 가리키고 싶습니다. 그렇게 하면 모델 체크포인트 경로를 SGLang에 전달할 때 모델로 "LlamaForCausalLM" 대신 "LlamaWrapper"를 사용하려는 것임을 알게 됩니다.
{
"architectures": [
"LlamaWrapper"
],
...
}
하지만 LlamaWrapper 클래스를 "LlamaWrapper" 레지스트리 키워드에 연결하지 않으면 SGLang이 모델을 찾을 수 없습니다. 따라서 LlamaWrapper를 등록하려면 위 "Registering an External Model Implementation" 섹션의 단계를 따르려고 합니다.
@lru_cache()
def import_new_model_classes():
model_arch_name_to_cls = {"LlamaWrapper": LlamaWrapper}
return model_arch_name_to_cls
ModelRegistry.models.update(import_new_model_classes())
마지막으로 Engine을 만들 때 로컬 모델 디렉터리 경로를 전달하기만 하면 됩니다. 그러면 LlamaWrapper가 서빙될 준비가 됩니다. 이 설명에서는 SGLang Engine의 비스트리밍 비동기 생성 엔드포인트를 사용합니다.
def main():
llm = sgl.Engine(model_path="./llama_ckpt")
sampling_params = {"temperature": 0.2, "top_k": 5}
prompts = [
"Write a short, neutral self-introduction for a fictional character. Hello, my name is",
"Provide a concise factual statement about France’s capital city. The capital of France is",
"Explain possible future trends in artificial intelligence. The future of AI is",
]
asyncio.run(run_llm(llm, sampling_params, prompts))
llm.shutdown()
async def run_llm(
llm,
sampling_params,
prompts,
) -> None:
outputs = await llm.async_generate(prompts, sampling_params)
for prompt, output in zip(prompts, outputs):
print(f"\nPrompt: {prompt}")
print(f"Generated text: {output['text']}")
if __name__ == "__main__":
main()
이제 python run.py를 호출하면 새로 만든 모델의 출력을 얻을 수 있습니다!
표준 CLI로 외부 모델 서빙 (Serving External Models via the Standard CLI)
이전 섹션은 ModelRegistry로 모델을 프로그래밍 방식으로 등록하고 오프라인 엔진으로 서빙하는 방법을 보여줍니다. vLLM 모델 플러그인과 유사하게 SGLang 소스 코드를 수정하지 않고 표준 python -m sglang.launch_server CLI를 계속 사용할 수 있는 대안이 있습니다. SGLANG_EXTERNAL_MODEL_PACKAGE 환경 변수로 모델을 등록할 수 있습니다.
EntryClass 변수
SGLang이 모델 패키지를 스캔할 때 Python 파일의 모듈 수준에서 EntryClass 변수를 찾습니다. 모델 레지스트리는 파일을 임포트하고 EntryClass를 확인해 할당된 클래스를 등록합니다. HuggingFace 기반 모델을 사용한다면 이 클래스의 이름은 모델 config.json의 "architectures" 필드와 일치해야 합니다.
예를 들어 Llama 래퍼를 구현한다면 모델 파일 끝에 이 줄을 추가하세요:
# This is what "Add EntryClass at the end" means
EntryClass = LlamaWrapper
예시: 텍스트 전용 모델 (Example: Text-Only Model)
이전 섹션과 같은 Llama 래퍼를 사용해 CLI로 패키징·서빙하는 방법입니다.
- 프로젝트 만들기
sglang_custom_project/
|----setup.py
|----custom_llm/
|----__init__.py
|----llama_wrapper.py
setup.py 작성:
# sglang_custom_project/setup.py
from setuptools import setup, find_packages
setup(
name="sglang-custom-plugins",
version="0.1",
packages=find_packages(),
)
- 모델 코드 작성
llama_wrapper.py 안에 모델을 작성하고 EntryClass를 포함합니다:
# sglang_custom_project/custom_llm/llama_wrapper.py
import torch
from typing import Optional
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
from sglang.srt.layers.quantization.base_config import QuantizationConfig
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
from sglang.srt.models.llama import LlamaForCausalLM
class LlamaWrapper(LlamaForCausalLM):
def __init__(self, config, quant_config: Optional[QuantizationConfig] = None,
prefix: str = "") -> None:
super().__init__(config=config, quant_config=quant_config, prefix=prefix)
@torch.no_grad()
def forward(self, input_ids, positions, forward_batch,
pp_proxy_tensors=None, input_embeds=None, get_embedding=False):
hidden_states = self.model(
input_ids, positions, forward_batch, input_embeds,
pp_proxy_tensors=pp_proxy_tensors,
)
res: LogitsProcessorOutput = self.logits_processor(
input_ids, hidden_states, self.lm_head, forward_batch,
)
orig = res.next_token_logits
res.next_token_logits = torch.where(orig > 0, orig.sqrt(), orig)
return res
# Don't forget to add EntryClass
EntryClass = LlamaWrapper
- 패키지 설치
sglang_custom_project 디렉터리 안에서 활성 Python 환경에 코드를 설치합니다:
pip install -e .
config.json업데이트
HuggingFace 모델 체크포인트 디렉터리의 config.json을 업데이트해 architectures 필드가 클래스 이름과 일치하게 합니다:
{
"architectures": ["LlamaWrapper"],
...
}
- 서버 시작
CLI 실행 전에 환경 변수를 설정합니다:
export SGLANG_EXTERNAL_MODEL_PACKAGE=custom_llm
python -m sglang.launch_server \
--model-path /path/to/Llama-3.1-8B-Instruct \
--port 8000
SGLANG_EXTERNAL_MODEL_PACKAGE는 모델 관련 코드를 담은 부모 폴더 이름이어야 합니다. 이 예시에서는 custom_llm이어야 합니다.
예시: 멀티모달 모델 (Example: Multimodal Model)
멀티모달 모델을 다룰 때는 SGLANG_EXTERNAL_MODEL_PACKAGE만 설정하는 것으로는 충분하지 않습니다. SGLang은 이미지/비디오 처리 파이프라인을 활성화하기 위해 아키텍처를 멀티모달로 인식해야 하고, 커스텀 프로세서도 필요합니다.
두 가지 추가 환경 변수를 설정해 이를 처리할 수 있습니다:
SGLANG_EXTERNAL_MM_MODEL_ARCH: SGLang의 내부 멀티모달 모델 목록에 아키텍처 이름을 추가합니다.SGLANG_EXTERNAL_MM_PROCESSOR_PACKAGE: 커스텀 프로세서 클래스를 찾을 위치를 SGLang에 알려줍니다.
예를 들어 Qwen2-VL-Instruct에 기반해 logits의 제곱근을 취하는 커스텀 모델을 만들어 봅시다.
프로젝트 생성:
sglang_custom_project_vl/
|----setup.py
|----custom_vlm/
|----__init__.py
|----qwenvl_wrapper.py
setup.py 작성:
# sglang_custom_project_vl/setup.py
from setuptools import setup, find_packages
setup(
name="sglang-custom-plugins-vl",
version="0.1",
packages=find_packages(),
)
qwenvl_wrapper.py에 모델 작성:
# sglang_custom_project_vl/custom_vlm/qwenvl_wrapper.py
import torch
from sglang.srt.models.qwen2_vl import Qwen2VLForConditionalGeneration
from sglang.srt.multimodal.processors.qwen_vl import QwenVLImageProcessor
class CustomQwen2VL(Qwen2VLForConditionalGeneration):
def forward(self, input_ids, positions, forward_batch,
input_embeds=None, get_embedding=False):
res = super().forward(
input_ids, positions, forward_batch,
input_embeds=input_embeds, get_embedding=get_embedding
)
if not get_embedding:
orig = res.next_token_logits
res.next_token_logits = torch.where(orig > 0, orig.sqrt(), orig)
return res
class CustomQwen2VLProcessor(QwenVLImageProcessor):
models = [CustomQwen2VL]
def __init__(self, hf_config, server_args, _processor, *args, **kwargs):
super().__init__(hf_config, server_args, _processor, *args, **kwargs)
EntryClass = CustomQwen2VL
참고: 프로세서를 특정 모델 클래스와 연결하는 한 커스텀 프로세서용 별도 EntryClass는 필요하지 않습니다.
패키지 설치, config.json 업데이트, 실행:
pip install -e .
{
"architectures": ["CustomQwen2VL"],
...
}
export SGLANG_EXTERNAL_MODEL_PACKAGE=custom_vlm
export SGLANG_EXTERNAL_MM_MODEL_ARCH=CustomQwen2VL
export SGLANG_EXTERNAL_MM_PROCESSOR_PACKAGE=custom_vlm
python -m sglang.launch_server \
--model-path /path/to/Qwen2-VL-2B-Instruct \
--port 8000 \
--enable-multimodal
문서 (Documentation)
generative_models.mdx 또는 multimodal_language_models.mdx의 지원 모델 표에 추가합니다.
이 지침을 따르면 SGLang에서 새 언어 모델과 멀티모달 대규모 언어 모델 지원을 추가하고, 철저히 테스트되어 시스템에 쉽게 통합되도록 할 수 있습니다.