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
    "Dots1ForCausalLM": ("dots1", "Dots1ForCausalLM"),
74
    "Ernie4_5ForCausalLM": ("ernie45", "Ernie4_5ForCausalLM"),
75
    "Ernie4_5_MoeForCausalLM": ("ernie45_moe", "Ernie4_5_MoeForCausalLM"),
76
    "ExaoneForCausalLM": ("exaone", "ExaoneForCausalLM"),
77
    "Exaone4ForCausalLM": ("exaone4", "Exaone4ForCausalLM"),
78
    "FalconForCausalLM": ("falcon", "FalconForCausalLM"),
79
    "Fairseq2LlamaForCausalLM": ("fairseq2_llama", "Fairseq2LlamaForCausalLM"),
80
81
    "GemmaForCausalLM": ("gemma", "GemmaForCausalLM"),
    "Gemma2ForCausalLM": ("gemma2", "Gemma2ForCausalLM"),
82
    "Gemma3ForCausalLM": ("gemma3", "Gemma3ForCausalLM"),
Nicolò Lucchesi's avatar
Nicolò Lucchesi committed
83
    "Gemma3nForCausalLM": ("gemma3n", "Gemma3nForCausalLM"),
84
    "Qwen3NextForCausalLM": ("qwen3_next", "Qwen3NextForCausalLM"),
85
    "GlmForCausalLM": ("glm", "GlmForCausalLM"),
Yuxuan Zhang's avatar
Yuxuan Zhang committed
86
    "Glm4ForCausalLM": ("glm4", "Glm4ForCausalLM"),
Yuxuan Zhang's avatar
Yuxuan Zhang committed
87
    "Glm4MoeForCausalLM": ("glm4_moe", "Glm4MoeForCausalLM"),
88
    "GptOssForCausalLM": ("gpt_oss", "GptOssForCausalLM"),
89
90
91
92
93
94
    "GPT2LMHeadModel": ("gpt2", "GPT2LMHeadModel"),
    "GPTBigCodeForCausalLM": ("gpt_bigcode", "GPTBigCodeForCausalLM"),
    "GPTJForCausalLM": ("gpt_j", "GPTJForCausalLM"),
    "GPTNeoXForCausalLM": ("gpt_neox", "GPTNeoXForCausalLM"),
    "GraniteForCausalLM": ("granite", "GraniteForCausalLM"),
    "GraniteMoeForCausalLM": ("granitemoe", "GraniteMoeForCausalLM"),
95
    "GraniteMoeHybridForCausalLM": ("granitemoehybrid", "GraniteMoeHybridForCausalLM"),   # noqa: E501
96
    "GraniteMoeSharedForCausalLM": ("granitemoeshared", "GraniteMoeSharedForCausalLM"),   # noqa: E501
97
    "GritLM": ("gritlm", "GritLM"),
Michael Goin's avatar
Michael Goin committed
98
    "Grok1ModelForCausalLM": ("grok1", "Grok1ForCausalLM"),
99
100
    "HunYuanMoEV1ForCausalLM": ("hunyuan_v1", "HunYuanMoEV1ForCausalLM"),
    "HunYuanDenseV1ForCausalLM": ("hunyuan_v1", "HunYuanDenseV1ForCausalLM"),
101
    "HCXVisionForCausalLM": ("hyperclovax_vision", "HCXVisionForCausalLM"),
102
103
    "InternLMForCausalLM": ("llama", "LlamaForCausalLM"),
    "InternLM2ForCausalLM": ("internlm2", "InternLM2ForCausalLM"),
104
    "InternLM2VEForCausalLM": ("internlm2_ve", "InternLM2VEForCausalLM"),
105
    "InternLM3ForCausalLM": ("llama", "LlamaForCausalLM"),
106
107
    "JAISLMHeadModel": ("jais", "JAISLMHeadModel"),
    "JambaForCausalLM": ("jamba", "JambaForCausalLM"),
108
    "Lfm2ForCausalLM": ("lfm2", "Lfm2ForCausalLM"),
109
    "LlamaForCausalLM": ("llama", "LlamaForCausalLM"),
110
    "Llama4ForCausalLM": ("llama4", "Llama4ForCausalLM"),  # noqa: E501
111
112
    # For decapoda-research/llama-*
    "LLaMAForCausalLM": ("llama", "LlamaForCausalLM"),
XuruiYang's avatar
XuruiYang committed
113
    "LongcatFlashForCausalLM": ("longcat_flash", "LongcatFlashForCausalLM"),
114
    "MambaForCausalLM": ("mamba", "MambaForCausalLM"),
115
    "FalconMambaForCausalLM": ("mamba", "MambaForCausalLM"),
Dhia Eddine Rhaiem's avatar
Dhia Eddine Rhaiem committed
116
    "FalconH1ForCausalLM":("falcon_h1", "FalconH1ForCausalLM"),
