mirror of
https://github.com/linkedin/Liger-Kernel.git
synced 2026-10-12 02:17:47 +00:00
fix: Fix qwen2_vl and qwen2_5_vl monkey patch (#738)
## Summary <!--- This is a required section; please describe the main purpose of this proposed code change. ---> Resolve part of #729, #713 ## Details ### For monkey patch: Determine the class of instance and patch Liger Kernel to text model and vision model accordingly. Add supported model type to `MODEL_TYPE_TO_APPLY_LIGER_FN` dictionary to correctly call the corresponding functions. ### For convergence test: `video_processor` is now required for `Qwen2_Processor` and `Qwen2_5_Processor`. ## Testing Done <!--- This is a required section; please describe how this change was tested. ---> <details> <summary>transformers/monkey_patch</summary> ``` ❯ python3 -m pytest test/transformers/test_monkey_patch.py -k vl ================================================= test session starts ================================================== platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0 rootdir: /home/tcc/Liger-Kernel configfile: pyproject.toml plugins: rerunfailures-15.0, xdist-3.6.1 collected 30 items / 24 deselected / 6 selected test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_vl_for_conditional_generation ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_vl with kwargs: {} PASSED [ 16%] test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_vl ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_vl with kwargs: {} PASSED [ 33%] test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_vl_text ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_vl_text with kwargs: {} PASSED [ 50%] test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_5_vl ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_5_vl with kwargs: {} PASSED [ 66%] test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_5_vl_for_conditional_generation ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_5_vl with kwargs: {} PASSED [ 83%] test/transformers/test_monkey_patch.py::test_apply_liger_kernel_to_instance_for_qwen2_5_vl_text ---------------------------------------------------- live log call ----------------------------------------------------- INFO liger_kernel.transformers.monkey_patch:monkey_patch.py:1668 Applying Liger kernels to model instance with model type: qwen2_5_vl_text with kwargs: {} PASSED ``` </details> convergence test <details> <summary>bf16/test_mini_models</summary> ``` ❯ python3 -m pytest test/convergence/bf16/test_mini_models.py -k vl ================================================= test session starts ================================================== platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0 rootdir: /home/tcc/Liger-Kernel configfile: pyproject.toml plugins: rerunfailures-15.0, xdist-3.6.1 collecting ... ------------------------------------------------- live log collection -------------------------------------------------- INFO datasets:config.py:54 PyTorch version 2.7.0 available. collected 16 items / 14 deselected / 2 selected test/convergence/bf16/test_mini_models.py::test_mini_model[mini_qwen2_vl-32-0.0001-dtype7-0.001-0.05-1-0.1-0.01-0.01] PASSED [ 50%] test/convergence/bf16/test_mini_models.py::test_mini_model[mini_qwen2_5_vl-32-0.0001-dtype8-0.001-0.05-3-0.1-0.01-0.01] PASSED [100%] ``` </details> <details> <summary>bf16/test_mini_models_multimodal</summary> ``` ❯ python3 -m pytest test/convergence/bf16/test_mini_models_multimodal.py -k qwen2 ================================================= test session starts ================================================== platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0 rootdir: /home/tcc/Liger-Kernel configfile: pyproject.toml plugins: rerunfailures-15.0, xdist-3.6.1 collecting ... ------------------------------------------------- live log collection -------------------------------------------------- INFO datasets:config.py:54 PyTorch version 2.7.0 available. collected 7 items / 5 deselected / 2 selected test/convergence/bf16/test_mini_models_multimodal.py::test_mini_model_multimodal[mini_qwen2_vl-32-0.0001-dtype0-0.001-0.01-0.1-0.01-0.01-0.01] PASSED [ 50%] test/convergence/bf16/test_mini_models_multimodal.py::test_mini_model_multimodal[mini_qwen2_5_vl-32-0.0001-dtype2-0.001-0.01-0.1-0.01-0.01-0.01] PASSED [100%] ``` </details> <details> <summary>fp32/test_mini_models</summary> ``` ❯ python3 -m pytest test/convergence/fp32/test_mini_models.py -k vl ================================================= test session starts ================================================== platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0 rootdir: /home/tcc/Liger-Kernel configfile: pyproject.toml plugins: rerunfailures-15.0, xdist-3.6.1 collecting ... ------------------------------------------------- live log collection -------------------------------------------------- INFO datasets:config.py:54 PyTorch version 2.7.0 available. collected 17 items / 15 deselected / 2 selected test/convergence/fp32/test_mini_models.py::test_mini_model[mini_qwen2_vl-32-0.0001-dtype7-1e-05-0.1-1-0.1-0.005-1e-05] PASSED [ 50%] test/convergence/fp32/test_mini_models.py::test_mini_model[mini_qwen2_5_vl-32-0.0001-dtype8-1e-05-0.1-3-0.1-0.005-1e-05] PASSED [100%] ``` </details> <details> <summary>fp32/test_mini_models_multimodal</summary> ``` ❯ python3 -m pytest test/convergence/fp32/test_mini_models_multimodal.py -k vl ================================================= test session starts ================================================== platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0 rootdir: /home/tcc/Liger-Kernel configfile: pyproject.toml plugins: rerunfailures-15.0, xdist-3.6.1 collecting ... ------------------------------------------------- live log collection -------------------------------------------------- INFO datasets:config.py:54 PyTorch version 2.7.0 available. collected 7 items / 5 deselected / 2 selected test/convergence/fp32/test_mini_models_multimodal.py::test_mini_model_multimodal[mini_qwen2_vl-32-0.0001-dtype0-1e-08-1e-05-0.005-1e-05-0.005-1e-05] PASSED [ 50%] test/convergence/fp32/test_mini_models_multimodal.py::test_mini_model_multimodal[mini_qwen2_5_vl-32-0.0001-dtype2-1e-08-1e-05-0.005-1e-05-0.005-1e-05] PASSED [100%] ``` </details> <!-- Replace BLANK with your device type. For example, A100-80G-PCIe Complete the following tasks before sending your PR, and replace `[ ]` with `[x]` to indicate you have done them. --> - Hardware Type: <BLANK> - [ ] run `make test` to ensure correctness - [ ] run `make checkstyle` to ensure code style - [ ] run `make test-convergence` to ensure convergence --------- Signed-off-by: Tcc0403 <[email protected]> Co-authored-by: Shao Tang <[email protected]>
This commit is contained in:
@@ -5,12 +5,13 @@ from typing import Union
|
||||
|
||||
import torch
|
||||
|
||||
from torch.nn import CrossEntropyLoss
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLCausalLMOutputWithPast
|
||||
from transformers.utils import can_return_tuple
|
||||
|
||||
from liger_kernel.transformers.model.loss_utils import LigerForCausalLMLoss
|
||||
|
||||
|
||||
@can_return_tuple
|
||||
def lce_forward(
|
||||
self,
|
||||
input_ids: torch.LongTensor = None,
|
||||
@@ -34,14 +35,22 @@ def lce_forward(
|
||||
**kwargs,
|
||||
) -> Union[Tuple, Qwen2_5_VLCausalLMOutputWithPast]:
|
||||
r"""
|
||||
Copy paste Qwen2_5_VL's forward but replace torch cross entropy with liger fused linear cross entropy
|
||||
Args:
|
||||
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
||||
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
||||
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
||||
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
||||
|
||||
Returns:
|
||||
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
||||
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
||||
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
||||
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
||||
pixel_values_videos (`torch.FloatTensor` of shape `(seq_length, num_channels * temporal_size * image_size * image_size)):
|
||||
The tensors corresponding to the input videos. Pixel values can be obtained using
|
||||
[`AutoImageProcessor`]. See [`Qwen2_5_VLImageProcessor.__call__`] for details. [`Qwen2_5_VLProcessor`] uses
|
||||
[`Qwen2_5_VLImageProcessor`] for processing videos.
|
||||
image_grid_thw (`torch.LongTensor` of shape `(num_images, 3)`, *optional*):
|
||||
The temporal, height and width of feature shape of each image in LLM.
|
||||
video_grid_thw (`torch.LongTensor` of shape `(num_videos, 3)`, *optional*):
|
||||
The temporal, height and width of feature shape of each video in LLM.
|
||||
rope_deltas (`torch.LongTensor` of shape `(batch_size, )`, *optional*):
|
||||
The rope index difference between sequence length and multimodal rope.
|
||||
second_per_grid_ts (`torch.Tensor` of shape `(num_videos)`, *optional*):
|
||||
The time interval (in seconds) for each grid along the temporal dimension in the 3D position IDs.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -73,78 +82,20 @@ def lce_forward(
|
||||
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
||||
"The image shows a street scene with a red stop sign in the foreground. In the background, there is a large red gate with Chinese characters ..."
|
||||
```"""
|
||||
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
if inputs_embeds is None:
|
||||
inputs_embeds = self.model.embed_tokens(input_ids)
|
||||
if pixel_values is not None:
|
||||
pixel_values = pixel_values.type(self.visual.dtype)
|
||||
image_embeds = self.visual(pixel_values, grid_thw=image_grid_thw)
|
||||
n_image_tokens = (input_ids == self.config.image_token_id).sum().item()
|
||||
n_image_features = image_embeds.shape[0]
|
||||
if n_image_tokens != n_image_features:
|
||||
raise ValueError(
|
||||
f"Image features and image tokens do not match: tokens: {n_image_tokens}, features {n_image_features}"
|
||||
)
|
||||
|
||||
mask = input_ids == self.config.image_token_id
|
||||
mask_unsqueezed = mask.unsqueeze(-1)
|
||||
mask_expanded = mask_unsqueezed.expand_as(inputs_embeds)
|
||||
image_mask = mask_expanded.to(inputs_embeds.device)
|
||||
|
||||
image_embeds = image_embeds.to(inputs_embeds.device, inputs_embeds.dtype)
|
||||
inputs_embeds = inputs_embeds.masked_scatter(image_mask, image_embeds)
|
||||
|
||||
if pixel_values_videos is not None:
|
||||
pixel_values_videos = pixel_values_videos.type(self.visual.dtype)
|
||||
video_embeds = self.visual(pixel_values_videos, grid_thw=video_grid_thw)
|
||||
n_video_tokens = (input_ids == self.config.video_token_id).sum().item()
|
||||
n_video_features = video_embeds.shape[0]
|
||||
if n_video_tokens != n_video_features:
|
||||
raise ValueError(
|
||||
f"Video features and video tokens do not match: tokens: {n_video_tokens}, features {n_video_features}"
|
||||
)
|
||||
|
||||
mask = input_ids == self.config.video_token_id
|
||||
mask_unsqueezed = mask.unsqueeze(-1)
|
||||
mask_expanded = mask_unsqueezed.expand_as(inputs_embeds)
|
||||
video_mask = mask_expanded.to(inputs_embeds.device)
|
||||
|
||||
video_embeds = video_embeds.to(inputs_embeds.device, inputs_embeds.dtype)
|
||||
inputs_embeds = inputs_embeds.masked_scatter(video_mask, video_embeds)
|
||||
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(inputs_embeds.device)
|
||||
|
||||
# if we get 4D attention mask we cannot calculate rope deltas anymore. TODO @raushan fixme
|
||||
if position_ids is None and (attention_mask is None or attention_mask.ndim == 2):
|
||||
# calculate RoPE index once per generation in the pre-fill stage only
|
||||
if (cache_position is not None and cache_position[0] == 0) or self.rope_deltas is None:
|
||||
position_ids, rope_deltas = self.get_rope_index(
|
||||
input_ids,
|
||||
image_grid_thw,
|
||||
video_grid_thw,
|
||||
second_per_grid_ts,
|
||||
attention_mask,
|
||||
)
|
||||
self.rope_deltas = rope_deltas
|
||||
# then use the prev pre-calculated rope-deltas to get the correct position ids
|
||||
else:
|
||||
batch_size, seq_length, _ = inputs_embeds.shape
|
||||
delta = (cache_position[0] + self.rope_deltas).to(inputs_embeds.device) if cache_position is not None else 0
|
||||
position_ids = torch.arange(seq_length, device=inputs_embeds.device)
|
||||
position_ids = position_ids.view(1, -1).expand(batch_size, -1)
|
||||
if cache_position is not None: # otherwise `deltas` is an int `0`
|
||||
delta = delta.repeat_interleave(batch_size // delta.shape[0], dim=0)
|
||||
position_ids = position_ids.add(delta)
|
||||
position_ids = position_ids.unsqueeze(0).expand(3, -1, -1)
|
||||
|
||||
outputs = self.model(
|
||||
input_ids=None,
|
||||
input_ids=input_ids,
|
||||
pixel_values=pixel_values,
|
||||
pixel_values_videos=pixel_values_videos,
|
||||
image_grid_thw=image_grid_thw,
|
||||
video_grid_thw=video_grid_thw,
|
||||
second_per_grid_ts=second_per_grid_ts,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
past_key_values=past_key_values,
|
||||
@@ -180,19 +131,10 @@ def lce_forward(
|
||||
)
|
||||
else:
|
||||
logits = self.lm_head(hidden_states)
|
||||
|
||||
loss = None
|
||||
if labels is not None:
|
||||
# Upcast to float if we need to compute the loss to avoid potential precision issues
|
||||
logits = logits.float()
|
||||
# Shift so that tokens < n predict n
|
||||
shift_logits = logits[..., :-1, :].contiguous()
|
||||
shift_labels = labels[..., 1:].contiguous()
|
||||
# Flatten the tokens
|
||||
loss_fct = CrossEntropyLoss()
|
||||
shift_logits = shift_logits.view(-1, self.config.vocab_size)
|
||||
shift_labels = shift_labels.view(-1)
|
||||
# Enable model parallelism
|
||||
shift_labels = shift_labels.to(shift_logits.device)
|
||||
loss = loss_fct(shift_logits, shift_labels)
|
||||
loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size)
|
||||
|
||||
if not return_dict:
|
||||
output = (logits,) + outputs[1:]
|
||||
@@ -204,5 +146,5 @@ def lce_forward(
|
||||
past_key_values=outputs.past_key_values,
|
||||
hidden_states=outputs.hidden_states,
|
||||
attentions=outputs.attentions,
|
||||
rope_deltas=rope_deltas,
|
||||
rope_deltas=outputs.rope_deltas,
|
||||
)
|
||||
|
||||
@@ -5,14 +5,13 @@ from typing import Union
|
||||
|
||||
import torch
|
||||
|
||||
from packaging import version
|
||||
from torch.nn import CrossEntropyLoss
|
||||
from transformers import __version__ as transformers_version
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLCausalLMOutputWithPast
|
||||
from transformers.utils import can_return_tuple
|
||||
|
||||
from liger_kernel.transformers.model.loss_utils import LigerForCausalLMLoss
|
||||
|
||||
|
||||
@can_return_tuple
|
||||
def lce_forward(
|
||||
self,
|
||||
input_ids: torch.LongTensor = None,
|
||||
@@ -35,15 +34,20 @@ def lce_forward(
|
||||
**kwargs,
|
||||
) -> Union[Tuple, Qwen2VLCausalLMOutputWithPast]:
|
||||
r"""
|
||||
Copy paste Qwen2VL's forward but replace torch cross entropy with liger fused linear cross entropy
|
||||
|
||||
Args:
|
||||
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
||||
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
||||
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
||||
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
||||
|
||||
Returns:
|
||||
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
||||
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
||||
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
||||
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
||||
pixel_values_videos (`torch.FloatTensor` of shape `(seq_length, num_channels * temporal_size * image_size * image_size)):
|
||||
The tensors corresponding to the input videos. Pixel values can be obtained using
|
||||
[`AutoImageProcessor`]. See [`Qwen2VLImageProcessor.__call__`] for details. [`Qwen2VLProcessor`] uses
|
||||
[`Qwen2VLImageProcessor`] for processing videos.
|
||||
image_grid_thw (`torch.LongTensor` of shape `(num_images, 3)`, *optional*):
|
||||
The temporal, height and width of feature shape of each image in LLM.
|
||||
video_grid_thw (`torch.LongTensor` of shape `(num_videos, 3)`, *optional*):
|
||||
The temporal, height and width of feature shape of each video in LLM.
|
||||
rope_deltas (`torch.LongTensor` of shape `(batch_size, )`, *optional*):
|
||||
The rope index difference between sequence length and multimodal rope.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -75,80 +79,19 @@ def lce_forward(
|
||||
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
||||
"The image shows a street scene with a red stop sign in the foreground. In the background, there is a large red gate with Chinese characters ..."
|
||||
```"""
|
||||
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
if inputs_embeds is None:
|
||||
inputs_embeds = self.model.embed_tokens(input_ids)
|
||||
if pixel_values is not None:
|
||||
pixel_values = pixel_values.type(self.visual.get_dtype())
|
||||
image_embeds = self.visual(pixel_values, grid_thw=image_grid_thw)
|
||||
n_image_tokens = (input_ids == self.config.image_token_id).sum().item()
|
||||
n_image_features = image_embeds.shape[0]
|
||||
if n_image_tokens != n_image_features:
|
||||
raise ValueError(
|
||||
f"Image features and image tokens do not match: tokens: {n_image_tokens}, features {n_image_features}"
|
||||
)
|
||||
image_mask = (
|
||||
(input_ids == self.config.image_token_id)
|
||||
.unsqueeze(-1)
|
||||
.expand_as(inputs_embeds)
|
||||
.to(inputs_embeds.device)
|
||||
)
|
||||
image_embeds = image_embeds.to(inputs_embeds.device, inputs_embeds.dtype)
|
||||
inputs_embeds = inputs_embeds.masked_scatter(image_mask, image_embeds)
|
||||
|
||||
if pixel_values_videos is not None:
|
||||
pixel_values_videos = pixel_values_videos.type(self.visual.get_dtype())
|
||||
video_embeds = self.visual(pixel_values_videos, grid_thw=video_grid_thw)
|
||||
n_video_tokens = (input_ids == self.config.video_token_id).sum().item()
|
||||
n_video_features = video_embeds.shape[0]
|
||||
if n_video_tokens != n_video_features:
|
||||
raise ValueError(
|
||||
f"Video features and video tokens do not match: tokens: {n_video_tokens}, features {n_video_features}"
|
||||
)
|
||||
video_mask = (
|
||||
(input_ids == self.config.video_token_id)
|
||||
.unsqueeze(-1)
|
||||
.expand_as(inputs_embeds)
|
||||
.to(inputs_embeds.device)
|
||||
)
|
||||
video_embeds = video_embeds.to(inputs_embeds.device, inputs_embeds.dtype)
|
||||
inputs_embeds = inputs_embeds.masked_scatter(video_mask, video_embeds)
|
||||
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(inputs_embeds.device)
|
||||
|
||||
if version.parse(transformers_version) > version.parse("4.46.3"):
|
||||
# NOTE: this bug fix for qwen2-vl is not applied until transformers 4.47.0
|
||||
# https://github.com/huggingface/transformers/issues/33401
|
||||
# While correct, this breaks equivalence with past versions of Qwen2-VL from
|
||||
# transformers and leads to failed tests or users noticing differences in results.
|
||||
# TODO: remove above conditional when liger drops support for transformers<4.47.0
|
||||
# if we get 4D attention mask we cannot calculate rope deltas anymore. TODO @raushan fixme
|
||||
if position_ids is None and (attention_mask is None or attention_mask.ndim == 2):
|
||||
# calculate RoPE index once per generation in the pre-fill stage only
|
||||
if (cache_position is not None and cache_position[0] == 0) or self.rope_deltas is None:
|
||||
position_ids, rope_deltas = self.get_rope_index(
|
||||
input_ids, image_grid_thw, video_grid_thw, attention_mask
|
||||
)
|
||||
self.rope_deltas = rope_deltas
|
||||
# then use the prev pre-calculated rope-deltas to get the correct position ids
|
||||
else:
|
||||
batch_size, seq_length, _ = inputs_embeds.shape
|
||||
delta = cache_position[0] + self.rope_deltas if cache_position is not None else 0
|
||||
position_ids = torch.arange(seq_length, device=inputs_embeds.device)
|
||||
position_ids = position_ids.view(1, -1).expand(batch_size, -1)
|
||||
if cache_position is not None: # otherwise `deltas` is an int `0`
|
||||
delta = delta.repeat_interleave(batch_size // delta.shape[0], dim=0)
|
||||
position_ids = position_ids.add(delta)
|
||||
position_ids = position_ids.unsqueeze(0).expand(3, -1, -1)
|
||||
|
||||
outputs = self.model(
|
||||
input_ids=None,
|
||||
input_ids=input_ids,
|
||||
pixel_values=pixel_values,
|
||||
pixel_values_videos=pixel_values_videos,
|
||||
image_grid_thw=image_grid_thw,
|
||||
video_grid_thw=video_grid_thw,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
past_key_values=past_key_values,
|
||||
@@ -184,23 +127,10 @@ def lce_forward(
|
||||
)
|
||||
else:
|
||||
logits = self.lm_head(hidden_states)
|
||||
if labels is not None:
|
||||
# Upcast to float if we need to compute the loss to avoid potential precision issues
|
||||
logits = logits.float()
|
||||
# Shift so that tokens < n predict n
|
||||
shift_logits = logits[..., :-1, :].contiguous()
|
||||
shift_labels = labels[..., 1:].contiguous()
|
||||
# Flatten the tokens
|
||||
loss_fct = CrossEntropyLoss()
|
||||
shift_logits = shift_logits.view(-1, self.config.vocab_size)
|
||||
shift_labels = shift_labels.view(-1)
|
||||
# Enable model parallelism
|
||||
shift_labels = shift_labels.to(shift_logits.device)
|
||||
loss = loss_fct(shift_logits, shift_labels)
|
||||
|
||||
if not return_dict:
|
||||
output = (logits,) + outputs[1:]
|
||||
return (loss,) + output if loss is not None else output
|
||||
loss = None
|
||||
if labels is not None:
|
||||
loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size)
|
||||
|
||||
return Qwen2VLCausalLMOutputWithPast(
|
||||
loss=loss,
|
||||
@@ -208,5 +138,5 @@ def lce_forward(
|
||||
past_key_values=outputs.past_key_values,
|
||||
hidden_states=outputs.hidden_states,
|
||||
attentions=outputs.attentions,
|
||||
rope_deltas=rope_deltas,
|
||||
rope_deltas=outputs.rope_deltas,
|
||||
)
|
||||
|
||||
@@ -1225,7 +1225,7 @@ def apply_liger_kernel_to_qwen2_vl(
|
||||
) -> None:
|
||||
"""
|
||||
Apply Liger kernels to replace original implementation in HuggingFace Qwen2-VL models.
|
||||
NOTE: Qwen2-VL is not available in transformers<4.45.0
|
||||
NOTE: Qwen2-VL is not supported in transformers<4.52.4
|
||||
|
||||
Args:
|
||||
cross_entropy (bool): Whether to apply Liger's cross entropy loss. Default is False.
|
||||
@@ -1239,12 +1239,19 @@ def apply_liger_kernel_to_qwen2_vl(
|
||||
model (PreTrainedModel): The model instance to apply Liger kernels to, if the model has already been
|
||||
loaded. Default is None.
|
||||
"""
|
||||
if transformer_version < version.parse("4.52.4"):
|
||||
logger.warning("Qwen2-VL support is only compatible with transformers >= 4.52.4")
|
||||
return
|
||||
|
||||
assert not (cross_entropy and fused_linear_cross_entropy), (
|
||||
"cross_entropy and fused_linear_cross_entropy cannot both be True."
|
||||
)
|
||||
|
||||
from transformers.models.qwen2_vl import modeling_qwen2_vl
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VisionTransformerPretrainedModel
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLModel
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLTextModel
|
||||
|
||||
from liger_kernel.transformers.model.qwen2_vl import lce_forward as qwen2_vl_lce_forward
|
||||
|
||||
@@ -1266,24 +1273,38 @@ def apply_liger_kernel_to_qwen2_vl(
|
||||
# The model instance already exists, so we need to additionally patch the
|
||||
# instance variables that reference already-instantiated modules
|
||||
|
||||
# get the base model from the model instance
|
||||
base_model: Qwen2VLModel = getattr(model, model.base_model_prefix, model)
|
||||
if isinstance(model, (Qwen2VLForConditionalGeneration, Qwen2VLModel)):
|
||||
# Note: language_model and visual properties can be accessed throught conditional class for BC.
|
||||
# Not sure if it is subject to changes in the future.
|
||||
# Reference: https://github.com/huggingface/transformers/blob/v4.52.4/src/transformers/models/qwen2_vl/modeling_qwen2_vl.py#L1698
|
||||
text_model: Qwen2VLTextModel = model.language_model
|
||||
vision_model: Qwen2VisionTransformerPretrainedModel = model.visual
|
||||
elif isinstance(model, Qwen2VLTextModel):
|
||||
text_model: Qwen2VLTextModel = model
|
||||
vision_model = None
|
||||
else:
|
||||
# Note: Currently there's no support for patching vision model only. Feel free to raise an issue if needed.
|
||||
raise TypeError(
|
||||
f"Unsupported Qwen2VL model type. `model` must be `Qwen2VLForConditionalGeneration`, `Qwen2VLModel` or `Qwen2VLTextModel`. Got: {type(model)}"
|
||||
)
|
||||
|
||||
if hasattr(model, "visual"):
|
||||
# Patch Qwen2VisionTransformerPretrainedModel
|
||||
for vision_block in model.visual.blocks:
|
||||
# Patch Qwen2VisionTransformerPretrainedModel
|
||||
if vision_model is not None:
|
||||
for vision_block in vision_model.blocks:
|
||||
if layer_norm:
|
||||
_patch_layer_norm_module(vision_block.norm1)
|
||||
_patch_layer_norm_module(vision_block.norm2)
|
||||
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(base_model.norm)
|
||||
for decoder_layer in base_model.layers:
|
||||
if swiglu:
|
||||
_patch_swiglu_module(decoder_layer.mlp, LigerSwiGLUMLP)
|
||||
# Patch Qwen2VisionTextModel
|
||||
if text_model is not None:
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(decoder_layer.input_layernorm)
|
||||
_patch_rms_norm_module(decoder_layer.post_attention_layernorm)
|
||||
_patch_rms_norm_module(text_model.norm)
|
||||
for decoder_layer in text_model.layers:
|
||||
if swiglu:
|
||||
_patch_swiglu_module(decoder_layer.mlp, LigerSwiGLUMLP)
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(decoder_layer.input_layernorm)
|
||||
_patch_rms_norm_module(decoder_layer.post_attention_layernorm)
|
||||
|
||||
|
||||
def apply_liger_kernel_to_qwen2_5_vl(
|
||||
@@ -1309,12 +1330,19 @@ def apply_liger_kernel_to_qwen2_5_vl(
|
||||
model (PreTrainedModel): The model instance to apply Liger kernels to, if the model has already been
|
||||
loaded. Default is None.
|
||||
"""
|
||||
if transformer_version < version.parse("4.52.4"):
|
||||
logger.warning("Qwen2.5-VL support is only compatible with transformers >= 4.52.4")
|
||||
return
|
||||
|
||||
assert not (cross_entropy and fused_linear_cross_entropy), (
|
||||
"cross_entropy and fused_linear_cross_entropy cannot both be True."
|
||||
)
|
||||
|
||||
from transformers.models.qwen2_5_vl import modeling_qwen2_5_vl
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VisionTransformerPretrainedModel
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLModel
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLTextModel
|
||||
|
||||
from liger_kernel.transformers.model.qwen2_5_vl import lce_forward as qwen2_5_vl_lce_forward
|
||||
|
||||
@@ -1333,24 +1361,37 @@ def apply_liger_kernel_to_qwen2_5_vl(
|
||||
# The model instance already exists, so we need to additionally patch the
|
||||
# instance variables that reference already-instantiated modules
|
||||
|
||||
# get the base model from the model instance
|
||||
base_model: Qwen2_5_VLModel = getattr(model, model.base_model_prefix, model)
|
||||
if isinstance(model, (Qwen2_5_VLForConditionalGeneration, Qwen2_5_VLModel)):
|
||||
# Note: language_model and visual properties can be accessed throught conditional class for BC.
|
||||
# Not sure if it is subject to changes in the future.
|
||||
# Reference: https://github.com/huggingface/transformers/blob/v4.52.4/src/transformers/models/qwen2_5_vl/modeling_qwen2_5_vl.py#L1823
|
||||
text_model: Qwen2_5_VLTextModel = model.language_model
|
||||
vision_model: Qwen2_5_VisionTransformerPretrainedModel = model.visual
|
||||
elif isinstance(model, Qwen2_5_VLTextModel):
|
||||
text_model: Qwen2_5_VLTextModel = model
|
||||
vision_model = None
|
||||
else:
|
||||
# Note: Currently there's no support for patching vision model only. Feel free to raise an issue if needed.
|
||||
raise TypeError(
|
||||
f"Unsupported Qwen2VL model type. `model` must be `Qwen2VLForConditionalGeneration`, `Qwen2VLModel` or `Qwen2VLTextModel`. Got: {type(model)}"
|
||||
)
|
||||
|
||||
if hasattr(model, "visual"):
|
||||
if vision_model is not None:
|
||||
# Patch Qwen2_5_VisionTransformerPretrainedModel
|
||||
for vision_block in model.visual.blocks:
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(vision_block.norm1)
|
||||
_patch_rms_norm_module(vision_block.norm2)
|
||||
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(base_model.norm)
|
||||
for decoder_layer in base_model.layers:
|
||||
if swiglu:
|
||||
_patch_swiglu_module(decoder_layer.mlp, LigerSwiGLUMLP)
|
||||
if text_model is not None:
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(decoder_layer.input_layernorm)
|
||||
_patch_rms_norm_module(decoder_layer.post_attention_layernorm)
|
||||
_patch_rms_norm_module(text_model.norm)
|
||||
for decoder_layer in text_model.layers:
|
||||
if swiglu:
|
||||
_patch_swiglu_module(decoder_layer.mlp, LigerSwiGLUMLP)
|
||||
if rms_norm:
|
||||
_patch_rms_norm_module(decoder_layer.input_layernorm)
|
||||
_patch_rms_norm_module(decoder_layer.post_attention_layernorm)
|
||||
|
||||
|
||||
def apply_liger_kernel_to_phi3(
|
||||
@@ -1571,7 +1612,9 @@ MODEL_TYPE_TO_APPLY_LIGER_FN = {
|
||||
"qwen3": apply_liger_kernel_to_qwen3,
|
||||
"qwen3_moe": apply_liger_kernel_to_qwen3_moe,
|
||||
"qwen2_vl": apply_liger_kernel_to_qwen2_vl,
|
||||
"qwen2_vl_text": apply_liger_kernel_to_qwen2_vl,
|
||||
"qwen2_5_vl": apply_liger_kernel_to_qwen2_5_vl,
|
||||
"qwen2_5_vl_text": apply_liger_kernel_to_qwen2_5_vl,
|
||||
"phi3": apply_liger_kernel_to_phi3,
|
||||
"paligemma": apply_liger_kernel_to_paligemma,
|
||||
}
|
||||
|
||||
@@ -69,20 +69,26 @@ except ImportError:
|
||||
MLLAMA_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>4.44.2
|
||||
# Qwen2-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
# Qwen2.5-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
|
||||
@@ -35,26 +35,34 @@ from test.utils import supports_bfloat16
|
||||
from test.utils import train_bpe_tokenizer
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>=4.45.0
|
||||
# Qwen2-VL is only available in transformers>=4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2.tokenization_qwen2_fast import Qwen2TokenizerFast
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.image_processing_qwen2_vl import Qwen2VLImageProcessor
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
from transformers.models.qwen2_vl.processing_qwen2_vl import Qwen2VLProcessor
|
||||
from transformers.models.qwen2_vl.video_processing_qwen2_vl import Qwen2VLVideoProcessor
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
# Qwen2.5-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2.tokenization_qwen2_fast import Qwen2TokenizerFast
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
from transformers.models.qwen2_5_vl.processing_qwen2_5_vl import Qwen2_5_VLProcessor
|
||||
from transformers.models.qwen2_vl.image_processing_qwen2_vl import Qwen2VLImageProcessor
|
||||
from transformers.models.qwen2_vl.video_processing_qwen2_vl import Qwen2VLVideoProcessor
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
@@ -504,7 +512,12 @@ def create_processor(model_name: str):
|
||||
)
|
||||
qwen_tokenizer = Qwen2TokenizerFast(tokenizer_object=tokenizer_base, **tokenizer_config)
|
||||
image_processor = Qwen2VLImageProcessor()
|
||||
return Qwen2VLProcessor(image_processor=image_processor, tokenizer=qwen_tokenizer)
|
||||
video_processor = Qwen2VLVideoProcessor()
|
||||
return Qwen2VLProcessor(
|
||||
image_processor=image_processor,
|
||||
video_processor=video_processor,
|
||||
tokenizer=qwen_tokenizer,
|
||||
)
|
||||
|
||||
elif model_name == "mini_qwen2_5_vl":
|
||||
tokenizer_config = load_tokenizer_config(
|
||||
@@ -521,7 +534,12 @@ def create_processor(model_name: str):
|
||||
)
|
||||
qwen_tokenizer = Qwen2TokenizerFast(tokenizer_object=tokenizer_base, **tokenizer_config)
|
||||
image_processor = Qwen2VLImageProcessor()
|
||||
return Qwen2_5_VLProcessor(image_processor=image_processor, tokenizer=qwen_tokenizer)
|
||||
video_processor = Qwen2VLVideoProcessor()
|
||||
return Qwen2_5_VLProcessor(
|
||||
image_processor=image_processor,
|
||||
video_processor=video_processor,
|
||||
tokenizer=qwen_tokenizer,
|
||||
)
|
||||
|
||||
elif model_name == "mini_llava":
|
||||
tokenizer_config = load_tokenizer_config(
|
||||
|
||||
@@ -69,20 +69,26 @@ except ImportError:
|
||||
MLLAMA_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>4.44.2
|
||||
# Qwen2-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
# Qwen2.5-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
|
||||
@@ -68,20 +68,26 @@ except ImportError:
|
||||
MLLAMA_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>4.44.2
|
||||
# Qwen2-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
# Qwen2.5-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
|
||||
@@ -34,26 +34,34 @@ from test.utils import set_seed
|
||||
from test.utils import train_bpe_tokenizer
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>=4.45.0
|
||||
# Qwen2-VL is only available in transformers>=4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2.tokenization_qwen2_fast import Qwen2TokenizerFast
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.image_processing_qwen2_vl import Qwen2VLImageProcessor
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
from transformers.models.qwen2_vl.processing_qwen2_vl import Qwen2VLProcessor
|
||||
from transformers.models.qwen2_vl.video_processing_qwen2_vl import Qwen2VLVideoProcessor
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2.tokenization_qwen2_fast import Qwen2TokenizerFast
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
from transformers.models.qwen2_5_vl.processing_qwen2_5_vl import Qwen2_5_VLProcessor
|
||||
from transformers.models.qwen2_vl.image_processing_qwen2_vl import Qwen2VLImageProcessor
|
||||
from transformers.models.qwen2_vl.video_processing_qwen2_vl import Qwen2VLVideoProcessor
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
@@ -501,7 +509,12 @@ def create_processor(model_name: str):
|
||||
)
|
||||
qwen_tokenizer = Qwen2TokenizerFast(tokenizer_object=tokenizer_base, **tokenizer_config)
|
||||
image_processor = Qwen2VLImageProcessor()
|
||||
return Qwen2VLProcessor(image_processor=image_processor, tokenizer=qwen_tokenizer)
|
||||
video_processor = Qwen2VLVideoProcessor()
|
||||
return Qwen2VLProcessor(
|
||||
image_processor=image_processor,
|
||||
video_processor=video_processor,
|
||||
tokenizer=qwen_tokenizer,
|
||||
)
|
||||
|
||||
elif model_name == "mini_qwen2_5_vl":
|
||||
tokenizer_config = load_tokenizer_config(
|
||||
@@ -518,7 +531,12 @@ def create_processor(model_name: str):
|
||||
)
|
||||
qwen_tokenizer = Qwen2TokenizerFast(tokenizer_object=tokenizer_base, **tokenizer_config)
|
||||
image_processor = Qwen2VLImageProcessor()
|
||||
return Qwen2_5_VLProcessor(image_processor=image_processor, tokenizer=qwen_tokenizer)
|
||||
video_processor = Qwen2VLVideoProcessor()
|
||||
return Qwen2_5_VLProcessor(
|
||||
image_processor=image_processor,
|
||||
video_processor=video_processor,
|
||||
tokenizer=qwen_tokenizer,
|
||||
)
|
||||
|
||||
elif model_name == "mini_llava":
|
||||
tokenizer_config = load_tokenizer_config(
|
||||
|
||||
@@ -68,20 +68,26 @@ except ImportError:
|
||||
MLLAMA_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2-VL is only available in transformers>4.44.2
|
||||
# Qwen2-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_vl.configuration_qwen2_vl import Qwen2VLConfig
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
|
||||
QWEN2_VL_AVAILABLE = True
|
||||
QWEN2_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_VL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
# Qwen2.5-VL is only available in transformers>4.48.2
|
||||
# Qwen2.5-VL is only available in transformers>4.52.4
|
||||
import transformers
|
||||
|
||||
from packaging import version
|
||||
from transformers.models.qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
|
||||
QWEN2_5_VL_AVAILABLE = True
|
||||
QWEN2_5_VL_AVAILABLE = version.parse(transformers.__version__) >= version.parse("4.52.4")
|
||||
except ImportError:
|
||||
QWEN2_5_VL_AVAILABLE = False
|
||||
|
||||
|
||||
@@ -870,7 +870,7 @@ def test_apply_liger_kernel_to_instance_for_qwen3_moe():
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_vl_available(), reason="qwen2_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_vl():
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_vl_for_conditional_generation():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_vl.modeling_qwen2_vl"):
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLForConditionalGeneration
|
||||
@@ -899,8 +899,10 @@ def test_apply_liger_kernel_to_instance_for_qwen2_vl():
|
||||
assert isinstance(dummy_model_instance, Qwen2VLForConditionalGeneration)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.model.norm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.model.layers:
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) != inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
@@ -912,8 +914,10 @@ def test_apply_liger_kernel_to_instance_for_qwen2_vl():
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.model.norm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.model.layers:
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) == inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
@@ -927,8 +931,178 @@ def test_apply_liger_kernel_to_instance_for_qwen2_vl():
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_vl_available(), reason="qwen2_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_vl():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_vl.modeling_qwen2_vl"):
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLModel
|
||||
|
||||
# Instantiate a dummy model
|
||||
config = transformers.models.qwen2_vl.configuration_qwen2_vl.Qwen2VLConfig(
|
||||
torch_dtype=torch.bfloat16,
|
||||
rms_norm_eps=1e-5,
|
||||
hidden_size=32,
|
||||
intermediate_size=48,
|
||||
embed_dim=16,
|
||||
hidden_act="silu",
|
||||
num_hidden_layers=2,
|
||||
num_attention_heads=2,
|
||||
max_position_embeddings=128,
|
||||
vocab_size=1000,
|
||||
vision_config={
|
||||
"depth": 4,
|
||||
"embed_dim": 128,
|
||||
"num_heads": 8,
|
||||
"hidden_size": 1024,
|
||||
},
|
||||
)
|
||||
dummy_model_instance = Qwen2VLModel._from_config(config)
|
||||
|
||||
assert isinstance(dummy_model_instance, Qwen2VLModel)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) != inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for vision_block in dummy_model_instance.visual.blocks:
|
||||
assert inspect.getsource(vision_block.norm1.forward) != inspect.getsource(LigerLayerNorm.forward)
|
||||
assert inspect.getsource(vision_block.norm2.forward) != inspect.getsource(LigerLayerNorm.forward)
|
||||
|
||||
# Test applying kernels to the model instance
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) == inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for vision_block in dummy_model_instance.visual.blocks:
|
||||
assert inspect.getsource(vision_block.norm1.forward) == inspect.getsource(LigerLayerNorm.forward)
|
||||
assert inspect.getsource(vision_block.norm2.forward) == inspect.getsource(LigerLayerNorm.forward)
|
||||
|
||||
try:
|
||||
print(dummy_model_instance)
|
||||
except Exception as e:
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_vl_available(), reason="qwen2_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_vl_text():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_vl.modeling_qwen2_vl"):
|
||||
from transformers.models.qwen2_vl.modeling_qwen2_vl import Qwen2VLTextModel
|
||||
|
||||
# Instantiate a dummy model
|
||||
config = transformers.models.qwen2_vl.configuration_qwen2_vl.Qwen2VLTextConfig(
|
||||
torch_dtype=torch.bfloat16,
|
||||
rms_norm_eps=1e-5,
|
||||
hidden_size=32,
|
||||
intermediate_size=48,
|
||||
embed_dim=16,
|
||||
hidden_act="silu",
|
||||
num_hidden_layers=2,
|
||||
num_attention_heads=2,
|
||||
max_position_embeddings=128,
|
||||
vocab_size=1000,
|
||||
)
|
||||
dummy_model_instance = Qwen2VLTextModel._from_config(config)
|
||||
|
||||
assert isinstance(dummy_model_instance, Qwen2VLTextModel)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.norm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
# Test applying kernels to the model instance
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.norm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
try:
|
||||
print(dummy_model_instance)
|
||||
except Exception as e:
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_5_vl_available(), reason="qwen2_5_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_5_vl():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_5_vl.modeling_qwen2_5_vl"):
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLModel
|
||||
|
||||
# Instantiate a dummy model
|
||||
config = transformers.models.qwen2_5_vl.configuration_qwen2_5_vl.Qwen2_5_VLConfig(
|
||||
torch_dtype=torch.bfloat16,
|
||||
rms_norm_eps=1e-5,
|
||||
hidden_size=32,
|
||||
intermediate_size=48,
|
||||
embed_dim=16,
|
||||
hidden_act="silu",
|
||||
num_hidden_layers=2,
|
||||
num_attention_heads=2,
|
||||
max_position_embeddings=128,
|
||||
vocab_size=1000,
|
||||
vision_config={
|
||||
"depth": 4,
|
||||
"embed_dim": 128,
|
||||
"num_heads": 8,
|
||||
"hidden_size": 1024,
|
||||
},
|
||||
)
|
||||
dummy_model_instance = Qwen2_5_VLModel._from_config(config)
|
||||
|
||||
assert isinstance(dummy_model_instance, Qwen2_5_VLModel)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) != inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for vision_block in dummy_model_instance.visual.blocks:
|
||||
assert inspect.getsource(vision_block.norm1.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(vision_block.norm2.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
# Test applying kernels to the model instance
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) == inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for vision_block in dummy_model_instance.visual.blocks:
|
||||
assert inspect.getsource(vision_block.norm1.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(vision_block.norm2.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
try:
|
||||
print(dummy_model_instance)
|
||||
except Exception as e:
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_5_vl_available(), reason="qwen2_5_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_5_vl_for_conditional_generation():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_5_vl.modeling_qwen2_5_vl"):
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLForConditionalGeneration
|
||||
@@ -957,8 +1131,10 @@ def test_apply_liger_kernel_to_instance_for_qwen2_5_vl():
|
||||
assert isinstance(dummy_model_instance, Qwen2_5_VLForConditionalGeneration)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.model.norm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.model.layers:
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) != inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
@@ -970,8 +1146,10 @@ def test_apply_liger_kernel_to_instance_for_qwen2_5_vl():
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.model.norm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.model.layers:
|
||||
assert inspect.getsource(dummy_model_instance.language_model.norm.forward) == inspect.getsource(
|
||||
LigerRMSNorm.forward
|
||||
)
|
||||
for layer in dummy_model_instance.language_model.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
@@ -985,6 +1163,52 @@ def test_apply_liger_kernel_to_instance_for_qwen2_5_vl():
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_qwen2_5_vl_available(), reason="qwen2_5_vl module not available")
|
||||
def test_apply_liger_kernel_to_instance_for_qwen2_5_vl_text():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.qwen2_5_vl.modeling_qwen2_5_vl"):
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLTextModel
|
||||
|
||||
# Instantiate a dummy model
|
||||
config = transformers.models.qwen2_5_vl.configuration_qwen2_5_vl.Qwen2_5_VLTextConfig(
|
||||
torch_dtype=torch.bfloat16,
|
||||
rms_norm_eps=1e-5,
|
||||
hidden_size=32,
|
||||
intermediate_size=48,
|
||||
embed_dim=16,
|
||||
hidden_act="silu",
|
||||
num_hidden_layers=2,
|
||||
num_attention_heads=2,
|
||||
max_position_embeddings=128,
|
||||
vocab_size=1000,
|
||||
)
|
||||
dummy_model_instance = Qwen2_5_VLTextModel._from_config(config)
|
||||
|
||||
assert isinstance(dummy_model_instance, Qwen2_5_VLTextModel)
|
||||
|
||||
# Check that model instance variables are not yet patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.norm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) != inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) != inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
# Test applying kernels to the model instance
|
||||
_apply_liger_kernel_to_instance(model=dummy_model_instance)
|
||||
|
||||
# Check that the model's instance variables were correctly patched with Liger modules
|
||||
assert inspect.getsource(dummy_model_instance.norm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
for layer in dummy_model_instance.layers:
|
||||
assert inspect.getsource(layer.mlp.forward) == inspect.getsource(LigerSwiGLUMLP.forward)
|
||||
assert inspect.getsource(layer.input_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
assert inspect.getsource(layer.post_attention_layernorm.forward) == inspect.getsource(LigerRMSNorm.forward)
|
||||
|
||||
try:
|
||||
print(dummy_model_instance)
|
||||
except Exception as e:
|
||||
pytest.fail(f"An exception occured in extra_expr: {type(e).__name__} - {e}")
|
||||
|
||||
|
||||
def test_apply_liger_kernel_to_instance_for_phi3():
|
||||
# Ensure any monkey patching is cleaned up for subsequent tests
|
||||
with patch("transformers.models.phi3.modeling_phi3"):
|
||||
|
||||
Reference in New Issue
Block a user