main
py 283 lines 9.3 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # adapted from
5 # https://github.com/deepseek-ai/DeepSeek-OCR-2/blob/main/DeepSeek-OCR2-master/DeepSeek-OCR2-vllm/deepencoderv2/qwen2_d2e.py
6
7 # Copyright (c) Meta Platforms, Inc. and affiliates.
8 # All rights reserved.
9
10 # This source code is licensed under the license found in the
11 # LICENSE file in the root directory of this source tree.
12
13 from functools import lru_cache
14
15 import torch
16 import torch.nn as nn
17 import transformers
18 from transformers.models.qwen2.modeling_qwen2 import Qwen2Model
19
20 from vllm.model_executor.custom_op import PluggableLayer
21
22
23 # --8<-- [start:qwen2_decoder]
24 @PluggableLayer.register("qwen2_decoder")
25 class CustomQwen2Decoder(PluggableLayer):
26 """Qwen2 visual encoder
27 non-causal attention + causal attention
28 token_type_ids :0=non-causal, 1=causal
29 """
30
31 # --8<-- [end:qwen2_decoder]
32
33 def __init__(
34 self,
35 decoder_layer: int = 24,
36 max_position_embeddings: int = 131072,
37 hidden_dimension: int = 896,
38 num_attention_heads: int = 14,
39 num_key_value_heads: int = 2,
40 intermediate_size: int = 4864,
41 vocab_size: int = 151936,
42 attn_implementation: str = "sdpa",
43 rms_norm_eps: float = 1e-06,
44 rope_theta: float = 1000000.0,
45 attention_dropout: float = 0.0,
46 hidden_act: str = "silu",
47 initializer_range: float = 0.02,
48 ):
49 super().__init__()
50
51 # load
52 Qwen2Config = transformers.Qwen2Config
53
54 # config
55 config = Qwen2Config(
56 hidden_size=hidden_dimension,
57 num_hidden_layers=decoder_layer,
58 num_attention_heads=num_attention_heads,
59 num_key_value_heads=num_key_value_heads,
60 intermediate_size=intermediate_size,
61 max_position_embeddings=max_position_embeddings,
62 vocab_size=vocab_size,
63 rms_norm_eps=rms_norm_eps,
64 rope_theta=rope_theta,
65 attention_dropout=attention_dropout,
66 hidden_act=hidden_act,
67 initializer_range=initializer_range,
68 _attn_implementation=attn_implementation, # ⭐
69 )
70
71 #
72 self.model = self._create_custom_model(config)
73
74 del self.model.embed_tokens
75
76 def _create_custom_model(self, config):
77 """Qwen2Model."""
78
79 class CustomQwen2ModelInner(Qwen2Model):
80 def forward(
81 self,
82 input_ids=None,
83 attention_mask=None,
84 position_ids=None,
85 past_key_values=None,
86 inputs_embeds=None,
87 token_type_ids=None, # ⭐
88 use_cache=None,
89 output_attentions=None,
90 output_hidden_states=None,
91 return_dict=None,
92 cache_position=None,
93 ):
94 causal_mask_mapping = {
95 "full_attention": self._update_causal_mask(
96 attention_mask,
97 inputs_embeds,
98 cache_position,
99 past_key_values,
100 output_attentions,
101 )
102 }
103 outputs = super().forward(
104 input_ids=input_ids,
105 attention_mask=causal_mask_mapping,
106 position_ids=position_ids,
107 past_key_values=past_key_values,
108 inputs_embeds=inputs_embeds,
109 use_cache=use_cache,
110 output_attentions=output_attentions,
111 output_hidden_states=output_hidden_states,
112 return_dict=return_dict,
113 cache_position=cache_position,
114 )
115
116 return outputs
117
118 def _update_causal_mask(
119 self,
120 attention_mask,
121 input_tensor,
122 cache_position,
123 past_key_values,
124 output_attentions,
125 ):
126 dtype, device = input_tensor.dtype, input_tensor.device
127 min_dtype = torch.finfo(dtype).min
128 batch_size, sequence_length = (
129 input_tensor.shape[0],
130 input_tensor.shape[1],
131 )
132
133 # attention mask
134 causal_mask = self._create_custom_4d_mask(
135 sequence_length=sequence_length,
136 dtype=dtype,
137 device=device,
138 batch_size=batch_size,
139 )
140
141 # padding mask
142 if attention_mask is not None and attention_mask.dim() == 2:
143 padding_mask = attention_mask[:, None, None, :].to(dtype=dtype)
144 padding_mask = (1.0 - padding_mask) * min_dtype
145 causal_mask = causal_mask + padding_mask
146
147 return causal_mask
148
149 @classmethod
150 @lru_cache(maxsize=8)
151 def compute_mask_base(cls, sequence_length, dtype, device):
152 # token_type_ids is the fixed pattern [0]*n_query + [1]*n_query,
153 # identical across the batch, so the mask depends only on
154 # sequence_length: img tokens (first half) attend to
155 # everything, txt tokens (second half) attend causally among
156 # themselves. lru_cache keeps one batch-invariant [1, 1, S, S]
157 # mask per (S, dtype, device).
158 min_dtype = torch.finfo(dtype).min
159 n_query = sequence_length // 2
160 img = torch.arange(sequence_length, device=device) < n_query
161 txt = ~img
162 causal = torch.tril(
163 torch.ones(
164 sequence_length,
165 sequence_length,
166 dtype=torch.bool,
167 device=device,
168 )
169 )
170 allow = img[None, :] | (txt[:, None] & txt[None, :] & causal)
171 return torch.where(
172 allow,
173 torch.zeros((), dtype=dtype, device=device),
174 torch.full((), min_dtype, dtype=dtype, device=device),
175 )[None, None]
176
177 def _create_custom_4d_mask(
178 self,
179 sequence_length,
180 dtype,
181 device,
182 batch_size,
183 ):
184 base = self.compute_mask_base(sequence_length, dtype, device)
185 return base.expand(batch_size, -1, -1, -1)
186
187 return CustomQwen2ModelInner(config)
188
189 def forward(
190 self,
191 inputs_embeds: torch.Tensor,
192 token_type_ids: torch.Tensor,
193 attention_mask: torch.Tensor = None,
194 **kwargs,
195 ):
196 """Args:
197 inputs_embeds: [batch_size, seq_len, hidden_dim]
198 token_type_ids: [batch_size, seq_len], 0=non-causal, 1=causal
199 attention_mask: [batch_size, seq_len], optional
200
201 """
202 return self.model(
203 inputs_embeds=inputs_embeds,
204 token_type_ids=token_type_ids,
205 attention_mask=attention_mask,
206 **kwargs,
207 )
208
209
210 class Qwen2Decoder2Encoder(nn.Module):
211 """Decoder based on Multilingual BART
212 Set the initial weights and configuration with a pretrained multilingual BART model,
213 and modify the detailed configurations as a Nougat decoder
214 """
215
216 def __init__(
217 self,
218 decoder_layer: int,
219 hidden_dimension: int,
220 num_attention_heads: int,
221 num_key_value_heads: int,
222 intermediate_size: int,
223 ):
224 super().__init__()
225
226 self.model = CustomQwen2Decoder(
227 decoder_layer=decoder_layer,
228 hidden_dimension=hidden_dimension,
229 num_attention_heads=num_attention_heads,
230 num_key_value_heads=num_key_value_heads,
231 intermediate_size=intermediate_size,
232 attn_implementation="sdpa",
233 )
234 self.query_768 = nn.Embedding(144, hidden_dimension)
235 self.query_1024 = nn.Embedding(256, hidden_dimension)
236
237 def forward(self, x: torch.Tensor) -> torch.Tensor:
238 x = x.flatten(2).transpose(1, 2)
239
240 bs, n_query, _ = x.shape
241
242 if n_query == 144:
243 param_img = self.query_768.weight
244 elif n_query == 256:
245 param_img = self.query_1024.weight
246
247 batch_query_imgs = param_img.unsqueeze(0).expand(
248 bs, -1, -1
249 ) # (batch_size, num_queries, hidden_size)
250
251 x_combined = torch.cat([x, batch_query_imgs], dim=1)
252
253 token_type_ids = torch.cat(
254 [
255 torch.zeros(bs, n_query, dtype=torch.long),
256 torch.ones(bs, n_query, dtype=torch.long),
257 ],
258 dim=1,
259 )
260
261 y = self.model(x_combined, token_type_ids)[0]
262
263 y = y[:, n_query:, :] # causal flow query
264
265 return y
266
267
268 def build_qwen2_decoder_as_encoder(
269 decoder_layer=24,
270 hidden_dimension=896,
271 num_attention_heads=14,
272 num_key_value_heads=2,
273 intermediate_size=4864,
274 ):
275 decoder_as_encoder = Qwen2Decoder2Encoder(
276 decoder_layer=decoder_layer,
277 hidden_dimension=hidden_dimension,
278 num_attention_heads=num_attention_heads,
279 num_key_value_heads=num_key_value_heads,
280 intermediate_size=intermediate_size,
281 )
282
283 return decoder_as_encoder