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:
Tcc0403
2025-06-10 10:46:13 -07:00
committed by GitHub
co-authored by Shao Tang
parent 6853d5dfc5
commit 53a37a5cc5
10 changed files with 441 additions and 242 deletions
@@ -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,
)
+26 -96
View File
@@ -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,
)
+66 -23
View File
@@ -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,
}
+10 -4
View File
@@ -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
+10 -4
View File
@@ -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
+233 -9
View File
@@ -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"):