registry.py 42.7 KB
Newer Older
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5
6
"""
Whenever you add an architecture to this page, please also update
`tests/models/registry.py` with example HuggingFace models for it.
"""
7
import hashlib
8
import importlib
9
import json
10
import os
11
import pickle
12
13
import subprocess
import sys
14
import tempfile
15
from abc import ABC, abstractmethod
16
from collections.abc import Set
17
from dataclasses import asdict, dataclass, field
18
from functools import lru_cache
19
from pathlib import Path
20
from typing import Callable, Optional, TypeVar, Union
21
22

import torch.nn as nn
23
import transformers
24

25
from vllm import envs
26
from vllm.config import (ModelConfig, iter_architecture_defaults,
27
                         try_match_architecture_defaults)
28
from vllm.logger import init_logger
29
from vllm.logging_utils import logtime
30
31
from vllm.transformers_utils.dynamic_module import (
    try_get_class_from_dynamic_module)
32

33
34
from .interfaces import (has_inner_state, has_noops, is_attention_free,
                         is_hybrid, supports_cross_encoding,
35
36
                         supports_multimodal,
                         supports_multimodal_encoder_tp_data,
37
                         supports_multimodal_raw_input_only, supports_pp,
38
                         supports_transcription, supports_v0_only)
39
40
from .interfaces_base import (get_default_pooling_type, is_pooling_model,
                              is_text_generation_model)
41
42
43

logger = init_logger(__name__)

