Skip to content

Commit 5572c8f

Browse files
committed
[video-comprehension] Fix failing example.
This commit fixes errors in video-comprehension example involving VideLLava and CLIP models and caused by latest transformers upgrade. * Adapt modeling_video_llava to the transformers upgrade by adding GaudiVideoLlavaModel.forward * Fix mismatched matrix sizes in CLIP attention. * Fix access to non-existing attribute in GaudiGenerationMixin. Signed-off-by: Urszula <urszula.golowicz@intel.com>
1 parent f5ed4bf commit 5572c8f

6 files changed

Lines changed: 114 additions & 72 deletions

File tree

optimum/habana/transformers/generation/utils.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,7 @@ def _prepare_inputs_for_generation(
236236
# 1. Handle BC:
237237
model_inputs = {}
238238
# - some models don't have `Cache` support (which implies they don't expect `cache_position` in `forward`)
239-
if self._supports_cache_class:
240-
model_inputs["cache_position"] = cache_position
241-
# - `cache_position` was not a mandatory input in `prepare_inputs_for_generation` for those models, and this
242-
# function may be called outside of `generate`. Handle most use cases by creating `cache_position` on the fly
243-
# (this alternative is not as robust as calling `generate` and letting it create `cache_position`)
244-
elif cache_position is None:
245-
past_length = past_key_values[0][0].shape[2] if past_key_values is not None else 0
246-
cache_position = torch.arange(past_length, input_ids.shape[1], dtype=torch.long, device=input_ids.device)
239+
model_inputs["cache_position"] = cache_position
247240

248241
# 2. Generic cache-dependent input preparation
249242
if past_key_values is not None:

optimum/habana/transformers/modeling_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@
211211
GaudiStarcoder2Model,
212212
GaudiT5ForConditionalGeneration,
213213
GaudiVideoLlavaForConditionalGeneration,
214+
GaudiVideoLlavaModel,
214215
GaudiVisionSdpaAttention,
215216
GaudiWhisperDecoder,
216217
GaudiWhisperDecoderLayer,
@@ -826,6 +827,7 @@ def adapt_transformers_to_gaudi():
826827
transformers.models.video_llava.modeling_video_llava.VideoLlavaForConditionalGeneration = (
827828
GaudiVideoLlavaForConditionalGeneration
828829
)
830+
transformers.models.video_llava.modeling_video_llava.VideoLlavaModel = GaudiVideoLlavaModel
829831

830832
# Optimization for Whisper on Gaudi
831833
transformers.models.whisper.modeling_whisper.WhisperAttention = GaudiWhisperSdpaAttention

optimum/habana/transformers/models/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@
373373
gaudi_T5Stack_forward,
374374
)
375375
from .table_transformer import gaudi_table_transformer_conv_encoder_forward
376-
from .video_llava import GaudiVideoLlavaForConditionalGeneration
376+
from .video_llava import GaudiVideoLlavaForConditionalGeneration, GaudiVideoLlavaModel
377377
from .vision_encoder_decoder import (
378378
gaudi_VisionEncoderDecoderModel_prepare_inputs_for_generation,
379379
)

optimum/habana/transformers/models/clip/modeling_clip.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,15 @@ def forward(
9595
keys = self.k_proj(hidden_states)
9696
values = self.v_proj(hidden_states)
9797

98-
queries = queries.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2)
99-
keys = keys.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2)
100-
values = values.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2)
98+
queries = queries.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2).contiguous()
99+
keys = keys.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2).contiguous()
100+
values = values.view(batch_size, seq_length, -1, self.head_dim).transpose(1, 2).contiguous()
101+
102+
proj_shape = (batch_size * self.num_heads, -1, self.head_dim)
103+
queries = queries.view(*proj_shape)
104+
keys = keys.view(*proj_shape)
105+
values = values.view(*proj_shape)
106+
101107
# CLIP text model uses both `causal_attention_mask` and `attention_mask`
102108
# in case FA2 kernel is called, `is_causal` should be inferred from `causal_attention_mask`
103109
if self.config._attn_implementation == "flash_attention_2":
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .modeling_video_llava import GaudiVideoLlavaForConditionalGeneration
1+
from .modeling_video_llava import GaudiVideoLlavaForConditionalGeneration, GaudiVideoLlavaModel

