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

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

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

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

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

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

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

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

328
329
330
331
332
333
334
335
# 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"
]

336
337
338
339
340
341
342
343
344
345
346
_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",
}
347

348

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

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


393
class _BaseRegisteredModel(ABC):
394

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

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


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

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

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

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

423
    def load_model_cls(self) -> type[nn.Module]:
424
425
426
427
428
429
430
431
432
433
434
        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

435
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
    @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")
489
    def inspect_model_cls(self) -> _ModelInfo:
490
491
        model_path = Path(
            __file__).parent / f"{self.module_name.split('.')[-1]}.py"
492
        module_hash = None
493

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
        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)
509
510
511

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

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

        return mi
521

522
    def load_model_cls(self) -> type[nn.Module]:
523
524
525
526
527
528
529
530
        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,
531
) -> Optional[type[nn.Module]]:
532
    from vllm.platforms import current_platform
533
    current_platform.verify_model_arch(model_arch)
534
535
536
537
538
539
    try:
        return model.load_model_cls()
    except Exception:
        logger.exception("Error in loading model architecture '%s'",
                         model_arch)
        return None
540
541


542
543
544
545
546
547
548
549
550
551
552
@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
553
554


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

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

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

571
        `model_cls` can be either:
572

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

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

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

603
        self.models[model_arch] = model
604

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

608
609
610
611
612
        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.")

613
614
615
616
617
618
619
620
621
622
        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.")

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

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

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

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

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
        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:
683
                if model_config.model_impl != "transformers":
684
685
686
687
688
689
690
691
692
693
                    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():
694
            if model_config.model_impl != "transformers":
695
                return None
696

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

701
        return model_config._get_transformers_backend_cls()
702

703
    def _normalize_arch(
704
        self,
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
        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
720

721
722
723
724
725
            # 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
726

727
        return architecture
728

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

        # Require transformers impl
740
        if model_config.model_impl == "transformers":
741
742
743
744
745
746
            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)
747
        elif model_config.model_impl == "terratorch":
748
749
            model_info = self._try_inspect_model_cls("Terratorch")
            return (model_info, "Terratorch")
750

751
752
        # Fallback to transformers impl (after resolving convert_type)
        if (all(arch not in self.models for arch in architectures)
753
                and model_config.model_impl == "auto"
754
755
756
757
758
759
760
                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)
761

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

768
769
        # Fallback to transformers impl (before resolving runner_type)
        if (all(arch not in self.models for arch in architectures)
770
                and model_config.model_impl == "auto"):
771
772
773
774
775
776
777
            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)

778
        return self._raise_for_unsupported(architectures)
779

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

        # Require transformers impl
791
        if model_config.model_impl == "transformers":
792
793
794
795
796
797
            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)
798
        elif model_config.model_impl == "terratorch":
799
800
801
802
            arch = "Terratorch"
            model_cls = self._try_load_model_cls(arch)
            if model_cls is not None:
                return (model_cls, arch)
803

804
805
        # Fallback to transformers impl (after resolving convert_type)
        if (all(arch not in self.models for arch in architectures)
806
                and model_config.model_impl == "auto"
807
808
809
810
811
812
813
                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)
814

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

821
822
        # Fallback to transformers impl (before resolving runner_type)
        if (all(arch not in self.models for arch in architectures)
823
                and model_config.model_impl == "auto"):
824
825
826
827
828
829
830
            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)

831
        return self._raise_for_unsupported(architectures)
832

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

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

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

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

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

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

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

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

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

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

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

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

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

937
938

ModelRegistry = _ModelRegistry({
939
940
    model_arch:
    _LazyRegisteredModel(
941
942
943
944
945
946
947
948
949
950
        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:
951
952
953
954
955
    # 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")

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

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

        # 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

974
        with open(output_filepath, "rb") as f:
975
976
977
978
979
980
981
982
983
984
985
            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()
986
987
988

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


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