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

104 lines
3.5 KiB
Python

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
from typing import Any, Dict, Optional
import torch
from deepspeed.accelerator import get_accelerator
from ....allocator import empty_from
from ....inference_utils import is_gated
from ....kernels.core_ops import (
BlasLibLinear,
CUDABiasActivation,
CUDAGatedActivation,
)
from ...interfaces import DSLinearBase, DSLinearRegistry
from ...configs import DSLinearConfig
from ....inference_parameter import InferenceParameter
@DSLinearRegistry.register_module
class BlasFPLinear(DSLinearBase):
"""
Linear DSModule based on BLAS library and standalone bias + activation kernel implementation.
"""
@staticmethod
def name():
return 'blas_fp_linear'
@staticmethod
def supports_config(config: DSLinearConfig) -> bool:
if config.input_dtype != config.output_dtype:
return False
if config.input_dtype != torch.float16 and config.input_dtype != torch.bfloat16:
return False
if is_gated(config.activation):
try:
_ = CUDAGatedActivation(config.out_channels, config.output_dtype, config.activation)
except ValueError:
return False
else:
try:
_ = CUDABiasActivation(config.out_channels, config.output_dtype, config.activation)
except ValueError:
return False
return True
def __init__(self, config: DSLinearConfig, implementation_config: Dict[str, Any]) -> None:
super().__init__(config, implementation_config)
self._linear_impl = BlasLibLinear(self._config.input_dtype)
if is_gated(config.activation):
self._is_gated = True
self._act_fn = CUDAGatedActivation(config.out_channels, config.output_dtype, config.activation)
self._double_buffer = torch.empty((config.max_tokens, config.out_channels * 2),
dtype=config.output_dtype,
device=get_accelerator().current_device())
else:
self._is_gated = False
self._act_fn = CUDABiasActivation(config.out_channels, config.output_dtype, config.activation)
self._output = torch.empty((config.max_tokens, config.out_channels),
dtype=config.output_dtype,
device=get_accelerator().current_device())
def transform_param(self, param: torch.Tensor) -> InferenceParameter:
"""
Converts param to same data type as input and output.
Parameters:
param (torch.Tensor): Weight or bias tensor.
"""
param = param.to(self._config.output_dtype)
return InferenceParameter.initialize(param)
def forward(self, hidden_states: torch.Tensor, w: torch.Tensor, b: Optional[torch.Tensor] = None) -> torch.Tensor:
output = empty_from(self._output, (hidden_states.shape[0], self._config.out_channels))
if self._is_gated:
staging_output = empty_from(self._double_buffer, (hidden_states.shape[0], self._config.out_channels * 2))
self._linear_impl(staging_output, hidden_states, w)
self._act_fn(output, staging_output, b)
else:
self._linear_impl(output, hidden_states, w)
self._act_fn(output, b)
return output
@property
def output(self) -> torch.Tensor:
"""
Return the padded, pre-allocated output Tensor.
"""
return self._output