Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn> Signed-off-by: Isotr0py <2037008807@qq.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com> Co-authored-by: SYLAR <125541396+lishunyang12@users.noreply.github.com>
148 lines
5.0 KiB
Python
148 lines
5.0 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from typing import TYPE_CHECKING, Literal
|
|
|
|
import torch
|
|
import torch.nn as nn
|
|
from vllm.model_executor.layers.linear import (
|
|
ColumnParallelLinear,
|
|
ReplicatedLinear,
|
|
RowParallelLinear,
|
|
)
|
|
from vllm.model_executor.models.transformers.utils import init_on_device_without_buffers
|
|
from vllm.model_executor.models.utils import maybe_prefix
|
|
|
|
from vllm_omni.diffusion.data import OmniDiffusionConfig
|
|
from vllm_omni.quantization import build_quant_config
|
|
|
|
if TYPE_CHECKING:
|
|
from transformers import PretrainedConfig, PreTrainedModel
|
|
from transformers.models.auto.auto_factory import _BaseAutoModelClass
|
|
from vllm.model_executor.layers.quantization.base_config import (
|
|
QuantizationConfig,
|
|
)
|
|
|
|
|
|
Style = Literal["colwise", "colwise_rep", "rowwise", "rowwise_rep", "replicate"]
|
|
|
|
|
|
def replace_linear_class(
|
|
linear: nn.Linear,
|
|
style: Style = "replicate",
|
|
quant_config: QuantizationConfig | None = None,
|
|
*,
|
|
prefix: str = "",
|
|
) -> ColumnParallelLinear | RowParallelLinear | ReplicatedLinear:
|
|
"""
|
|
Replace nn.Linear with one of vLLM's tensor parallel linear classes.
|
|
|
|
Args:
|
|
linear: `nn.Linear` to be replaced.
|
|
style: Tensor parallel style of the new linear, e.g. "colwise".
|
|
quant_config: Quantization config for the new linear.
|
|
Returns:
|
|
The new linear.
|
|
"""
|
|
|
|
if not isinstance(style, str):
|
|
raise ValueError(f"Unsupported parallel style type {type(style)}, expected str")
|
|
|
|
vllm_linear_maps = {
|
|
"colwise": (ColumnParallelLinear, {}),
|
|
"colwise_rep": (ColumnParallelLinear, {"gather_output": True}),
|
|
"rowwise": (RowParallelLinear, {}),
|
|
"rowwise_rep": (RowParallelLinear, {"input_is_parallel": False}),
|
|
"replicate": (ReplicatedLinear, {}),
|
|
}
|
|
vllm_linear_cls, vllm_linear_kwargs = vllm_linear_maps[style]
|
|
|
|
return vllm_linear_cls(
|
|
input_size=linear.in_features,
|
|
output_size=linear.out_features,
|
|
bias=linear.bias is not None,
|
|
quant_config=quant_config,
|
|
prefix=prefix,
|
|
return_bias=False,
|
|
**vllm_linear_kwargs,
|
|
)
|
|
|
|
|
|
def recursive_replace_linear(model: nn.Module, od_config: OmniDiffusionConfig):
|
|
"""Recursively replace modules in the model as needed.
|
|
Currently, this replaces:
|
|
- `nn.Linear` with vLLM's tensor parallel linear classes
|
|
"""
|
|
# Prefix the patterns because we always start from `self.model`
|
|
quant_config = build_quant_config(od_config.quantization_config)
|
|
|
|
def _recursive_replace(module: nn.Module, prefix: str):
|
|
for child_name, child_module in module.named_children():
|
|
new_module = child_module
|
|
qual_name = maybe_prefix(prefix, child_name)
|
|
# Replace modules as needed
|
|
if isinstance(child_module, nn.Linear):
|
|
style = "replicate"
|
|
new_module = replace_linear_class(child_module, style, quant_config, prefix=qual_name)
|
|
else:
|
|
_recursive_replace(child_module, prefix=qual_name)
|
|
if new_module is not child_module:
|
|
setattr(module, child_name, new_module)
|
|
|
|
_recursive_replace(model, prefix="")
|
|
|
|
|
|
def init_parameters(
|
|
module: nn.Module,
|
|
dtype: torch.dtype | None,
|
|
device: torch.device | None = None,
|
|
):
|
|
for name, param in module.named_parameters(recurse=False):
|
|
if param.device == torch.device("meta"):
|
|
new_param = nn.Parameter(
|
|
torch.empty_like(
|
|
param.data,
|
|
dtype=dtype,
|
|
device=device,
|
|
),
|
|
requires_grad=param.requires_grad,
|
|
)
|
|
setattr(module, name, new_param)
|
|
for child in module.children():
|
|
init_parameters(child, dtype, device)
|
|
|
|
|
|
def create_transformers_model(
|
|
auto_cls: _BaseAutoModelClass,
|
|
od_config: OmniDiffusionConfig,
|
|
hf_config: PretrainedConfig,
|
|
dtype: torch.dtype | None = None,
|
|
device: torch.device | None = None,
|
|
) -> PreTrainedModel:
|
|
"""Create a HuggingFace model using the given auto class and model name."""
|
|
dtype = dtype or od_config.dtype
|
|
device = device or torch.get_default_device()
|
|
with init_on_device_without_buffers("meta"):
|
|
model = auto_cls.from_config(hf_config)
|
|
recursive_replace_linear(model, od_config)
|
|
init_parameters(model, dtype=dtype, device=device)
|
|
return model
|
|
|
|
|
|
def _load_json(model_path: str, filename: str, local_files_only: bool = True) -> dict:
|
|
"""Load a JSON config file from a local path or HuggingFace Hub repo."""
|
|
if local_files_only:
|
|
path = os.path.join(model_path, *filename.split("/"))
|
|
with open(path) as f:
|
|
return json.load(f)
|
|
else:
|
|
from huggingface_hub import hf_hub_download
|
|
|
|
cached = hf_hub_download(repo_id=model_path, filename=filename)
|
|
with open(cached) as f:
|
|
return json.load(f)
|