Files
2026-07-13 13:18:33 +08:00

116 lines
4.0 KiB
Python

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
import torch
from ...model_implementations.parameter_base import ParameterBase
"""
Common QKV Parameter Patterns
"""
class FusedQKVParameter(ParameterBase):
"""
Traditional fused QKV parameters for QKV projection. This is functionally
a direct copy.
src_qkv_w shape: [3 * out_features, in_features]
qkv_w shape: [3 * out_features, in_features]
"""
params: torch.Tensor
def finalize(self) -> torch.Tensor:
return self.inference_model.transform_qkv_param(self.params)
class UnfusedQKVParameter(ParameterBase):
"""
QKV parameter container for unfused QKV projection.
src_param shapes: 3 x [out_features, in_features]
dst_param shape: [3 x out_features, in_features]
"""
q_params: torch.Tensor
k_params: torch.Tensor
v_params: torch.Tensor
def finalize(self):
fused_param = torch.cat([self.q_params, self.k_params, self.v_params], dim=0)
return self.inference_model.transform_qkv_param(fused_param)
def megatron_qkv_reshape(param: torch.Tensor, head_size: int, n_heads: int) -> torch.Tensor:
assert param.shape[0] == 3 * n_heads * head_size
all_heads = torch.chunk(param, chunks=3 * n_heads, dim=0)
q_heads = all_heads[::3]
k_heads = all_heads[1::3]
v_heads = all_heads[2::3]
return torch.cat([q_heads, k_heads, v_heads], dim=0)
class MegatronQKVParameter(ParameterBase):
"""
QKV parameter container for Megatron-style QKV projection. Megatron stores the parameter
as [n_heads, 3, head_size, in_features] whereas our inference system is built around
[3, n_heads, head_size, in_features]. This container handles the conversion.
Note: this container expects the model implementation to implement properties for
`head_size` and `n_heads`.
src_qkv_w shape: [3 * out_features, in_features]
qkv_w shape: [3 * out_features, in_features]
"""
params: torch.Tensor
def finalize(self) -> torch.Tensor:
head_size = self.inference_model.head_size
n_heads = self.inference_model.n_heads
transposed_param = megatron_qkv_reshape(self.params, head_size, n_heads)
return self.inference_model.transform_qkv_param(transposed_param)
def transform_gqa_megatron(src_param: torch.Tensor, head_size: int, n_q_heads: int, n_kv_heads: int) -> torch.Tensor:
assert src_param.shape[0] == (2 * n_kv_heads + n_q_heads) * head_size
head_ratio = n_q_heads // n_kv_heads
# Reshape to get the groups as the leading dimension
groups_leading_view = src_param.reshape(n_kv_heads, 2 + head_ratio, head_size, -1)
q_heads = groups_leading_view[:, :head_ratio, :, :].reshape(-1, groups_leading_view.shape[-1])
k_heads = groups_leading_view[:, head_ratio, :, :].reshape(-1, groups_leading_view.shape[-1])
v_heads = groups_leading_view[:, head_ratio + 1, :, :].reshape(-1, groups_leading_view.shape[-1])
# Squeeze will remove extra dimension for bias
return torch.cat([q_heads, k_heads, v_heads], dim=0).squeeze()
class GQAMegatronQKVParameter(ParameterBase):
"""
QKV parameter for Megatron-style QKV projection with GQA-style QKV projection. In this
storage format each of the groups is stored consecutively, so there will be multiple q_heads,
then one k head, and one v head.
Note: this container expects the model implementation to implement properties for
`head_size`, `n_q_heads`, and `n_kv_heads`.
src_qkv_w shape: [(2 * n_kv_heads + n_q_heads) * head_size, in_features]
qkv_w shape: [(2 * n_kv_heads + n_q_heads) * head_size, in_features]
"""
params: torch.Tensor
def finalize(self) -> torch.Tensor:
head_size = self.inference_model.head_size
n_q_heads = self.inference_model.n_heads_q
n_kv_heads = self.inference_model.n_heads_kv
transposed_param = transform_gqa_megatron(self.params, head_size, n_q_heads, n_kv_heads)
return self.inference_model.transform_qkv_param(transposed_param)