optimum/habana/transformers/models/video_llava/modeling_video_llava.py

Lines changed: 100 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,46 @@
1717
from typing import Optional, Union
1818

1919
import torch
20-
from torch import nn
20+
from transformers.cache_utils import Cache
21+
from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
2122
from transformers.models.video_llava.modeling_video_llava import (
2223
VideoLlavaCausalLMOutputWithPast,
2324
VideoLlavaForConditionalGeneration,
25+
VideoLlavaModel,
26+
VideoLlavaModelOutputWithPast,
2427
)
25-
from transformers.utils import is_torchdynamo_compiling, logging
28+
from transformers.processing_utils import Unpack
29+
from transformers.utils import TransformersKwargs, logging
2630

2731

2832
logger = logging.get_logger(__name__)
2933

3034

31-
class GaudiVideoLlavaForConditionalGeneration(VideoLlavaForConditionalGeneration):
35+
class GaudiVideoLlavaModel(VideoLlavaModel):
3236
def forward(
3337
self,
3438
input_ids: torch.LongTensor = None,
3539
pixel_values_images: torch.FloatTensor = None,
3640
pixel_values_videos: torch.FloatTensor = None,
3741
attention_mask: Optional[torch.Tensor] = None,
3842
position_ids: Optional[torch.LongTensor] = None,
39-
past_key_values: Optional[list[torch.FloatTensor]] = None,
43+
past_key_values: Optional[Cache] = None,
4044
inputs_embeds: Optional[torch.FloatTensor] = None,
4145
vision_feature_layer: Optional[Union[int, list[int]]] = None,
4246
vision_feature_select_strategy: Optional[str] = None,
43-
labels: Optional[torch.LongTensor] = None,
4447
use_cache: Optional[bool] = None,
4548
output_attentions: Optional[bool] = None,
4649
output_hidden_states: Optional[bool] = None,
4750
return_dict: Optional[bool] = None,
4851
cache_position: Optional[torch.LongTensor] = None,
49-
logits_to_keep: Union[int, torch.Tensor] = 0,
5052
token_idx: Optional[torch.Tensor] = None,
51-
**lm_kwargs,
52-
) -> Union[tuple, VideoLlavaCausalLMOutputWithPast]:
53+
**kwargs: Unpack[FlashAttentionKwargs],
54+
) -> Union[tuple, VideoLlavaModelOutputWithPast]:
5355
r"""
54-
Copied from VideoLlavaForConditionalGeneration.forward: https://github.com/huggingface/transformers/blob/v4.51.3/src/transformers/models/video_llava/modeling_video_llava.py#L365
56+
Copied from VideoLlavaForConditionalGeneration.forward: https://github.com/huggingface/transformers/blob/v4.55.4/src/transformers/models/video_llava/modeling_video_llava.py#L327
5557
The only difference is:
5658
- add new args token_idx
5759
"""
58-
5960
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
6061
output_hidden_states = (
6162
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
@@ -73,12 +74,6 @@ def forward(
7374
if (input_ids is None) ^ (inputs_embeds is not None):
7475
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
7576

76-
if (pixel_values_images is not None or pixel_values_videos is not None) and inputs_embeds is not None:
77-
raise ValueError(
78-
"You cannot specify both `pixel_values_images`/`pixel_values_videos` and `inputs_embeds` at the same "
79-
"time, and must specify either one"
80-
)
81-
8277
if inputs_embeds is None:
8378
inputs_embeds = self.get_input_embeddings()(input_ids)
8479

@@ -88,32 +83,21 @@ def forward(
8883
vision_feature_layer=vision_feature_layer,
8984
vision_feature_select_strategy=vision_feature_select_strategy,
9085
)
91-
special_image_mask = (input_ids == self.config.image_token_index).unsqueeze(-1)
92-
special_image_mask = special_image_mask.expand_as(inputs_embeds).to(inputs_embeds.device)
93-
if not is_torchdynamo_compiling() and inputs_embeds[special_image_mask].numel() != image_features.numel():
94-
n_image_tokens = (input_ids == self.config.image_token_index).sum()
95-
n_image_features = image_features.shape[0] * image_features.shape[1]
96-
raise ValueError(
97-
f"Image features and image tokens do not match: tokens: {n_image_tokens}, features {n_image_features}"
98-
)
9986
image_features = image_features.to(inputs_embeds.device, inputs_embeds.dtype)
87+
special_image_mask, _ = self.get_placeholder_mask(
88+
input_ids, inputs_embeds=inputs_embeds, image_features=image_features
89+
)
10090
inputs_embeds = inputs_embeds.masked_scatter(special_image_mask, image_features)
10191

10292
if pixel_values_videos is not None:
10393
video_features, num_frames = self.get_video_features(
10494
pixel_values_videos=pixel_values_videos, vision_feature_layer=vision_feature_layer
10595
)
106-
107-
special_image_mask = (input_ids == self.config.video_token_index).unsqueeze(-1)
108-
special_image_mask = special_image_mask.expand_as(inputs_embeds).to(inputs_embeds.device)
109-
if not is_torchdynamo_compiling() and inputs_embeds[special_image_mask].numel() != video_features.numel():
110-
n_video_tokens = (input_ids == self.config.video_token_index).sum()
111-
n_video_features = video_features.shape[0] * video_features.shape[1]
112-
raise ValueError(
113-
f"Video features and video tokens do not match: tokens: {n_video_tokens}, features {n_video_features}"
114-
)
11596
video_features = video_features.to(inputs_embeds.device, inputs_embeds.dtype)
116-
inputs_embeds = inputs_embeds.masked_scatter(special_image_mask, video_features)
97+
_, special_video_mask = self.get_placeholder_mask(
98+
input_ids, inputs_embeds=inputs_embeds, video_features=video_features
99+
)
100+
inputs_embeds = inputs_embeds.masked_scatter(special_video_mask, video_features)
117101

118102
outputs = self.language_model(
119103
attention_mask=attention_mask,
@@ -123,43 +107,100 @@ def forward(
123107
use_cache=use_cache,
124108
output_attentions=output_attentions,
125109
output_hidden_states=output_hidden_states,
126-
return_dict=return_dict,
110+
return_dict=True,
111+
cache_position=cache_position,
112+
token_idx=token_idx,
113+
**kwargs,
114+
)
115+
116+
return VideoLlavaModelOutputWithPast(
117+
last_hidden_state=outputs.last_hidden_state,
118+
past_key_values=outputs.past_key_values,
119+
hidden_states=outputs.hidden_states,
120+
attentions=outputs.attentions,
121+
image_hidden_states=image_features if pixel_values_images is not None else None,
122+
video_hidden_states=video_features if pixel_values_videos is not None else None,
123+
)
124+
125+
126+
class GaudiVideoLlavaForConditionalGeneration(VideoLlavaForConditionalGeneration):
127+
def forward(
128+
self,
129+
input_ids: torch.LongTensor = None,
130+
pixel_values_images: torch.FloatTensor = None,
131+
pixel_values_videos: torch.FloatTensor = None,
132+
attention_mask: Optional[torch.Tensor] = None,
133+
position_ids: Optional[torch.LongTensor] = None,
134+
past_key_values: Optional[Cache] = None,
135+
inputs_embeds: Optional[torch.FloatTensor] = None,
136+
vision_feature_layer: Optional[Union[int, list[int]]] = None,
137+
vision_feature_select_strategy: Optional[str] = None,
138+
labels: Optional[torch.LongTensor] = None,
139+
use_cache: Optional[bool] = None,
140+
output_attentions: Optional[bool] = None,
141+
output_hidden_states: Optional[bool] = None,
142+
return_dict: Optional[bool] = None,
143+
cache_position: Optional[torch.LongTensor] = None,
144+
logits_to_keep: Union[int, torch.Tensor] = 0,
145+
token_idx: Optional[torch.Tensor] = None,
146+
**kwargs: Unpack[TransformersKwargs],
147+
) -> Union[tuple, VideoLlavaCausalLMOutputWithPast]:
148+
r"""
149+
Copied from VideoLlavaForConditionalGeneration.forward: https://github.com/huggingface/transformers/blob/v4.55.4/src/transformers/models/video_llava/modeling_video_llava.py#L483
150+
The only difference is:
151+
- add new args token_idx
152+
"""
153+
154+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
155+
output_hidden_states = (
156+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
157+
)
158+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
159+
vision_feature_layer = (
160+
vision_feature_layer if vision_feature_layer is not None else self.config.vision_feature_layer
161+
)
162+
vision_feature_select_strategy = (
163+
vision_feature_select_strategy
164+
if vision_feature_select_strategy is not None
165+
else self.config.vision_feature_select_strategy
166+
)
167+
168+
outputs = self.model(
169+
input_ids=input_ids,
170+
pixel_values_images=pixel_values_images,
171+
pixel_values_videos=pixel_values_videos,
172+
attention_mask=attention_mask,
173+
position_ids=position_ids,
174+
past_key_values=past_key_values,
175+
inputs_embeds=inputs_embeds,
176+
use_cache=use_cache,
177+
vision_feature_layer=vision_feature_layer,
178+
vision_feature_select_strategy=vision_feature_select_strategy,
179+
output_attentions=output_attentions,
180+
output_hidden_states=output_hidden_states,
181+
return_dict=True,
127182
cache_position=cache_position,
128-
logits_to_keep=logits_to_keep,
129183
token_idx=token_idx,
130-
**lm_kwargs,
184+
**kwargs,
131185
)
132186

133-
logits = outputs[0]
187+
hidden_states = outputs[0]
188+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
189+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
190+
logits = self.lm_head(hidden_states[:, slice_indices, :])
134191

135192
loss = None
136193
if labels is not None:
137-
# Shift so that tokens < n predict n
138-
if attention_mask is not None:
139-
# we use the input attention mask to shift the logits and labels, because it is 2D.
140-
# we also crop attn mask in case it is longer, which happens in PrefixTuning with peft
141-
shift_attention_mask = attention_mask[:, -(logits.shape[1] - 1) :].to(logits.device)
142-
shift_logits = logits[..., :-1, :][shift_attention_mask.to(logits.device) != 0].contiguous()
143-
shift_labels = labels[..., 1:][shift_attention_mask.to(labels.device) != 0].contiguous()
144-
else:
145-
shift_logits = logits[..., :-1, :].contiguous()
146-
shift_labels = labels[..., 1:].contiguous()
147-
# Flatten the tokens
148-
loss_fct = nn.CrossEntropyLoss()
149-
loss = loss_fct(
150-
shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1).to(shift_logits.device)
194+
loss = self.loss_function(
195+
logits=logits, labels=labels, vocab_size=self.config.text_config.vocab_size, **kwargs
151196
)
152197

153-
if not return_dict:
154-
output = (logits,) + outputs[1:]
155-
return (loss,) + output if loss is not None else output
156-
157198
return VideoLlavaCausalLMOutputWithPast(
158199
loss=loss,
159200
logits=logits,
160201
past_key_values=outputs.past_key_values,
161202
hidden_states=outputs.hidden_states,
162203
attentions=outputs.attentions,
163-
image_hidden_states=image_features if pixel_values_images is not None else None,
164-
video_hidden_states=video_features if pixel_values_videos is not None else None,
165-
)
204+
image_hidden_states=outputs.image_hidden_states,
205+
video_hidden_states=outputs.video_hidden_states,
206+
)

0 commit comments

Comments
 (0)