44
# yapf: disable
45
46
_TEXT_GENERATION_MODELS = {
    # [Decoder-only]
47
    "ApertusForCausalLM": ("apertus", "ApertusForCausalLM"),
48
49
    "AquilaModel": ("llama", "LlamaForCausalLM"),
    "AquilaForCausalLM": ("llama", "LlamaForCausalLM"),  # AquilaChat2
Raghav Ravishankar's avatar
Raghav Ravishankar committed
50
    "ArceeForCausalLM": ("arcee", "ArceeForCausalLM"),
51
    "ArcticForCausalLM": ("arctic", "ArcticForCausalLM"),
52
    "MiniMaxForCausalLM": ("minimax_text_01", "MiniMaxText01ForCausalLM"),
53
    "MiniMaxText01ForCausalLM": ("minimax_text_01", "MiniMaxText01ForCausalLM"),
54
    "MiniMaxM1ForCausalLM": ("minimax_text_01", "MiniMaxText01ForCausalLM"),
chenych's avatar
chenych committed
55
    "MiniMaxM2ForCausalLM": ("minimax_m2", "MiniMaxM2ForCausalLM"),
56
57
58
59
    # baichuan-7b, upper case 'C' in the class name
    "BaiChuanForCausalLM": ("baichuan", "BaiChuanForCausalLM"),
    # baichuan-13b, lower case 'c' in the class name
    "BaichuanForCausalLM": ("baichuan", "BaichuanForCausalLM"),
60
    "BailingMoeForCausalLM": ("bailing_moe", "BailingMoeForCausalLM"),
ant-yy's avatar
ant-yy committed
61
    "BailingMoeV2ForCausalLM": ("bailing_moe", "BailingMoeV2ForCausalLM"),
Yu Chin Fabian Lim's avatar
Yu Chin Fabian Lim committed
62
    "BambaForCausalLM": ("bamba", "BambaForCausalLM"),
63
    "BloomForCausalLM": ("bloom", "BloomForCausalLM"),
64
    "ChatGLMModel": ("chatglm", "ChatGLMForCausalLM"),
65
    "ChatGLMForConditionalGeneration": ("chatglm", "ChatGLMForCausalLM"),
66
    "CohereForCausalLM": ("commandr", "CohereForCausalLM"),
67
    "Cohere2ForCausalLM": ("commandr", "CohereForCausalLM"),
68
    "CwmForCausalLM": ("llama", "LlamaForCausalLM"),
69
    "DbrxForCausalLM": ("dbrx", "DbrxForCausalLM"),
70
    "DeciLMForCausalLM": ("nemotron_nas", "DeciLMForCausalLM"),
71
72
    "DeepseekForCausalLM": ("deepseek", "DeepseekForCausalLM"),
    "DeepseekV2ForCausalLM": ("deepseek_v2", "DeepseekV2ForCausalLM"),
73
    "DeepseekV3ForCausalLM": ("deepseek_v2", "DeepseekV3ForCausalLM"),
74
    "DeepseekV32ForCausalLM": ("deepseek_v2", "DeepseekV3ForCausalLM"),
75
    "Dots1ForCausalLM": ("dots1", "Dots1ForCausalLM"),
76
    "Ernie4_5ForCausalLM": ("ernie45", "Ernie4_5ForCausalLM"),
77
    "Ernie4_5_MoeForCausalLM": ("ernie45_moe", "Ernie4_5_MoeForCausalLM"),
78
    "ExaoneForCausalLM": ("exaone", "ExaoneForCausalLM"),
79
    "Exaone4ForCausalLM": ("exaone4", "Exaone4ForCausalLM"),
80
    "FalconForCausalLM": ("falcon", "FalconForCausalLM"),
81
    "FM9GForCausalLM": ("fm9g", "FM9GForCausalLM"),
82
    "Fairseq2LlamaForCausalLM": ("fairseq2_llama", "Fairseq2LlamaForCausalLM"),
83
84
    "GemmaForCausalLM": ("gemma", "GemmaForCausalLM"),
    "Gemma2ForCausalLM": ("gemma2", "Gemma2ForCausalLM"),
85
    "Gemma3ForCausalLM": ("gemma3", "Gemma3ForCausalLM"),
Nicolò Lucchesi's avatar
Nicolò Lucchesi committed
86
    "Gemma3nForCausalLM": ("gemma3n", "Gemma3nForCausalLM"),
87
    "Qwen3NextForCausalLM": ("qwen3_next", "Qwen3NextForCausalLM"),
88
    "GlmForCausalLM": ("glm", "GlmForCausalLM"),
Yuxuan Zhang's avatar
Yuxuan Zhang committed
89
    "Glm4ForCausalLM": ("glm4", "Glm4ForCausalLM"),
zhuwenwen's avatar
zhuwenwen committed
90
    "Glm4MoeForCausalLM": ("glm4_moe", "Glm4MoeForCausalLM"),
91
    "GptOssForCausalLM": ("gpt_oss", "GptOssForCausalLM"),
92
93
94
95
96
97
    "GPT2LMHeadModel": ("gpt2", "GPT2LMHeadModel"),
    "GPTBigCodeForCausalLM": ("gpt_bigcode", "GPTBigCodeForCausalLM"),
    "GPTJForCausalLM": ("gpt_j", "GPTJForCausalLM"),
    "GPTNeoXForCausalLM": ("gpt_neox", "GPTNeoXForCausalLM"),
    "GraniteForCausalLM": ("granite", "GraniteForCausalLM"),
    "GraniteMoeForCausalLM": ("granitemoe", "GraniteMoeForCausalLM"),
98
    "GraniteMoeHybridForCausalLM": ("granitemoehybrid", "GraniteMoeHybridForCausalLM"),   # noqa: E501
99
    "GraniteMoeSharedForCausalLM": ("granitemoeshared", "GraniteMoeSharedForCausalLM"),   # noqa: E501
100
    "GritLM": ("gritlm", "GritLM"),
Michael Goin's avatar
Michael Goin committed
101
    "Grok1ModelForCausalLM": ("grok1", "Grok1ForCausalLM"),
102
103
    "HunYuanMoEV1ForCausalLM": ("hunyuan_v1", "HunYuanMoEV1ForCausalLM"),
    "HunYuanDenseV1ForCausalLM": ("hunyuan_v1", "HunYuanDenseV1ForCausalLM"),
104
    "HunYuanForCausalLM": ("hunyuan", "HunYuanForCausalLM"),
105
    "HCXVisionForCausalLM": ("hyperclovax_vision", "HCXVisionForCausalLM"),
106
107
    "InternLMForCausalLM": ("llama", "LlamaForCausalLM"),
    "InternLM2ForCausalLM": ("internlm2", "InternLM2ForCausalLM"),
108
    "InternLM2VEForCausalLM": ("internlm2_ve", "InternLM2VEForCausalLM"),
109
    "InternLM3ForCausalLM": ("llama", "LlamaForCausalLM"),
110
111
    "JAISLMHeadModel": ("jais", "JAISLMHeadModel"),
    "JambaForCausalLM": ("jamba", "JambaForCausalLM"),
112
    "Lfm2ForCausalLM": ("lfm2", "Lfm2ForCausalLM"),
113
    "LlamaForCausalLM": ("llama", "LlamaForCausalLM"),
114
    "Llama4ForCausalLM": ("llama4", "Llama4ForCausalLM"),  # noqa: E501
115
116
    # For decapoda-research/llama-*
    "LLaMAForCausalLM": ("llama", "LlamaForCausalLM"),
zhuwenwen's avatar
zhuwenwen committed
117
    "LongcatFlashForCausalLM": ("longcat_flash", "LongcatFlashForCausalLM"),
118
    "MambaForCausalLM": ("mamba", "MambaForCausalLM"),
119
    "FalconMambaForCausalLM": ("mamba", "MambaForCausalLM"),
Dhia Eddine Rhaiem's avatar
Dhia Eddine Rhaiem committed
120
    "FalconH1ForCausalLM":("falcon_h1", "FalconH1ForCausalLM"),
121
    "Mamba2ForCausalLM": ("mamba2", "Mamba2ForCausalLM"),
122
123
    "MiniCPMForCausalLM": ("minicpm", "MiniCPMForCausalLM"),
    "MiniCPM3ForCausalLM": ("minicpm3", "MiniCPM3ForCausalLM"),
124
125
    "MistralForCausalLM": ("llama", "LlamaForCausalLM"),
    "MixtralForCausalLM": ("mixtral", "MixtralForCausalLM"),
126
    "MotifForCausalLM": ("motif", "MotifForCausalLM"),
127
128
129
    # transformers's mpt class has lower case
    "MptForCausalLM": ("mpt", "MPTForCausalLM"),
    "MPTForCausalLM": ("mpt", "MPTForCausalLM"),
130
    "MiMoForCausalLM": ("mimo", "MiMoForCausalLM"),
131
    "NemotronForCausalLM": ("nemotron", "NemotronForCausalLM"),
Luis Vega's avatar
Luis Vega committed
132
    "NemotronHForCausalLM": ("nemotron_h", "NemotronHForCausalLM"),
133
    "OlmoForCausalLM": ("olmo", "OlmoForCausalLM"),
134
    "Olmo2ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
135
    "Olmo3ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
136
137
138
139
140
141
142
    "OlmoeForCausalLM": ("olmoe", "OlmoeForCausalLM"),
    "OPTForCausalLM": ("opt", "OPTForCausalLM"),
    "OrionForCausalLM": ("orion", "OrionForCausalLM"),
    "PersimmonForCausalLM": ("persimmon", "PersimmonForCausalLM"),
    "PhiForCausalLM": ("phi", "PhiForCausalLM"),
    "Phi3ForCausalLM": ("phi3", "Phi3ForCausalLM"),
    "PhiMoEForCausalLM": ("phimoe", "PhiMoEForCausalLM"),
Shinichi Hemmi's avatar
Shinichi Hemmi committed
143
    "Plamo2ForCausalLM": ("plamo2", "Plamo2ForCausalLM"),
144
    "QWenLMHeadModel": ("qwen", "QWenLMHeadModel"),
145
146
    "Qwen2ForCausalLM": ("qwen2", "Qwen2ForCausalLM"),
    "Qwen2MoeForCausalLM": ("qwen2_moe", "Qwen2MoeForCausalLM"),
147
148
    "Qwen3ForCausalLM": ("qwen3", "Qwen3ForCausalLM"),
    "Qwen3MoeForCausalLM": ("qwen3_moe", "Qwen3MoeForCausalLM"),
149
    "RWForCausalLM": ("falcon", "FalconForCausalLM"),
150
    "SeedOssForCausalLM": ("seed_oss", "SeedOssForCausalLM"),
zhuwenwen's avatar
zhuwenwen committed
151
    "Step3TextForCausalLM": ("step3_text", "Step3TextForCausalLM"),
152
153
154
155
    "StableLMEpochForCausalLM": ("stablelm", "StablelmForCausalLM"),
    "StableLmForCausalLM": ("stablelm", "StablelmForCausalLM"),
    "Starcoder2ForCausalLM": ("starcoder2", "Starcoder2ForCausalLM"),
    "SolarForCausalLM": ("solar", "SolarForCausalLM"),
156
    "TeleChat2ForCausalLM": ("telechat2", "TeleChat2ForCausalLM"),
157
    "TeleFLMForCausalLM": ("teleflm", "TeleFLMForCausalLM"),
158
    "XverseForCausalLM": ("llama", "LlamaForCausalLM"),
159
    "Zamba2ForCausalLM": ("zamba2", "Zamba2ForCausalLM"),
160
161
162
}

