@@ -1296,6 +1296,7 @@ def forward(
12961296 audio_embed_sizes = audio_embed_sizes ,
12971297 audio_attention_mask = audio_attention_mask ,
12981298 input_mode = input_mode ,
1299+ temporal_ids = temporal_ids ,
12991300 ** kwargs ,
13001301 )
13011302
@@ -1648,6 +1649,7 @@ def preprocess_inputs(
16481649 tokenizer : Optional [PreTrainedTokenizer ] = None ,
16491650 config : Optional [PretrainedConfig ] = None ,
16501651 video : Optional ["VideoInput" ] = None ,
1652+ video_temporal_ids : Optional [List [List [int ]]] = None ,
16511653 audio : Optional [np .ndarray ] = None ,
16521654 ):
16531655 if processor is None :
@@ -2572,6 +2574,7 @@ def get_vision_embeddings(self, pixel_values, input_ids=None, **kwargs):
25722574 if input_ids is not None and input_ids .shape [1 ] == 1 :
25732575 return None
25742576 tgt_sizes = kwargs ["tgt_sizes" ]
2577+ temporal_ids = kwargs .get ("temporal_ids" )
25752578 pixel_values_list = pixel_values
25762579 vision_hidden_states = []
25772580 all_pixel_values = []
@@ -2607,14 +2610,17 @@ def get_vision_embeddings(self, pixel_values, input_ids=None, **kwargs):
26072610 pixel_values = all_pixel_values , patch_attention_mask = patch_attn_mask , position_ids = position_ids
26082611 )[0 ]
26092612 )
2610- vision_embedding = self .resampling (vision_embedding , tgt_sizes )
2613+ temporal_groups = None
2614+ if temporal_ids is not None :
2615+ temporal_groups = [group for sample_groups in temporal_ids for group in sample_groups ]
2616+ vision_embedding = self .resampling (vision_embedding , tgt_sizes , temporal_groups )
26112617
26122618 start = 0
2613- for pixel_value in pixel_values_list :
2614- img_cnt = len (pixel_value )
2615- if img_cnt > 0 :
2616- vision_hidden_states .append (vision_embedding [start : start + img_cnt ])
2617- start += img_cnt
2619+ for sample_idx , pixel_value in enumerate ( pixel_values_list ) :
2620+ output_count = len ( temporal_ids [ sample_idx ]) if temporal_ids is not None else len (pixel_value )
2621+ if output_count > 0 :
2622+ vision_hidden_states .append (vision_embedding [start : start + output_count ])
2623+ start += output_count
26182624 else :
26192625 vision_hidden_states .append ([])
26202626 else : # no image
@@ -2623,7 +2629,7 @@ def get_vision_embeddings(self, pixel_values, input_ids=None, **kwargs):
26232629 vision_hidden_states .append (dummy_feature )
26242630 return vision_hidden_states
26252631
2626- def resampling (self , x , tgt_sizes ):
2632+ def resampling (self , x , tgt_sizes , temporal_groups = None ):
26272633 bs = x .shape [0 ]
26282634
26292635 patch_len = tgt_sizes [:, 0 ] * tgt_sizes [:, 1 ]
@@ -2642,6 +2648,50 @@ def resampling(self, x, tgt_sizes):
26422648 pos_embed = torch .nn .utils .rnn .pad_sequence (pos_embed , batch_first = True , padding_value = 0.0 ).permute (
26432649 1 , 0 , 2
26442650 ) # BLD => L * B * D
2651+ # A temporal group is represented by one fixed set of resampler query tokens, so concatenate
2652+ # its frame features and positions before inference instead of producing tokens for every frame.
2653+ if temporal_groups is not None :
2654+ group_features = []
2655+ group_positions = []
2656+ group_masks = []
2657+ frame_start = 0
2658+ for group in temporal_groups :
2659+ group_ids = [int (temporal_id ) for temporal_id in group ]
2660+ if not group_ids :
2661+ raise ValueError ("Temporal groups must not be empty" )
2662+ frame_end = frame_start + len (group_ids )
2663+ if frame_end > bs :
2664+ raise ValueError ("Temporal groups contain more frames than were encoded" )
2665+
2666+ group_pos_embed = pos_embed [:, frame_start :frame_end ].permute (1 , 0 , 2 )
2667+ temporal_positions = np .asarray ([max (temporal_id , 0 ) for temporal_id in group_ids ], dtype = np .float32 )
2668+ temporal_embed = self ._get_1d_sincos_pos_embed_from_grid_new (
2669+ self .embed_dim , temporal_positions [:, None ]
2670+ ).squeeze (1 )
2671+ temporal_embed [np .asarray (group_ids ) < 0 ] = 0
2672+ group_pos_embed += torch .from_numpy (temporal_embed ).to (group_pos_embed .dtype ).unsqueeze (1 )
2673+
2674+ group_features .append (x [frame_start :frame_end ].reshape (- 1 , x .shape [- 1 ]))
2675+ group_positions .append (group_pos_embed .reshape (- 1 , self .embed_dim ))
2676+ group_masks .append (key_padding_mask [frame_start :frame_end ].reshape (- 1 ))
2677+ frame_start = frame_end
2678+
2679+ if frame_start != bs :
2680+ raise ValueError (f"Temporal groups cover { frame_start } frames, but { bs } were encoded" )
2681+
2682+ image_feature = torch .nn .utils .rnn .pad_sequence (group_features , batch_first = True , padding_value = 0.0 )
2683+ pos_embed = torch .nn .utils .rnn .pad_sequence (group_positions , batch_first = True , padding_value = 0.0 ).permute (
2684+ 1 , 0 , 2
2685+ )
2686+ key_padding_mask = torch .nn .utils .rnn .pad_sequence (group_masks , batch_first = True , padding_value = True )
2687+ return torch .from_numpy (
2688+ self .resampler (
2689+ image_feature = image_feature ,
2690+ pos_embed = pos_embed ,
2691+ key_padding_mask = key_padding_mask ,
2692+ )
2693+ )
2694+
26452695 res = torch .from_numpy (self .resampler (image_feature = x , pos_embed = pos_embed , key_padding_mask = key_padding_mask ))
26462696 return res
26472697
@@ -2761,14 +2811,57 @@ def preprocess_inputs(
27612811 tokenizer : Optional [PreTrainedTokenizer ] = None ,
27622812 config : Optional [PretrainedConfig ] = None ,
27632813 video : Optional ["VideoInput" ] = None ,
2814+ video_temporal_ids : Optional [List [List [int ]]] = None ,
27642815 audio : Optional [np .ndarray ] = None ,
27652816 ):
27662817 if processor is None :
27672818 raise ValueError ("Processor is required." )
2768- if video is not None :
2769- raise ValueError ("Video input is not supported" )
27702819 if audio is not None :
27712820 raise ValueError ("Audio input is not supported" )
2821+ if video is not None and (getattr (config , "version" , 0 ) or 0 ) >= 4.5 :
2822+ from PIL import Image as PILImage
2823+
2824+ video_frames = [
2825+ frame if isinstance (frame , PILImage .Image ) else PILImage .fromarray (np .asarray (frame ))
2826+ for frame in video
2827+ ]
2828+ if len (video_frames ) == 0 :
2829+ raise ValueError ("Video input must contain at least one frame" )
2830+
2831+ image_inputs = [] if image is None else image if isinstance (image , list ) else [image ]
2832+ visual_inputs = image_inputs + video_frames
2833+ temporal_ids = [[- 1 ] for _ in image_inputs ]
2834+ if video_temporal_ids is None :
2835+ temporal_ids .extend (
2836+ list (range (group_start , min (group_start + 6 , len (video_frames ))))
2837+ for group_start in range (0 , len (video_frames ), 6 )
2838+ )
2839+ else :
2840+ if sum (len (group ) for group in video_temporal_ids ) != len (video_frames ):
2841+ raise ValueError ("video_temporal_ids must contain one ID for every video frame" )
2842+ temporal_ids .extend (video_temporal_ids )
2843+ messages = [
2844+ {
2845+ "role" : "user" ,
2846+ "content" : "(<image>./</image>)" * len (visual_inputs ) + "\n " + text ,
2847+ }
2848+ ]
2849+ chat_template_processor = (
2850+ processor if getattr (processor , "chat_template" , None ) is not None else processor .tokenizer
2851+ )
2852+ prompt = chat_template_processor .apply_chat_template (messages , tokenize = False , add_generation_prompt = True )
2853+ inputs = processor (
2854+ prompt ,
2855+ visual_inputs ,
2856+ temporal_ids = temporal_ids ,
2857+ max_slice_nums = 1 ,
2858+ use_image_id = False ,
2859+ return_tensors = "pt" ,
2860+ )
2861+ inputs .pop ("image_sizes" , None )
2862+ return inputs
2863+ if video is not None :
2864+ raise ValueError ("Video input is not supported" )
27722865 if getattr (processor , "chat_template" , None ) is not None :
27732866 messages = [{"role" : "user" , "content" : text if image is None else "(<image>./</image>)\n " + text }]
27742867 prompt = processor .apply_chat_template (messages , tokenize = False , add_generation_prompt = True )
0 commit comments