117
    "Mamba2ForCausalLM": ("mamba2", "Mamba2ForCausalLM"),
118
119
    "MiniCPMForCausalLM": ("minicpm", "MiniCPMForCausalLM"),
    "MiniCPM3ForCausalLM": ("minicpm3", "MiniCPM3ForCausalLM"),
120
121
122
123
124
    "MistralForCausalLM": ("llama", "LlamaForCausalLM"),
    "MixtralForCausalLM": ("mixtral", "MixtralForCausalLM"),
    # transformers's mpt class has lower case
    "MptForCausalLM": ("mpt", "MPTForCausalLM"),
    "MPTForCausalLM": ("mpt", "MPTForCausalLM"),
125
    "MiMoForCausalLM": ("mimo", "MiMoForCausalLM"),
126
    "NemotronForCausalLM": ("nemotron", "NemotronForCausalLM"),
Luis Vega's avatar
Luis Vega committed
127
    "NemotronHForCausalLM": ("nemotron_h", "NemotronHForCausalLM"),
128
    "OlmoForCausalLM": ("olmo", "OlmoForCausalLM"),
129
    "Olmo2ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
130
    "Olmo3ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
131
132
133
134
135
136
137
    "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
138
    "Plamo2ForCausalLM": ("plamo2", "Plamo2ForCausalLM"),
139
    "QWenLMHeadModel": ("qwen", "QWenLMHeadModel"),
140
141
    "Qwen2ForCausalLM": ("qwen2", "Qwen2ForCausalLM"),
    "Qwen2MoeForCausalLM": ("qwen2_moe", "Qwen2MoeForCausalLM"),
142
143
    "Qwen3ForCausalLM": ("qwen3", "Qwen3ForCausalLM"),
    "Qwen3MoeForCausalLM": ("qwen3_moe", "Qwen3MoeForCausalLM"),
144
    "RWForCausalLM": ("falcon", "FalconForCausalLM"),
145
    "SeedOssForCausalLM": ("seed_oss", "SeedOssForCausalLM"),
Song's avatar
Song committed
146
    "Step3TextForCausalLM": ("step3_text", "Step3TextForCausalLM"),
147
148
149
150
    "StableLMEpochForCausalLM": ("stablelm", "StablelmForCausalLM"),
    "StableLmForCausalLM": ("stablelm", "StablelmForCausalLM"),
    "Starcoder2ForCausalLM": ("starcoder2", "Starcoder2ForCausalLM"),
    "SolarForCausalLM": ("solar", "SolarForCausalLM"),
151
    "TeleChat2ForCausalLM": ("telechat2", "TeleChat2ForCausalLM"),
152
    "TeleFLMForCausalLM": ("teleflm", "TeleFLMForCausalLM"),
153
    "XverseForCausalLM": ("llama", "LlamaForCausalLM"),
154
    "Zamba2ForCausalLM": ("zamba2", "Zamba2ForCausalLM"),
155
156
157
}

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

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

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

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

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

_TRANSFORMERS_BACKEND_MODELS = {
309
    "TransformersModel": ("transformers", "TransformersModel"),
310
    "TransformersForCausalLM": ("transformers", "TransformersForCausalLM"),
311
    "TransformersForMultimodalLM": ("transformers", "TransformersForMultimodalLM"), # noqa: E501
312
}
313
# yapf: enable
314

315
_VLLM_MODELS = {
316
    **_TEXT_GENERATION_MODELS,
317
    **_EMBEDDING_MODELS,
318
    **_CROSS_ENCODER_MODELS,
319
    **_MULTIMODAL_MODELS,
320
    **_SPECULATIVE_DECODING_MODELS,
321
322
    **_TRANSFORMERS_SUPPORTED_MODELS,
    **_TRANSFORMERS_BACKEND_MODELS,
323
324
}

325
326
327
328
329
330
331
332
# 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"
]

333
_PREVIOUSLY_SUPPORTED_MODELS = {
334
    "MotifForCausalLM": "0.10.2",
335
    "Phi3SmallForCausalLM": "0.9.2",
336
    "Phi4FlashForCausalLM": "0.10.2",
337
338
339
340
341
342
343
344
345
    # 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",
}
346

347

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

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


392
class _BaseRegisteredModel(ABC):
393

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

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


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

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

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

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

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

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

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

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

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

        return mi
520

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


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


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

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

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

570
        `model_cls` can be either:
571

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

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

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

602
        self.models[model_arch] = model
603

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

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

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

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

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

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

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

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

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

700
        return model_config._get_transformers_backend_cls()
701

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

            # 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

        return architecture
727

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

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

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

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

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

777
        return self._raise_for_unsupported(architectures)
778

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

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

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

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

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

830
        return self._raise_for_unsupported(architectures)
831

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

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

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

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

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

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

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

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

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

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

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

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

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

936
937

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

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

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

        # 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

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

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


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