_EMBEDDING_MODELS = {
163
    # [Text-only]
164
    "BertModel": ("bert", "BertEmbeddingModel"),
165
    "DeciLMForCausalLM": ("nemotron_nas", "DeciLMForCausalLM"),
166
    "Gemma2Model": ("gemma2", "Gemma2ForCausalLM"),
167
    "Gemma3TextModel": ("gemma3", "Gemma3Model"),
168
    "GlmForCausalLM": ("glm", "GlmForCausalLM"),
169
    "GPT2ForSequenceClassification": ("gpt2", "GPT2ForSequenceClassification"),
170
    "GritLM": ("gritlm", "GritLM"),
171
172
    "GteModel": ("bert_with_rope", "SnowflakeGteNewModel"),
    "GteNewModel": ("bert_with_rope", "GteNewModel"),
173
    "InternLM2ForRewardModel": ("internlm2", "InternLM2ForRewardModel"),
174
    "JambaForSequenceClassification": ("jamba", "JambaForSequenceClassification"),  # noqa: E501
175
    "LlamaModel": ("llama", "LlamaForCausalLM"),
176
177
178
179
180
    **{
        # Multiple models share the same architecture, so we include them all
        k: (mod, arch) for k, (mod, arch) in _TEXT_GENERATION_MODELS.items()
        if arch == "LlamaForCausalLM"
    },
181
    "MistralModel": ("llama", "LlamaForCausalLM"),
182
    "ModernBertModel": ("modernbert", "ModernBertModel"),
183
    "NomicBertModel": ("bert_with_rope", "NomicBertModel"),
184
    "Phi3ForCausalLM": ("phi3", "Phi3ForCausalLM"),
185
    "Qwen2Model": ("qwen2", "Qwen2ForCausalLM"),
186
    "Qwen2ForCausalLM": ("qwen2", "Qwen2ForCausalLM"),
187
    "Qwen2ForRewardModel": ("qwen2_rm", "Qwen2ForRewardModel"),
188
    "Qwen2ForProcessRewardModel": ("qwen2_rm", "Qwen2ForProcessRewardModel"),
189
190
    "RobertaForMaskedLM": ("roberta", "RobertaEmbeddingModel"),
    "RobertaModel": ("roberta", "RobertaEmbeddingModel"),
191
    "TeleChat2ForCausalLM": ("telechat2", "TeleChat2ForCausalLM"),
192
    "XLMRobertaModel": ("roberta", "RobertaEmbeddingModel"),
193
    # [Multimodal]
Cyrus Leung's avatar
Cyrus Leung committed
194
    "LlavaNextForConditionalGeneration": ("llava_next", "LlavaNextForConditionalGeneration"),  # noqa: E501
195
    "Phi3VForCausalLM": ("phi3v", "Phi3VForCausalLM"),
196
    "Qwen2VLForConditionalGeneration": ("qwen2_vl", "Qwen2VLForConditionalGeneration"),  # noqa: E501
197
    # Technically Terratorch models work on images, both in
198
199
    # input and output. I am adding it here because it piggy-backs on embedding
    # models for the time being.
200
201
    "PrithviGeoSpatialMAE": ("terratorch", "Terratorch"),
    "Terratorch": ("terratorch", "Terratorch"),
202
203
}

204
205
_CROSS_ENCODER_MODELS = {
    "BertForSequenceClassification": ("bert", "BertForSequenceClassification"),
206
    "BertForTokenClassification": ("bert", "BertForTokenClassification"),
207
208
209
210
    "GteNewForSequenceClassification": ("bert_with_rope",
                                        "GteNewForSequenceClassification"),
    "ModernBertForSequenceClassification": ("modernbert",
                                            "ModernBertForSequenceClassification"),
211
212
213
214
    "RobertaForSequenceClassification": ("roberta",
                                         "RobertaForSequenceClassification"),
    "XLMRobertaForSequenceClassification": ("roberta",
                                            "RobertaForSequenceClassification"),
215
    # [Auto-converted (see adapters.py)]
216
    "JinaVLForRanking": ("jina_vl", "JinaVLForSequenceClassification"), # noqa: E501,
217
218
}

