main
py 549 lines 18.6 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """This is basically a copy from perception_models/core/vision_encoder/pe.py."""
4
5 from collections.abc import Callable
6 from functools import partial
7
8 import torch
9 from einops import rearrange, repeat
10 from torch import nn
11 from torch.nn import functional as F
12
13 from vllm.config import VllmConfig
14 from vllm.distributed import get_tensor_model_parallel_world_size
15 from vllm.model_executor.layers.activation import get_act_fn
16 from vllm.model_executor.layers.attention.mm_encoder_attention import MMEncoderAttention
17 from vllm.model_executor.layers.conv import Conv2dLayer
18 from vllm.model_executor.layers.linear import (
19 ColumnParallelLinear,
20 QKVParallelLinear,
21 RowParallelLinear,
22 )
23 from vllm.model_executor.layers.quantization import QuantizationConfig
24
25 from .interfaces import supports_pp
26 from .step3_vl import Step3VLForConditionalGeneration
27 from .utils import WeightsMapper, init_vllm_registered_model, maybe_prefix
28 from .vision import is_vit_use_data_parallel, run_dp_sharded_vision_model
29
30 _DEFAULT_NORM_LAYER = partial(nn.LayerNorm, eps=1e-5)
31
32
33 def rotate_half(x):
34 x = rearrange(x, "... (d r) -> ... d r", r=2)
35 x1, x2 = x.unbind(dim=-1)
36 x = torch.stack((-x2, x1), dim=-1)
37 return rearrange(x, "... d r -> ... (d r)")
38
39
40 def apply_rotary_emb(freqs, t, start_index=0, scale=1.0, seq_dim=-2):
41 dtype = t.dtype
42
43 if t.ndim == 3:
44 seq_len = t.shape[seq_dim]
45 freqs = freqs[-seq_len:]
46
47 rot_dim = freqs.shape[-1]
48 end_index = start_index + rot_dim
49
50 assert rot_dim <= t.shape[-1], (
51 "feature dimension {} is not of sufficient size to rotate in all the "
52 "positions {}".format(t.shape[-1], rot_dim)
53 )
54
55 t_left, t, t_right = (
56 t[..., :start_index],
57 t[..., start_index:end_index],
58 t[..., end_index:],
59 )
60 t = (t * freqs.cos() * scale) + (rotate_half(t) * freqs.sin() * scale)
61 out = torch.cat((t_left, t, t_right), dim=-1)
62
63 return out.type(dtype)
64
65
66 class PerceptionEncoderRope2D(nn.Module):
67 def __init__(
68 self,
69 dim: int,
70 max_grid_height: int,
71 max_grid_width: int,
72 use_cls_token: bool = False,
73 theta=10000,
74 max_freq=10,
75 num_freqs=1,
76 theta_rescale_factor=1.0,
77 ):
78 super().__init__()
79 self.dim = dim
80 self.max_grid_height = max_grid_height
81 self.max_grid_width = max_grid_width
82 self.use_cls_token = use_cls_token
83 self.theta = theta * theta_rescale_factor ** (dim / (dim - 2))
84 self.max_freq = max_freq
85 self.num_freqs = num_freqs
86 cache = self._compute_2d_freqs()
87 self.register_buffer("freqs_cache", cache, persistent=False)
88
89 def _compute_inv_freq(self, base: int | float, dim: int) -> torch.Tensor:
90 freqs = 1.0 / (base ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
91 return freqs
92
93 def _compute_freqs(self, t: torch.Tensor, inv_freq: torch.Tensor):
94 freqs = torch.einsum("..., f -> ... f", t.type(inv_freq.dtype), inv_freq)
95 freqs = repeat(freqs, "... n -> ... (n r)", r=2)
96 return freqs
97
98 def _compute_2d_freqs(self) -> torch.Tensor:
99 grid_h_range = torch.arange(self.max_grid_height, dtype=torch.float)
100 grid_w_range = torch.arange(self.max_grid_width, dtype=torch.float)
101 if self.use_cls_token:
102 grid_h_range += 1
103 grid_w_range += 1
104 inv_freq = self._compute_inv_freq(self.theta, self.dim // 2)
105 freqs_h = self._compute_freqs(grid_h_range, inv_freq)[:, None].expand(
106 self.max_grid_height, self.max_grid_width, -1
107 )
108 freqs_w = self._compute_freqs(grid_w_range, inv_freq)[None, :].expand(
109 self.max_grid_height, self.max_grid_width, -1
110 )
111 freqs = torch.cat([freqs_w, freqs_h], dim=-1).reshape(
112 self.max_grid_height * self.max_grid_width, -1
113 )
114 if self.use_cls_token:
115 freqs = torch.cat([torch.zeros(1, freqs.shape[-1]), freqs], dim=0)
116 freqs = freqs[None, None, ...]
117 return freqs
118
119 def forward(self, q: torch.Tensor, k: torch.Tensor, grid_hw: tuple[int, int]):
120 if grid_hw[0] != self.max_grid_height or grid_hw[1] != self.max_grid_width:
121 rows = torch.arange(grid_hw[0], device=q.device).view(-1, 1)
122 cols = torch.arange(grid_hw[1], device=q.device).view(1, -1)
123 positions = (rows * self.max_grid_width + cols).reshape(-1).to(torch.long)
124 if self.use_cls_token:
125 positions = torch.cat(
126 [torch.zeros(1, device=q.device), positions + 1], dim=0
127 )
128 positions = positions.to(torch.long)
129 freqs = self.freqs_cache.index_select(2, positions)
130 else:
131 freqs = self.freqs_cache
132 q = apply_rotary_emb(freqs, q)
133 k = apply_rotary_emb(freqs, k)
134 return q, k
135
136
137 class PerceptionEncoderLayerScale(nn.Module):
138 def __init__(self, dim, init_values=1e-5, inplace=False):
139 super().__init__()
140 self.inplace = inplace
141 self.gamma = nn.Parameter(init_values * torch.ones(dim))
142
143 def forward(self, x):
144 return x.mul_(self.gamma) if self.inplace else x * self.gamma
145
146
147 class PerceptionEncoderMLP(nn.Module):
148 def __init__(
149 self,
150 input_dim: int,
151 hidden_dim: int,
152 act_layer: Callable[[torch.Tensor], torch.Tensor],
153 quant_config: QuantizationConfig | None = None,
154 prefix: str = "",
155 ):
156 super().__init__()
157 use_data_parallel = is_vit_use_data_parallel()
158 self.fc1 = ColumnParallelLinear(
159 input_dim,
160 hidden_dim,
161 bias=True,
162 quant_config=quant_config,
163 prefix=f"{prefix}.fc1",
164 disable_tp=use_data_parallel,
165 )
166 self.activation = act_layer
167 self.fc2 = RowParallelLinear(
168 hidden_dim,
169 input_dim,
170 bias=True,
171 quant_config=quant_config,
172 prefix=f"{prefix}.fc2",
173 disable_tp=use_data_parallel,
174 )
175
176 def forward(self, x: torch.Tensor) -> torch.Tensor:
177 x, _ = self.fc1(x)
178 x = self.activation(x)
179 x, _ = self.fc2(x)
180 return x
181
182
183 class PerceptionEncoderVisionAttention(nn.Module):
184 def __init__(
185 self,
186 embed_dim: int,
187 num_heads: int,
188 max_grid_height: int,
189 max_grid_width: int,
190 use_cls_token: bool = False,
191 quant_config: QuantizationConfig | None = None,
192 prefix: str = "",
193 ):
194 super().__init__()
195 self.embed_dim = embed_dim
196 self.total_num_heads = num_heads
197 self.head_dim = embed_dim // num_heads
198 self.scale = self.head_dim**-0.5
199
200 use_data_parallel = is_vit_use_data_parallel()
201 tp_size = 1 if use_data_parallel else get_tensor_model_parallel_world_size()
202 assert self.total_num_heads % tp_size == 0, (
203 "embed_dim must be divisible by num_heads"
204 )
205 self.num_heads = self.total_num_heads // tp_size
206
207 self.qkv_proj = QKVParallelLinear(
208 embed_dim,
209 self.head_dim,
210 self.total_num_heads,
211 bias=True,
212 quant_config=quant_config,
213 prefix=f"{prefix}.qkv_proj",
214 disable_tp=use_data_parallel,
215 )
216 self.out_proj = RowParallelLinear(
217 embed_dim,
218 embed_dim,
219 bias=True,
220 quant_config=quant_config,
221 prefix=f"{prefix}.out_proj",
222 disable_tp=use_data_parallel,
223 )
224 self.attn = MMEncoderAttention(
225 self.num_heads,
226 self.head_dim,
227 self.scale,
228 prefix=f"{prefix}.attn",
229 )
230 self.rope = PerceptionEncoderRope2D(
231 dim=self.head_dim,
232 max_grid_height=max_grid_height,
233 max_grid_width=max_grid_width,
234 use_cls_token=use_cls_token,
235 )
236
237 def forward(self, x: torch.Tensor, grid_hw: tuple[int, int]) -> torch.Tensor:
238 bsz, seq_len, _ = x.shape
239 qkv, _ = self.qkv_proj(x)
240 q, k, v = qkv.chunk(chunks=3, dim=-1)
241
242 q = q.view(bsz, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
243 k = k.view(bsz, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
244 q, k = self.rope(q, k, grid_hw=grid_hw)
245 q = q.permute(0, 2, 1, 3).reshape(bsz, seq_len, self.num_heads * self.head_dim)
246 k = k.permute(0, 2, 1, 3).reshape(bsz, seq_len, self.num_heads * self.head_dim)
247
248 attn_output = self.attn(q, k, v)
249 attn_output, _ = self.out_proj(attn_output)
250 return attn_output
251
252
253 class PerceptionEncoderVisionBlock(nn.Module):
254 def __init__(
255 self,
256 d_model: int,
257 n_head: int,
258 max_grid_height: int,
259 max_grid_width: int,
260 mlp_ratio: float = 4.0,
261 ls_init_value: float | None = None,
262 act_layer: Callable = nn.GELU,
263 norm_layer: Callable = nn.LayerNorm,
264 use_cls_token: bool = False,
265 quant_config: QuantizationConfig | None = None,
266 prefix: str = "",
267 ):
268 super().__init__()
269 self.attn = PerceptionEncoderVisionAttention(
270 d_model,
271 n_head,
272 max_grid_height=max_grid_height,
273 max_grid_width=max_grid_width,
274 use_cls_token=use_cls_token,
275 quant_config=quant_config,
276 prefix=f"{prefix}.attn",
277 )
278 self.ls_1 = (
279 PerceptionEncoderLayerScale(d_model, ls_init_value)
280 if ls_init_value is not None
281 else nn.Identity()
282 )
283 self.ls_2 = (
284 PerceptionEncoderLayerScale(d_model, ls_init_value)
285 if ls_init_value is not None
286 else nn.Identity()
287 )
288 self.ln_1 = norm_layer(d_model)
289 self.ln_2 = norm_layer(d_model)
290 hidden_dim = int(d_model * mlp_ratio)
291 self.mlp = PerceptionEncoderMLP(
292 d_model,
293 hidden_dim,
294 act_layer,
295 quant_config=quant_config,
296 prefix=f"{prefix}.mlp",
297 )
298
299 def forward(self, x: torch.Tensor, grid_hw: tuple[int, int]):
300 x = x + self.ls_1(self.attn(self.ln_1(x), grid_hw=grid_hw))
301 x = x + self.ls_2(self.mlp(self.ln_2(x)))
302 return x
303
304
305 class PerceptionEncoderVisionTransformer(nn.Module):
306 def __init__(
307 self,
308 width: int,
309 layers: int,
310 heads: int,
311 max_grid_height: int,
312 max_grid_width: int,
313 mlp_ratio: float = 4.0,
314 ls_init_value: float | None = None,
315 act_layer: Callable = nn.GELU,
316 norm_layer: Callable = nn.LayerNorm,
317 use_cls_token: bool = False,
318 quant_config: QuantizationConfig | None = None,
319 prefix: str = "",
320 ):
321 super().__init__()
322 self.width = width
323 self.layers = layers
324 self.resblocks = nn.ModuleList(
325 [
326 PerceptionEncoderVisionBlock(
327 d_model=width,
328 n_head=heads,
329 max_grid_height=max_grid_height,
330 max_grid_width=max_grid_width,
331 mlp_ratio=mlp_ratio,
332 ls_init_value=ls_init_value,
333 act_layer=act_layer,
334 norm_layer=norm_layer,
335 use_cls_token=use_cls_token,
336 quant_config=quant_config,
337 prefix=f"{prefix}.resblocks.{i}",
338 )
339 for i in range(layers)
340 ]
341 )
342
343 def forward(self, x: torch.Tensor, grid_hw: tuple[int, int]):
344 for block in self.resblocks:
345 x = block(x, grid_hw=grid_hw)
346 return x
347
348
349 class PerceptionEncoder(nn.Module):
350 def __init__(
351 self,
352 config,
353 act_layer: Callable,
354 norm_layer: Callable = _DEFAULT_NORM_LAYER,
355 quant_config: QuantizationConfig | None = None,
356 prefix: str = "",
357 ):
358 super().__init__()
359 self.patch_size = config.patch_size
360
361 self.output_dim = config.output_dim or config.width
362 self.heads = config.heads
363 self.width = config.width
364 self.layers = config.layers
365
366 self.use_abs_posemb = config.use_abs_posemb
367 self.use_cls_token = config.use_cls_token
368 self.use_rope2d = config.use_rope2d
369 if not self.use_rope2d:
370 raise ValueError("use_rope2d must be True")
371 self.image_size = config.image_size
372
373 self.conv1 = Conv2dLayer(
374 in_channels=3,
375 out_channels=config.width,
376 kernel_size=config.patch_size,
377 stride=config.patch_size,
378 bias=False,
379 )
380
381 self.ln_pre = norm_layer(config.width) if config.use_ln_pre else nn.Identity()
382 self.ln_post = norm_layer(self.width) if config.use_ln_post else nn.Identity()
383
384 self.transformer = PerceptionEncoderVisionTransformer(
385 config.width,
386 config.layers,
387 config.heads,
388 max_grid_height=self.image_size // self.patch_size,
389 max_grid_width=self.image_size // self.patch_size,
390 mlp_ratio=config.mlp_ratio,
391 ls_init_value=config.ls_init_value,
392 act_layer=act_layer,
393 norm_layer=norm_layer,
394 use_cls_token=self.use_cls_token,
395 quant_config=quant_config,
396 prefix=f"{prefix}.transformer",
397 )
398
399 self.vit_downsampler1 = Conv2dLayer(
400 config.width, config.width * 2, kernel_size=3, stride=2, padding=1
401 )
402 self.vit_downsampler2 = Conv2dLayer(
403 config.width * 2, config.width * 4, kernel_size=3, stride=2, padding=1
404 )
405
406 if self.use_cls_token:
407 self.class_embedding = nn.Parameter(
408 (self.width**-0.5) * torch.randn(self.width)
409 )
410
411 if self.use_abs_posemb:
412 self.posemb_grid_size = self.image_size // self.patch_size
413 self.positional_embedding = nn.Parameter(
414 (self.width**-0.5)
415 * torch.randn(
416 int(self.use_cls_token) + self.posemb_grid_size**2,
417 self.width,
418 )
419 )
420
421 def sample_abs_posemb(self, grid_h: int, grid_w: int):
422 if self.posemb_grid_size == grid_h and self.posemb_grid_size == grid_w:
423 return self.positional_embedding[None, ...]
424
425 pos_embed = self.positional_embedding
426 if self.use_cls_token:
427 cls_token_embed, pos_embed = pos_embed[:1], pos_embed[1:]
428
429 pos_embed = (
430 pos_embed.reshape(1, self.posemb_grid_size, self.posemb_grid_size, -1)
431 .permute(0, 3, 1, 2)
432 .contiguous()
433 )
434 pos_embed = F.interpolate(
435 pos_embed, size=(grid_h, grid_w), mode="bilinear", align_corners=False
436 )
437 pos_embed = pos_embed.permute(0, 2, 3, 1).reshape(-1, self.width)
438
439 if self.use_cls_token:
440 pos_embed = torch.cat([cls_token_embed, pos_embed], dim=0)
441
442 return pos_embed[None, ...]
443
444 def forward_features(self, x: torch.Tensor):
445 batch, _, h, w = x.shape
446 grid_h, grid_w = h // self.patch_size, w // self.patch_size
447
448 x = self.conv1(x)
449 x = x.permute(0, 2, 3, 1).reshape(batch, -1, self.width)
450
451 if self.use_cls_token:
452 x = torch.cat(
453 [self.class_embedding.view(1, 1, -1).expand(batch, -1, -1), x], dim=1
454 )
455
456 if self.use_abs_posemb:
457 x = x + self.sample_abs_posemb(grid_h, grid_w)
458
459 x = self.ln_pre(x)
460 x = self.transformer(x, grid_hw=(grid_h, grid_w))
461 x = self.ln_post(x)
462
463 if self.use_cls_token:
464 x = x[:, 1:, :]
465
466 return x
467
468 def forward(self, x: torch.Tensor):
469 x = self.forward_features(x)
470 B, P, C = x.shape
471 T = int(P**0.5)
472 x = x.transpose(2, 1).contiguous()
473 x = x.view(B, C, T, T)
474
475 x = self.vit_downsampler1(x)
476 x = self.vit_downsampler2(x)
477
478 B, C, T, T = x.shape
479 return x.view(B, -1, T * T).transpose(1, 2)
480
481
482 class StepVLForConditionalGeneration(Step3VLForConditionalGeneration):
483 hf_to_vllm_mapper = WeightsMapper(
484 orig_to_new_prefix={
485 "model.": "language_model.model.",
486 "lm_head.": "language_model.lm_head.",
487 },
488 orig_to_new_substr={
489 ".attn.in_proj_weight": ".attn.qkv_proj.weight",
490 ".attn.in_proj_bias": ".attn.qkv_proj.bias",
491 ".mlp.c_fc": ".mlp.fc1",
492 ".mlp.c_proj": ".mlp.fc2",
493 },
494 )
495
496 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
497 super(Step3VLForConditionalGeneration, self).__init__()
498
499 config = vllm_config.model_config.hf_config
500 multimodal_config = vllm_config.model_config.get_multimodal_config()
501 quant_config = vllm_config.quant_config
502
503 self.config = config
504 self.model_config = vllm_config.model_config
505 self.multimodal_config = multimodal_config
506 self.use_data_parallel = multimodal_config.mm_encoder_tp_mode == "data"
507
508 with self._mark_tower_model(vllm_config, "image"):
509 self.vision_model = PerceptionEncoder(
510 config.vision_config,
511 get_act_fn(config.vision_config.hidden_act),
512 quant_config=quant_config,
513 prefix=maybe_prefix(prefix, "vision_model"),
514 )
515 self.vit_large_projector = ColumnParallelLinear(
516 config.vision_config.width * 4,
517 config.text_config.hidden_size,
518 bias=config.projector_bias,
519 gather_output=True,
520 quant_config=quant_config,
521 prefix=maybe_prefix(prefix, "vit_large_projector"),
522 disable_tp=self.use_data_parallel,
523 )
524
525 with self._mark_language_model(vllm_config):
526 language_model = init_vllm_registered_model(
527 vllm_config=vllm_config,
528 hf_config=config.text_config,
529 prefix=maybe_prefix(prefix, "language_model"),
530 )
531 self.language_model = language_model
532 assert supports_pp(language_model)
533
534 self.make_empty_intermediate_tensors = (
535 language_model.make_empty_intermediate_tensors
536 )
537
538 def _get_vision_model_output(
539 self, input_tensor: torch.Tensor | None
540 ) -> torch.Tensor | None:
541 if input_tensor is None:
542 return None
543 if self.use_data_parallel:
544 return run_dp_sharded_vision_model(input_tensor, self.vision_model)
545 return self.vision_model(input_tensor)
546
547 def _process_image_features(self, image_features: torch.Tensor) -> torch.Tensor:
548 image_features, _ = self.vit_large_projector(image_features)
549 return image_features