Qwen3-VL 2B
개요
이 튜토리얼은 여러 개의 RBLN NPU를 사용하여 vLLM에서 멀티 모달 모델을 실행하는 방법을 설명합니다. 이 가이드에서는 이미지와 비디오를 입력받을 수 있는 Qwen/Qwen3-VL-2B-Instruct 모델을 사용합니다.
환경 설정 및 설치 확인
시작하기 전에 시스템 환경이 올바르게 구성되어 있으며, 필요한 모든 필수 패키지가 설치되어 있는지 확인하십시오. 다음 항목이 포함됩니다:
- 시스템 요구 사항:
- 필수 패키지:
- 설치 명령어:
| pip install \
--extra-index-url https://pypi.rbln.ai/simple \
rebel-compiler==0.10.4
pip install \
--extra-index-url https://wheels.vllm.ai/0.18.0/cpu \
--extra-index-url https://download.pytorch.org/whl/cpu \
vllm-rbln==0.10.4
|
Note
rebel-compiler를 사용하려면 RBLN 포털 계정이 필요하니 참고하십시오.
- 위 명령은 Debian 계열 Linux(예: Ubuntu)에서 pip로 패키지를 설치하는 일반적인 절차를 전제로 합니다. OS나 환경이 다른 경우에는 설치 가이드에서 지원되는 설치 조합과 적용 가능한 명령을 확인하세요.
1. 실행: 사전 컴파일 사용
이 단계는 여러 개의 RBLN NPU를 사용해 vLLM으로 Qwen/Qwen3-VL-2B-Instruct 모델을 서빙하는 방법을 설명합니다.
Warning
batch_size가 커질수록 서브모듈들이 기본 디바이스 풀을 공유할 때 디바이스 메모리가 부족할 수 있습니다. 아래 예시는 visual과 LM을 서로 다른 디바이스 풀에 배치하여 이를 방지합니다. 자세한 사항은 다중 모듈 모델를 참고하세요.
1.1. 모델 컴파일
rbln_config를 통해 메인 모듈을 비롯한 서브 모듈의 파라미터를 수정할 수 있습니다. 원본 소스 코드는 RBLN Model Zoo를 참고하세요.
API 레퍼런스가 필요하다면 RblnModelConfig를 확인하세요.
-
visual submodule:
-
max_seq_lens: Vision Transformer (ViT)에서의 최대 시퀀스 길이를 정의하며, 이는 이미지 내 패치(patch)의 개수를 나타냅니다.
-
device: 실행 중 각 서브모듈에 할당할 디바이스를 정의합니다.
-
tensor_parallel_size: ViT 추론에 사용할 NPU의 수를 정의합니다.
Qwen3-VL은 여러 서브모듈로 구성되어 있어, 모든 모듈을 하나의 디바이스에 로드하면 특히 배치 사이즈가 클 경우 메모리 용량을 초과할 수 있습니다. 서브모듈을 여러 디바이스에 분산시킴으로써 메모리 사용을 최적화하고 효율적인 실행 성능을 확보할 수 있습니다.
-
main module:
-
tensor_parallel_size: 추론에 사용할 NPU의 수를 정의합니다.
-
kvcache_partition_len: Flash Attention을 위한 KV 캐시 파티션의 길이를 정의합니다.
-
max_seq_len: 언어 모델의 최대 위치 임베딩을 정의하며, kvcache_partition_len의 배수여야 합니다.
-
device: 특정 디바이스에 할당된 서브모듈을 제외한 메인 모듈의 디바이스 할당을 정의합니다.
-
batch_size: 컴파일 시의 배치 사이즈를 정의합니다.
-
decoder_batch_sizes: 동적 배칭을 위한 배치 크기들을 정의합니다.
Note
모델 크기와 NPU 사양에 따라 적절한 배치 사이즈를 선택하세요.
또한, vllm-rbln은 최적의 처리량과 자원 활용을 보장하기 위해 동적 배치(Dynamic Batching)을 지원합니다.
자세한 내용은 동적 배치 추론를 참고하세요.
| from optimum.rbln import RBLNQwen3VLForConditionalGeneration
model_id = "Qwen/Qwen3-VL-2B-Instruct"
model = RBLNQwen3VLForConditionalGeneration.from_pretrained(
model_id,
export=True,
rbln_config={
"visual": {
"device": [8, 9, 10, 11, 12, 13, 14, 15],
"max_seq_lens": 16_384,
"tensor_parallel_size": 8,
},
"tensor_parallel_size": 8,
"kvcache_partition_len": 16_384,
"max_seq_len": 262_144,
"device": [0, 1, 2, 3, 4, 5, 6, 7],
"batch_size": 8,
},
)
model.save_pretrained("rbln-Qwen3-VL-2B-Instruct")
|
1.2. vLLM을 활용한 추론
컴파일된 모델은 vLLM과 함께 사용할 수 있습니다. 아래 예시는 컴파일된 모델을 사용하여 vLLM 엔진을 설정하고 추론을 수행하는 방법을 보여줍니다.
Note
from_pretrained의 매개변수는 일반적으로 rbln_batch_size, rbln_max_seq_len과 같이 rbln 접두사가 필요합니다.
하지만 rbln_config 내부의 매개변수는 이러한 접두사가 필요하지 않습니다. 동일한 매개변수를 rbln_config에서 설정할 때는 절대로 rbln 접두사를 붙이지 마세요.
| from qwen_vl_utils import process_vision_info
from transformers import AutoProcessor, AutoTokenizer
from vllm import LLM, SamplingParams
import os
# If the video is too long
# set `VLLM_ENGINE_ITERATION_TIMEOUT_S` to a higher timeout value.
VIDEO_URLS = [
"https://duguang-labelling.oss-cn-shanghai.aliyuncs.com/qiansun/video_ocr/videos/50221078283.mp4",
]
def generate_prompts_video(model_id: str):
processor = AutoProcessor.from_pretrained(model_id, padding_side="left")
video_nums = len(VIDEO_URLS)
messages = [[
{
"role":
"user",
"content": [
{
"type": "video",
"video": VIDEO_URLS[i],
},
{
"type": "text",
"text": "Describe this video."
},
],
},
] for i in range(video_nums)]
texts = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=False,
)
arr_video_inputs = []
for i in range(video_nums):
_, video_inputs = process_vision_info(
messages[i], return_video_metadata=True)
arr_video_inputs.append(video_inputs)
# With return_video_metadata=True, each video_input is already a
# (video_tensor, metadata_dict) tuple, satisfying Qwen3-VL's
# video_needs_metadata=True requirement.
return [{
"prompt": text,
"multi_modal_data": {
"video": video_inputs,
},
"mm_processor_kwargs": {
"min_pixels": 1024 * 14 * 14,
"max_pixels": 5120 * 14 * 14,
},
} for text, video_inputs in zip(texts, arr_video_inputs)]
def main():
model_id = "rbln-Qwen3-VL-2B-Instruct"
llm = LLM(model=model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
sampling_params = SamplingParams(
temperature=0,
ignore_eos=False,
skip_special_tokens=True,
stop_token_ids=[tokenizer.eos_token_id],
max_tokens=200
)
inputs = generate_prompts_video(model_id)
outputs = llm.generate(inputs, sampling_params)
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(generated_text)
if __name__ == "__main__":
main()
|
예시 출력:
| The video begins with a close-up shot of a clear plastic container filled with various fruits, including apples, pears, and grapes. The container is placed on a wooden table, and the background features a blue wall with a floral arrangement. The camera then zooms in on the container, highlighting its transparent design and the vibrant colors of the fruits inside. The video emphasizes the container's ability to keep the fruits fresh and visible.
Next, the video transitions to a demonstration of the container's durability. A hand is seen placing a heavy brick on top of the container, which remains intact and undamaged. This scene is repeated several times, each time with a different angle or lighting, to emphasize the container's strength and resistance to pressure. The text on the screen highlights the container's ability to withstand heavy loads, making it suitable for transporting and storing fruits.
The video then shifts to a close-up of the container being rotated on a white surface, showcasing its sleek design and the clarity of the plastic
|
2. 실행: 사전 컴파일 미사용 (베타)
Info
이 기능은 베타 단계입니다. 주어진 vLLM 파라미터로 Qwen/Qwen3-VL-2B-Instruct 모델을 컴파일하고, encoder를 별도의 NPU 그룹에 배치하여 서빙합니다.
2.1. vLLM을 활용한 컴파일 및 추론
vLLM Parameters를 제공하면, vLLM RBLN이 엔진 시작 시 optimum-rbln으로 모델을 컴파일하여 추론에 사용합니다. 아래 예시는 vLLM engine 설정 방법을 보여줍니다.
Note
VLLM_RBLN_TP_SIZE는 메인 모듈의 텐서 병렬 크기를 설정합니다. 서브모듈에 tensor_parallel_size를 지정하려면 아래 예시처럼 rbln_config의 해당 서브모듈 아래에 직접 설정하세요.
Note
컴파일된 모델은 $VLLM_CACHE_ROOT/compiled_models 아래에 저장됩니다. VLLM_CACHE_ROOT는 기본값이 ~/.cache/vllm이며, 환경 변수로 다른 위치를 지정할 수 있습니다.
| from qwen_vl_utils import process_vision_info
from transformers import AutoProcessor, AutoTokenizer
from vllm import LLM, SamplingParams
import os
# VIDEO_URLS와 generate_prompts_video()는 동일합니다.
def main():
model_id = "Qwen/Qwen3-VL-2B-Instruct"
os.environ["VLLM_RBLN_TP_SIZE"] = "8"
llm = LLM(
model=model_id,
block_size=16_384,
max_model_len=262_144,
max_num_seqs=8,
additional_config={
"rbln_config": {
# LM은 device 0~7
"device": [0, 1, 2, 3, 4, 5, 6, 7],
# ViT는 device 8~15
"visual": {
"device": [8, 9, 10, 11, 12, 13, 14, 15],
"tensor_parallel_size": 8,
"max_seq_lens": 16_384,
}
}
}
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
# ... (이하 main()의 나머지는 동일)
if __name__ == "__main__":
main()
|
예시 출력:
| The video begins with a close-up shot of a clear plastic container filled with various fruits, including apples, pears, and grapes. The container is placed on a wooden table, and the background features a blue wall with a floral arrangement. The camera then zooms in on the container, highlighting its transparent design and the vibrant colors of the fruits inside. The video emphasizes the container's ability to keep the fruits fresh and visible.
Next, the video transitions to a demonstration of the container's durability. A hand is seen placing a heavy brick on top of the container, which remains intact and undamaged. This scene is repeated several times, each time with a different angle or lighting, to emphasize the container's strength and resistance to pressure. The text on the screen highlights the container's ability to withstand heavy loads, making it suitable for transporting and storing fruits.
The video then shifts to a close-up of the container being rotated on a white surface, showcasing its sleek design and the clarity of the plastic
|
참고