219
_MULTIMODAL_MODELS = {
220
    # [Decoder-only]
221
    "AriaForConditionalGeneration": ("aria", "AriaForConditionalGeneration"),
Jennifer Zhao's avatar
Jennifer Zhao committed
222
    "AyaVisionForConditionalGeneration": ("aya_vision", "AyaVisionForConditionalGeneration"),  # noqa: E501
223
224
    "Blip2ForConditionalGeneration": ("blip2", "Blip2ForConditionalGeneration"),
    "ChameleonForConditionalGeneration": ("chameleon", "ChameleonForConditionalGeneration"),  # noqa: E501
225
    "Cohere2VisionForConditionalGeneration": ("cohere2_vision", "Cohere2VisionForConditionalGeneration"),  # noqa: E501
226
    "DeepseekVLV2ForCausalLM": ("deepseek_vl2", "DeepseekVLV2ForCausalLM"),
Roger Wang's avatar
Roger Wang committed
227
    "DotsOCRForCausalLM": ("dots_ocr", "DotsOCRForCausalLM"),
228
    "Ernie4_5_VLMoeForConditionalGeneration": ("ernie45_vl", "Ernie4_5_VLMoeForConditionalGeneration"),  # noqa: E501
229
    "FuyuForCausalLM": ("fuyu", "FuyuForCausalLM"),
230
    "Gemma3ForConditionalGeneration": ("gemma3_mm", "Gemma3ForConditionalGeneration"),  # noqa: E501
Nicolò Lucchesi's avatar
Nicolò Lucchesi committed
231
    "Gemma3nForConditionalGeneration": ("gemma3n_mm", "Gemma3nForConditionalGeneration"),    # noqa: E501
232
    "GLM4VForCausalLM": ("glm4v", "GLM4VForCausalLM"),
233
    "Glm4vForConditionalGeneration": ("glm4_1v", "Glm4vForConditionalGeneration"),  # noqa: E501
Jee Jee Li's avatar
Jee Jee Li committed
234
    "Glm4vMoeForConditionalGeneration": ("glm4_1v", "Glm4vMoeForConditionalGeneration"),  # noqa: E501
235
    "GraniteSpeechForConditionalGeneration": ("granite_speech", "GraniteSpeechForConditionalGeneration"),  # noqa: E501
236
    "H2OVLChatModel": ("h2ovl", "H2OVLChatModel"),
237
    "InternVLChatModel": ("internvl", "InternVLChatModel"),
238
    "NemotronH_Nano_VL_V2": ("nano_nemotron_vl", "NemotronH_Nano_VL_V2"),
Lyu Han's avatar
Lyu Han committed
239
    "InternS1ForConditionalGeneration": ("interns1", "InternS1ForConditionalGeneration"),  # noqa: E501
240
    "InternVLForConditionalGeneration": ("interns1", "InternS1ForConditionalGeneration"),  # noqa: E501
241
    "Idefics3ForConditionalGeneration":("idefics3","Idefics3ForConditionalGeneration"),
242
    "SmolVLMForConditionalGeneration": ("smolvlm","SmolVLMForConditionalGeneration"),  # noqa: E501
243
    "KeyeForConditionalGeneration": ("keye", "KeyeForConditionalGeneration"),
244
    "KeyeVL1_5ForConditionalGeneration": ("keye_vl1_5", "KeyeVL1_5ForConditionalGeneration"), # noqa: E501
245
    "RForConditionalGeneration": ("rvl", "RForConditionalGeneration"),
246
    "KimiVLForConditionalGeneration": ("kimi_vl", "KimiVLForConditionalGeneration"),  # noqa: E501
247
    "Llama_Nemotron_Nano_VL": ("nemotron_vl", "LlamaNemotronVLChatModel"),
248
    "Llama4ForConditionalGeneration": ("mllama4", "Llama4ForConditionalGeneration"),  # noqa: E501
249
250
251
252
    "LlavaForConditionalGeneration": ("llava", "LlavaForConditionalGeneration"),
    "LlavaNextForConditionalGeneration": ("llava_next", "LlavaNextForConditionalGeneration"),  # noqa: E501
    "LlavaNextVideoForConditionalGeneration": ("llava_next_video", "LlavaNextVideoForConditionalGeneration"),  # noqa: E501
    "LlavaOnevisionForConditionalGeneration": ("llava_onevision", "LlavaOnevisionForConditionalGeneration"),  # noqa: E501
253
    "MantisForConditionalGeneration": ("llava", "MantisForConditionalGeneration"),  # noqa: E501
254
    "MiDashengLMModel": ("midashenglm", "MiDashengLMModel"),
255
    "MiniMaxVL01ForConditionalGeneration": ("minimax_vl_01", "MiniMaxVL01ForConditionalGeneration"),  # noqa: E501
256
    "MiniCPMO": ("minicpmo", "MiniCPMO"),
257
    "MiniCPMV": ("minicpmv", "MiniCPMV"),
258
    "Mistral3ForConditionalGeneration": ("mistral3", "Mistral3ForConditionalGeneration"),  # noqa: E501
259
    "MolmoForCausalLM": ("molmo", "MolmoForCausalLM"),
260
    "NVLM_D": ("nvlm_d", "NVLM_D_Model"),
261
    "Ovis": ("ovis", "Ovis"),
262
    "Ovis2_5": ("ovis2_5", "Ovis2_5"),
263
    "PaliGemmaForConditionalGeneration": ("paligemma", "PaliGemmaForConditionalGeneration"),  # noqa: E501
264
    "Phi3VForCausalLM": ("phi3v", "Phi3VForCausalLM"),
265
266
    "Phi4MMForCausalLM": ("phi4mm", "Phi4MMForCausalLM"),
    "Phi4MultimodalForCausalLM": ("phi4_multimodal", "Phi4MultimodalForCausalLM"),  # noqa: E501
267
    "PixtralForConditionalGeneration": ("pixtral", "PixtralForConditionalGeneration"),  # noqa: E501
268
    "QwenVLForConditionalGeneration": ("qwen_vl", "QwenVLForConditionalGeneration"),  # noqa: E501
269
    "Qwen2VLForConditionalGeneration": ("qwen2_vl", "Qwen2VLForConditionalGeneration"),  # noqa: E501
Roger Wang's avatar
Roger Wang committed
270
    "Qwen2_5_VLForConditionalGeneration": ("qwen2_5_vl", "Qwen2_5_VLForConditionalGeneration"),  # noqa: E501
271
    "Qwen2AudioForConditionalGeneration": ("qwen2_audio", "Qwen2AudioForConditionalGeneration"),  # noqa: E501
272
    "Qwen2_5OmniModel": ("qwen2_5_omni_thinker", "Qwen2_5OmniThinkerForConditionalGeneration"),  # noqa: E501
273
    "Qwen2_5OmniForConditionalGeneration": ("qwen2_5_omni_thinker", "Qwen2_5OmniThinkerForConditionalGeneration"),  # noqa: E501
274
275
    "Qwen3VLForConditionalGeneration": ("qwen3_vl", "Qwen3VLForConditionalGeneration"),  # noqa: E501
    "Qwen3VLMoeForConditionalGeneration": ("qwen3_vl_moe", "Qwen3VLMoeForConditionalGeneration"),  # noqa: E501
276
    "SkyworkR1VChatModel": ("skyworkr1v", "SkyworkR1VChatModel"),
zhuwenwen's avatar
zhuwenwen committed
277
    "Step3VLForConditionalGeneration": ("step3_vl", "Step3VLForConditionalGeneration"),  # noqa: E501
汪志鹏's avatar
汪志鹏 committed
278
    "TarsierForConditionalGeneration": ("tarsier", "TarsierForConditionalGeneration"),  # noqa: E501
279
    "Tarsier2ForConditionalGeneration": ("qwen2_vl", "Tarsier2ForConditionalGeneration"),  # noqa: E501
280
    "UltravoxModel": ("ultravox", "UltravoxModel"),
Patrick von Platen's avatar
Patrick von Platen committed
281
    "VoxtralForConditionalGeneration": ("voxtral", "VoxtralForConditionalGeneration"),  # noqa: E501
282
    # [Encoder-decoder]
283
    "WhisperForConditionalGeneration": ("whisper", "WhisperForConditionalGeneration"),  # noqa: E501
284
}
285
286

