diff --git a/vllm/model_executor/models/deepencoder2.py b/vllm/model_executor/models/deepencoder2.py index fdec155d53..9e251c39b2 100644 --- a/vllm/model_executor/models/deepencoder2.py +++ b/vllm/model_executor/models/deepencoder2.py @@ -10,6 +10,8 @@ # This source code is licensed under the license found in the # LICENSE file in the root directory of this source tree. +from functools import lru_cache + import torch import torch.nn as nn import transformers @@ -90,8 +92,6 @@ class CustomQwen2Decoder(PluggableLayer): return_dict=None, cache_position=None, ): - # token_type_ids - self._current_token_type_ids = token_type_ids causal_mask_mapping = { "full_attention": self._update_causal_mask( attention_mask, @@ -131,15 +131,12 @@ class CustomQwen2Decoder(PluggableLayer): input_tensor.shape[1], ) - token_type_ids = self._current_token_type_ids - # attention mask causal_mask = self._create_custom_4d_mask( sequence_length=sequence_length, dtype=dtype, device=device, batch_size=batch_size, - token_type_ids=token_type_ids, ) # padding mask @@ -150,44 +147,43 @@ class CustomQwen2Decoder(PluggableLayer): return causal_mask + @classmethod + @lru_cache(maxsize=8) + def compute_mask_base(cls, sequence_length, dtype, device): + # token_type_ids is the fixed pattern [0]*n_query + [1]*n_query, + # identical across the batch, so the mask depends only on + # sequence_length: img tokens (first half) attend to + # everything, txt tokens (second half) attend causally among + # themselves. lru_cache keeps one batch-invariant [1, 1, S, S] + # mask per (S, dtype, device). + min_dtype = torch.finfo(dtype).min + n_query = sequence_length // 2 + img = torch.arange(sequence_length, device=device) < n_query + txt = ~img + causal = torch.tril( + torch.ones( + sequence_length, + sequence_length, + dtype=torch.bool, + device=device, + ) + ) + allow = img[None, :] | (txt[:, None] & txt[None, :] & causal) + return torch.where( + allow, + torch.zeros((), dtype=dtype, device=device), + torch.full((), min_dtype, dtype=dtype, device=device), + )[None, None] + def _create_custom_4d_mask( self, sequence_length, dtype, device, batch_size, - token_type_ids, ): - min_dtype = torch.finfo(dtype).min - - masks = [] - for b in range(batch_size): - mask = torch.full( - (sequence_length, sequence_length), - fill_value=min_dtype, - dtype=dtype, - device=device, - ) - - type_ids = token_type_ids[b] - - image_positions = (type_ids == 0).nonzero(as_tuple=True)[0] - text_positions = (type_ids == 1).nonzero(as_tuple=True)[0] - - # non-casual - if len(image_positions) > 0: - mask[image_positions[:, None], image_positions] = 0.0 - - # causal - for i, text_pos in enumerate(text_positions): - if len(image_positions) > 0: - mask[text_pos, image_positions] = 0.0 - mask[text_pos, text_positions[: i + 1]] = 0.0 - - masks.append(mask) - - mask = torch.stack(masks, dim=0).unsqueeze(1) - return mask + base = self.compute_mask_base(sequence_length, dtype, device) + return base.expand(batch_size, -1, -1, -1) return CustomQwen2ModelInner(config)