_SPECULATIVE_DECODING_MODELS = {
287
    "MiMoMTPModel": ("mimo_mtp", "MiMoMTP"),
288
    "EagleLlamaForCausalLM": ("llama_eagle", "EagleLlamaForCausalLM"),
zhiweiz's avatar
zhiweiz committed
289
    "EagleLlama4ForCausalLM": ("llama4_eagle", "EagleLlama4ForCausalLM"),
290
    "EagleMiniCPMForCausalLM": ("minicpm_eagle", "EagleMiniCPMForCausalLM"),
291
    "Eagle3LlamaForCausalLM": ("llama_eagle3", "Eagle3LlamaForCausalLM"),
292
    "LlamaForCausalLMEagle3": ("llama_eagle3", "Eagle3LlamaForCausalLM"),
293
    "EagleDeepSeekMTPModel": ("deepseek_eagle", "EagleDeepseekV3ForCausalLM"),
294
    "DeepSeekMTPModel": ("deepseek_mtp", "DeepSeekMTP"),
295
    "ErnieMTPModel": ("ernie_mtp", "ErnieMTP"),
zhuwenwen's avatar
zhuwenwen committed
296
    "LongCatFlashMTPModel": ("longcat_flash_mtp", "LongCatFlashMTP"),
zhuwenwen's avatar
zhuwenwen committed
297
    "Glm4MoeMTPModel": ("glm4_moe_mtp", "Glm4MoeMTP"),
298
    "MedusaModel": ("medusa", "Medusa"),
299
    "Qwen3NextMTP": ("qwen3_next_mtp", "Qwen3NextMTP"),
300
301
302
    # Temporarily disabled.
    # # TODO(woosuk): Re-enable this once the MLP Speculator is supported in V1.
    # "MLPSpeculatorPreTrainedModel": ("mlp_speculator", "MLPSpeculator"),
303
}
304

305
_TRANSFORMERS_SUPPORTED_MODELS = {
306
307
308
    # Text generation models
    "SmolLM3ForCausalLM": ("transformers", "TransformersForCausalLM"),
    # Multimodal models
309
310
311
312
    "Emu3ForConditionalGeneration": ("transformers", "TransformersForMultimodalLM"),  # noqa: E501
}

_TRANSFORMERS_BACKEND_MODELS = {
313
    "TransformersModel": ("transformers", "TransformersModel"),
314
    "TransformersForCausalLM": ("transformers", "TransformersForCausalLM"),
315
    "TransformersForMultimodalLM": ("transformers", "TransformersForMultimodalLM"), # noqa: E501
316
}
317
# yapf: enable
318

319
_VLLM_MODELS = {
320
    **_TEXT_GENERATION_MODELS,
321
    **_EMBEDDING_MODELS,
322
    **_CROSS_ENCODER_MODELS,
323
    **_MULTIMODAL_MODELS,
324
    **_SPECULATIVE_DECODING_MODELS,
325
326
    **_TRANSFORMERS_SUPPORTED_MODELS,
    **_TRANSFORMERS_BACKEND_MODELS,
327
328
}

329
330
331
332
333
334
335
336
# This variable is used as the args for subprocess.run(). We
# can modify  this variable to alter the args if needed. e.g.
# when we use par format to pack things together, sys.executable
# might not be the target we want to run.
_SUBPROCESS_COMMAND = [
    sys.executable, "-m", "vllm.model_executor.models.registry"
]

337
338
339
340
341
342
343
344
345
346
347
_PREVIOUSLY_SUPPORTED_MODELS = {
    "Phi3SmallForCausalLM": "0.9.2",
    # encoder-decoder models except whisper
    # have been removed for V0 deprecation.
    "BartModel": "0.10.2",
    "BartForConditionalGeneration": "0.10.2",
    "DonutForConditionalGeneration": "0.10.2",
    "Florence2ForConditionalGeneration": "0.10.2",
    "MBartForConditionalGeneration": "0.10.2",
    "MllamaForConditionalGeneration": "0.10.2",
}
348

349

350
351
@dataclass(frozen=True)
class _ModelInfo:
352
    architecture: str
353
    is_text_generation_model: bool
354
    is_pooling_model: bool
355
    default_pooling_type: str
356
    supports_cross_encoding: bool
357
    supports_multimodal: bool
358
    supports_multimodal_raw_input_only: bool
359
    supports_multimodal_encoder_tp_data: bool
360
    supports_pp: bool
361
362
    has_inner_state: bool
    is_attention_free: bool
363
    is_hybrid: bool
364
    has_noops: bool
365
    supports_transcription: bool
366
    supports_transcription_only: bool
367
    supports_v0_only: bool
368
369

    @staticmethod
370
    def from_model_cls(model: type[nn.Module]) -> "_ModelInfo":
371
        return _ModelInfo(
372
            architecture=model.__name__,
373
            is_text_generation_model=is_text_generation_model(model),
374
            is_pooling_model=is_pooling_model(model),
375
            default_pooling_type=get_default_pooling_type(model),
376
            supports_cross_encoding=supports_cross_encoding(model),
377
            supports_multimodal=supports_multimodal(model),
378
379
            supports_multimodal_raw_input_only=
            supports_multimodal_raw_input_only(model),
380
381
            supports_multimodal_encoder_tp_data=
            supports_multimodal_encoder_tp_data(model),
382
            supports_pp=supports_pp(model),
383
384
            has_inner_state=has_inner_state(model),
            is_attention_free=is_attention_free(model),
385
            is_hybrid=is_hybrid(model),
386
            supports_transcription=supports_transcription(model),
387
388
            supports_transcription_only=(supports_transcription(model) and
                                         model.supports_transcription_only),
389
            supports_v0_only=supports_v0_only(model),
390
            has_noops=has_noops(model),
391
        )
392
393


394
class _BaseRegisteredModel(ABC):
395

396
397
398
    @abstractmethod
    def inspect_model_cls(self) -> _ModelInfo:
        raise NotImplementedError
399

400
    @abstractmethod
401
    def load_model_cls(self) -> type[nn.Module]:
402
        raise NotImplementedError
403
404


405
406
407
408
409
410
411
@dataclass(frozen=True)
class _RegisteredModel(_BaseRegisteredModel):
    """
    Represents a model that has already been imported in the main process.
    """

    interfaces: _ModelInfo
412
    model_cls: type[nn.Module]
413
414

    @staticmethod
415
    def from_model_cls(model_cls: type[nn.Module]):
416
417
418
419
420
421
422
423
        return _RegisteredModel(
            interfaces=_ModelInfo.from_model_cls(model_cls),
            model_cls=model_cls,
        )

    def inspect_model_cls(self) -> _ModelInfo:
        return self.interfaces

424
    def load_model_cls(self) -> type[nn.Module]:
425
426
427
428
429
430
431
432
433
434
435
        return self.model_cls


@dataclass(frozen=True)
class _LazyRegisteredModel(_BaseRegisteredModel):
    """
    Represents a model that has not been imported in the main process.
    """
    module_name: str
    class_name: str

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
    @staticmethod
    def _get_cache_dir() -> Path:
        return Path(envs.VLLM_CACHE_ROOT) / "modelinfos"

    def _get_cache_filename(self) -> str:
        cls_name = f"{self.module_name}-{self.class_name}".replace(".", "-")
        return f"{cls_name}.json"

    def _load_modelinfo_from_cache(self,
                                   module_hash: str) -> _ModelInfo | None:
        try:
            try:
                modelinfo_path = self._get_cache_dir(
                ) / self._get_cache_filename()
                with open(modelinfo_path, encoding="utf-8") as file:
                    mi_dict = json.load(file)
            except FileNotFoundError:
                logger.debug(("Cached model info file "
                              "for class %s.%s not found"), self.module_name,
                             self.class_name)
                return None

            if mi_dict["hash"] != module_hash:
                logger.debug(("Cached model info file "
                              "for class %s.%s is stale"), self.module_name,
                             self.class_name)
                return None

            # file not changed, use cached _ModelInfo properties
            return _ModelInfo(**mi_dict["modelinfo"])
        except Exception:
            logger.exception(("Cached model info "
                              "for class %s.%s error. "), self.module_name,
                             self.class_name)
            return None

    def _save_modelinfo_to_cache(self, mi: _ModelInfo,
                                 module_hash: str) -> None:
        """save dictionary json file to cache"""
        from vllm.model_executor.model_loader.weight_utils import atomic_writer
        try:
            modelinfo_dict = {
                "hash": module_hash,
                "modelinfo": asdict(mi),
            }
            cache_dir = self._get_cache_dir()
            cache_dir.mkdir(parents=True, exist_ok=True)
            modelinfo_path = cache_dir / self._get_cache_filename()
            with atomic_writer(modelinfo_path, encoding='utf-8') as f:
                json.dump(modelinfo_dict, f, indent=2)
        except Exception:
            logger.exception("Error saving model info cache.")

    @logtime(logger=logger, msg="Registry inspect model class")
490
    def inspect_model_cls(self) -> _ModelInfo:
491
492
        model_path = Path(
            __file__).parent / f"{self.module_name.split('.')[-1]}.py"
493
        module_hash = None
494

495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
        if model_path.exists():
            with open(model_path, "rb") as f:
                module_hash = hashlib.md5(f.read()).hexdigest()

            mi = self._load_modelinfo_from_cache(module_hash)
            if mi is not None:
                logger.debug(("Loaded model info "
                              "for class %s.%s from cache"), self.module_name,
                             self.class_name)
                return mi
            else:
                logger.debug(("Cache model info "
                              "for class %s.%s miss. "
                              "Loading model instead."), self.module_name,
                             self.class_name)
510
511
512

        # Performed in another process to avoid initializing CUDA
        mi = _run_in_subprocess(
513
            lambda: _ModelInfo.from_model_cls(self.load_model_cls()))
514
515
516
517
        logger.debug("Loaded model info for class %s.%s", self.module_name,
                     self.class_name)

        # save cache file
518
519
        if module_hash is not None:
            self._save_modelinfo_to_cache(mi, module_hash)
520
521

        return mi
522

523
    def load_model_cls(self) -> type[nn.Module]:
524
525
526
527
528
529
530
531
        mod = importlib.import_module(self.module_name)
        return getattr(mod, self.class_name)


@lru_cache(maxsize=128)
def _try_load_model_cls(
    model_arch: str,
    model: _BaseRegisteredModel,
532
) -> Optional[type[nn.Module]]:
533
    from vllm.platforms import current_platform
534
    current_platform.verify_model_arch(model_arch)
535
536
537
538
539
540
    try:
        return model.load_model_cls()
    except Exception:
        logger.exception("Error in loading model architecture '%s'",
                         model_arch)
        return None
541
542


543
544
545
546
547
548
549
550
551
552
553
@lru_cache(maxsize=128)
def _try_inspect_model_cls(
    model_arch: str,
    model: _BaseRegisteredModel,
) -> Optional[_ModelInfo]:
    try:
        return model.inspect_model_cls()
    except Exception:
        logger.exception("Error in inspecting model architecture '%s'",
                         model_arch)
        return None
554
555


556
557
558
@dataclass
class _ModelRegistry:
    # Keyed by model_arch
559
    models: dict[str, _BaseRegisteredModel] = field(default_factory=dict)
560

561
    def get_supported_archs(self) -> Set[str]:
562
        return self.models.keys()
563

564
565
566
    def register_model(
        self,
        model_arch: str,
567
        model_cls: Union[type[nn.Module], str],
568
    ) -> None:
569
570
571
        """
        Register an external model to be used in vLLM.

572
        `model_cls` can be either:
573

574
        - A [`torch.nn.Module`][] class directly referencing the model.
575
        - A string in the format `<module>:<class>` which can be used to
576
577
          lazily import the model. This is useful to avoid initializing CUDA
          when importing the model and thus the related error
578
          `RuntimeError: Cannot re-initialize CUDA in forked subprocess`.
579
        """
580
581
582
583
        if not isinstance(model_arch, str):
            msg = f"`model_arch` should be a string, not a {type(model_arch)}"
            raise TypeError(msg)

584
        if model_arch in self.models:
585
586
587
            logger.warning(
                "Model architecture %s is already registered, and will be "
                "overwritten by the new model class %s.", model_arch,
588
589
590
591
592
593
594
                model_cls)

        if isinstance(model_cls, str):
            split_str = model_cls.split(":")
            if len(split_str) != 2:
                msg = "Expected a string in the format `<module>:<class>`"
                raise ValueError(msg)
595

596
            model = _LazyRegisteredModel(*split_str)
597
        elif isinstance(model_cls, type) and issubclass(model_cls, nn.Module):
598
            model = _RegisteredModel.from_model_cls(model_cls)
599
600
601
602
        else:
            msg = ("`model_cls` should be a string or PyTorch model class, "
                   f"not a {type(model_arch)}")
            raise TypeError(msg)
603

604
        self.models[model_arch] = model
605

606
    def _raise_for_unsupported(self, architectures: list[str]):
607
        all_supported_archs = self.get_supported_archs()
608

609
610
611
612
613
        if any(arch in all_supported_archs for arch in architectures):
            raise ValueError(
                f"Model architectures {architectures} failed "
                "to be inspected. Please check the logs for more details.")

614
615
616
617
618
619
620
621
622
623
        for arch in architectures:
            if arch in _PREVIOUSLY_SUPPORTED_MODELS:
                previous_version = _PREVIOUSLY_SUPPORTED_MODELS[arch]

                raise ValueError(
                    f"Model architecture {arch} was supported in vLLM until "
                    f"v{previous_version}, and is not supported anymore. "
                    "Please use an older version of vLLM if you want to "
                    "use this model architecture.")

624
625
626
        raise ValueError(
            f"Model architectures {architectures} are not supported for now. "
            f"Supported architectures: {all_supported_archs}")
627

628
    def _try_load_model_cls(self,
629
                            model_arch: str) -> Optional[type[nn.Module]]:
630
631
        if model_arch not in self.models:
            return None
632

633
        return _try_load_model_cls(model_arch, self.models[model_arch])
634

635
    def _try_inspect_model_cls(self, model_arch: str) -> Optional[_ModelInfo]:
636
637
        if model_arch not in self.models:
            return None
638

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
        return _try_inspect_model_cls(model_arch, self.models[model_arch])

    def _try_resolve_transformers(
        self,
        architecture: str,
        model_config: ModelConfig,
    ) -> Optional[str]:
        if architecture in _TRANSFORMERS_BACKEND_MODELS:
            return architecture

        auto_map: dict[str, str] = getattr(model_config.hf_config, "auto_map",
                                           None) or dict()

        # Make sure that config class is always initialized before model class,
        # otherwise the model class won't be able to access the config class,
        # the expected auto_map should have correct order like:
        # "auto_map": {
        #     "AutoConfig": "<your-repo-name>--<config-name>",
        #     "AutoModel": "<your-repo-name>--<config-name>",
        #     "AutoModelFor<Task>": "<your-repo-name>--<config-name>",
        # },
        for prefix in ("AutoConfig", "AutoModel"):
            for name, module in auto_map.items():
                if name.startswith(prefix):
                    try_get_class_from_dynamic_module(
                        module,
                        model_config.model,
                        revision=model_config.revision,
                        warn_on_fail=False,
                    )

        model_module = getattr(transformers, architecture, None)

        if model_module is None:
            for name, module in auto_map.items():
                if name.startswith("AutoModel"):
                    model_module = try_get_class_from_dynamic_module(
                        module,
                        model_config.model,
                        revision=model_config.revision,
                        warn_on_fail=True,
                    )
                    if model_module is not None:
                        break
            else:
684
                if model_config.model_impl != "transformers":
685
686
687
688
689
690
691
692
693
694
                    return None

                raise ValueError(
                    f"Cannot find model module. {architecture!r} is not a "
                    "registered model in the Transformers library (only "
                    "relevant if the model is meant to be in Transformers) "
                    "and 'AutoModel' is not present in the model config's "
                    "'auto_map' (relevant if the model is custom).")

        if not model_module.is_backend_compatible():
695
            if model_config.model_impl != "transformers":
696
                return None
697

698
699
700
            raise ValueError(
                f"The Transformers implementation of {architecture!r} "
                "is not compatible with vLLM.")
701

702
        return model_config._get_transformers_backend_cls()
703

704
    def _normalize_arch(
705
        self,
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
        architecture: str,
        model_config: ModelConfig,
    ) -> str:
        if architecture in self.models:
            return architecture

        # This may be called in order to resolve runner_type and convert_type
        # in the first place, in which case we consider the default match
        match = try_match_architecture_defaults(
            architecture,
            runner_type=getattr(model_config, "runner_type", None),
            convert_type=getattr(model_config, "convert_type", None),
        )
        if match:
            suffix, _ = match
721

722
723
724
725
726
            # Get the name of the base model to convert
            for repl_suffix, _ in iter_architecture_defaults():
                base_arch = architecture.replace(suffix, repl_suffix)
                if base_arch in self.models:
                    return base_arch
727

728
        return architecture
729

730
731
    def inspect_model_cls(
        self,
732
        architectures: Union[str, list[str]],
733
        model_config: ModelConfig,
734
    ) -> tuple[_ModelInfo, str]:
735
736
        if isinstance(architectures, str):
            architectures = [architectures]
737
738
        if not architectures:
            raise ValueError("No model architectures are specified")
739
740

        # Require transformers impl
741
        if model_config.model_impl == "transformers":
742
743
744
745
746
747
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_info = self._try_inspect_model_cls(arch)
                if model_info is not None:
                    return (model_info, arch)
748
        elif model_config.model_impl == "terratorch":
749
750
            model_info = self._try_inspect_model_cls("Terratorch")
            return (model_info, "Terratorch")
751

752
753
        # Fallback to transformers impl (after resolving convert_type)
        if (all(arch not in self.models for arch in architectures)
754
                and model_config.model_impl == "auto"
755
756
757
758
759
760
761
                and getattr(model_config, "convert_type", "none") == "none"):
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_info = self._try_inspect_model_cls(arch)
                if model_info is not None:
                    return (model_info, arch)
762

763
        for arch in architectures:
764
            normalized_arch = self._normalize_arch(arch, model_config)
765
            model_info = self._try_inspect_model_cls(normalized_arch)
766
            if model_info is not None:
767
                return (model_info, arch)
768

769
770
        # Fallback to transformers impl (before resolving runner_type)
        if (all(arch not in self.models for arch in architectures)
771
                and model_config.model_impl == "auto"):
772
773
774
775
776
777
778
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_info = self._try_inspect_model_cls(arch)
                if model_info is not None:
                    return (model_info, arch)

779
        return self._raise_for_unsupported(architectures)
780

781
782
    def resolve_model_cls(
        self,
783
        architectures: Union[str, list[str]],
784
        model_config: ModelConfig,
785
    ) -> tuple[type[nn.Module], str]:
786
787
        if isinstance(architectures, str):
            architectures = [architectures]
788
789
        if not architectures:
            raise ValueError("No model architectures are specified")
790
791

        # Require transformers impl
792
        if model_config.model_impl == "transformers":
793
794
795
796
797
798
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_cls = self._try_load_model_cls(arch)
                if model_cls is not None:
                    return (model_cls, arch)
799
        elif model_config.model_impl == "terratorch":
800
801
802
803
            arch = "Terratorch"
            model_cls = self._try_load_model_cls(arch)
            if model_cls is not None:
                return (model_cls, arch)
804

805
806
        # Fallback to transformers impl (after resolving convert_type)
        if (all(arch not in self.models for arch in architectures)
807
                and model_config.model_impl == "auto"
808
809
810
811
812
813
814
                and getattr(model_config, "convert_type", "none") == "none"):
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_cls = self._try_load_model_cls(arch)
                if model_cls is not None:
                    return (model_cls, arch)
815

816
        for arch in architectures:
817
            normalized_arch = self._normalize_arch(arch, model_config)
818
            model_cls = self._try_load_model_cls(normalized_arch)
819
820
            if model_cls is not None:
                return (model_cls, arch)
821

822
823
        # Fallback to transformers impl (before resolving runner_type)
        if (all(arch not in self.models for arch in architectures)
824
                and model_config.model_impl == "auto"):
825
826
827
828
829
830
831
            arch = self._try_resolve_transformers(architectures[0],
                                                  model_config)
            if arch is not None:
                model_cls = self._try_load_model_cls(arch)
                if model_cls is not None:
                    return (model_cls, arch)

832
        return self._raise_for_unsupported(architectures)
833

834
835
    def is_text_generation_model(
        self,
836
        architectures: Union[str, list[str]],
837
        model_config: ModelConfig,
838
    ) -> bool:
839
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
840
        return model_cls.is_text_generation_model
841

842
    def is_pooling_model(
843
        self,
844
        architectures: Union[str, list[str]],
845
        model_config: ModelConfig,
846
    ) -> bool:
847
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
848
        return model_cls.is_pooling_model
849

850
851
    def is_cross_encoder_model(
        self,
852
        architectures: Union[str, list[str]],
853
        model_config: ModelConfig,
854
    ) -> bool:
855
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
856
        return model_cls.supports_cross_encoding
857

858
859
    def is_multimodal_model(
        self,
860
        architectures: Union[str, list[str]],
861
        model_config: ModelConfig,
862
    ) -> bool:
863
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
864
        return model_cls.supports_multimodal
865

866
    def is_multimodal_raw_input_only_model(
867
868
        self,
        architectures: Union[str, list[str]],
869
        model_config: ModelConfig,
870
    ) -> bool:
871
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
872
        return model_cls.supports_multimodal_raw_input_only
873

874
875
    def is_pp_supported_model(
        self,
876
        architectures: Union[str, list[str]],
877
        model_config: ModelConfig,
878
    ) -> bool:
879
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
880
        return model_cls.supports_pp
881

882
883
    def model_has_inner_state(
        self,
884
        architectures: Union[str, list[str]],
885
        model_config: ModelConfig,
886
    ) -> bool:
887
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
888
        return model_cls.has_inner_state
889

890
891
    def is_attention_free_model(
        self,
892
        architectures: Union[str, list[str]],
893
        model_config: ModelConfig,
894
    ) -> bool:
895
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
896
        return model_cls.is_attention_free
897

898
899
    def is_hybrid_model(
        self,
900
        architectures: Union[str, list[str]],
901
        model_config: ModelConfig,
902
    ) -> bool:
903
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
904
905
        return model_cls.is_hybrid

906
907
    def is_noops_model(
        self,
908
        architectures: Union[str, list[str]],
909
        model_config: ModelConfig,
910
    ) -> bool:
911
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
912
913
        return model_cls.has_noops

914
915
    def is_transcription_model(
        self,
916
        architectures: Union[str, list[str]],
917
        model_config: ModelConfig,
918
    ) -> bool:
919
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
920
921
        return model_cls.supports_transcription

922
923
924
    def is_transcription_only_model(
        self,
        architectures: Union[str, list[str]],
925
        model_config: ModelConfig,
926
    ) -> bool:
927
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
928
929
        return model_cls.supports_transcription_only

930
931
    def is_v1_compatible(
        self,
932
        architectures: Union[str, list[str]],
933
        model_config: ModelConfig,
934
    ) -> bool:
935
        model_cls, _ = self.inspect_model_cls(architectures, model_config)
936
937
        return not model_cls.supports_v0_only

938
939

ModelRegistry = _ModelRegistry({
940
941
    model_arch:
    _LazyRegisteredModel(
942
943
944
945
946
947
948
949
950
951
        module_name=f"vllm.model_executor.models.{mod_relname}",
        class_name=cls_name,
    )
    for model_arch, (mod_relname, cls_name) in _VLLM_MODELS.items()
})

_T = TypeVar("_T")


def _run_in_subprocess(fn: Callable[[], _T]) -> _T:
952
953
954
955
956
    # NOTE: We use a temporary directory instead of a temporary file to avoid
    # issues like https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
    with tempfile.TemporaryDirectory() as tempdir:
        output_filepath = os.path.join(tempdir, "registry_output.tmp")

957
        # `cloudpickle` allows pickling lambda functions directly
958
        import cloudpickle
959
        input_bytes = cloudpickle.dumps((fn, output_filepath))
960
961
962

        # cannot use `sys.executable __file__` here because the script
        # contains relative imports
963
964
965
        returned = subprocess.run(_SUBPROCESS_COMMAND,
                                  input=input_bytes,
                                  capture_output=True)
966
967
968
969
970
971
972
973
974

        # check if the subprocess is successful
        try:
            returned.check_returncode()
        except Exception as e:
            # wrap raised exception to provide more information
            raise RuntimeError(f"Error raised in subprocess:\n"
                               f"{returned.stderr.decode()}") from e

975
        with open(output_filepath, "rb") as f:
976
977
978
979
980
981
982
983
984
985
986
            return pickle.load(f)


def _run() -> None:
    # Setup plugins
    from vllm.plugins import load_general_plugins
    load_general_plugins()

    fn, output_file = pickle.loads(sys.stdin.buffer.read())

    result = fn()
987
988
989

    with open(output_file, "wb") as f:
        f.write(pickle.dumps(result))
990
991
992


if __name__ == "__main__":
993
    _run()