# Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 # DeepSpeed Team import math import torch import torch.nn as nn from deepspeed import comm as dist from deepspeed.utils.types import GATED_ACTIVATION_TYPES from deepspeed.accelerator import get_accelerator from .op_binding import MLPGemmOp, VectorMatMulOp, GELUGemmOp, ResidualAddOp class DeepSpeedMLP(nn.Module): _inter_w_buffers = [] def __init__(self, config, mp_group=None, q_scales=None, q_groups=1, merge_count=1, mlp_extra_grouping=False): super(DeepSpeedMLP, self).__init__() self.config = config data_type = torch.int8 if self.config.dtype == torch.int8 else self.config.dtype data_type_fp = torch.half if self.config.dtype == torch.int8 else self.config.dtype device = get_accelerator().current_device_name() proj_factor = 2 if self.config.mlp_act_func_type in GATED_ACTIVATION_TYPES else 1 self.config.intermediate_size = self.config.intermediate_size if self.config.intermediate_size > 0 else 4 * self.config.hidden_size self.intm_w_sz_per_partition = self.config.intermediate_size * proj_factor // self.config.mp_size self.intm_o_sz_per_partition = self.config.intermediate_size // self.config.mp_size if self.config.set_empty_params: self.attn_nw = None self.attn_nb = None self.inter_w = None self.inter_b = None self.inter_up_w = None self.inter_up_b = None self.inter_gate_w = None self.inter_gate_b = None self.output_w = None self.output_b = None else: self.attn_nw = nn.Parameter(torch.empty(self.config.hidden_size, dtype=data_type_fp, device=device), requires_grad=False) self.attn_nb = nn.Parameter(torch.empty(self.config.hidden_size, dtype=data_type_fp, device=device), requires_grad=False) self.inter_w = nn.Parameter(torch.empty(self.config.hidden_size, self.intm_w_sz_per_partition, dtype=data_type, device=device), requires_grad=False) self.inter_b = nn.Parameter(torch.empty(self.intm_w_sz_per_partition, dtype=data_type_fp, device=device), requires_grad=False) self.output_w = nn.Parameter(torch.empty(self.intm_o_sz_per_partition, self.config.hidden_size, dtype=data_type, device=device), requires_grad=False) self.output_b = nn.Parameter(torch.empty(self.config.hidden_size, dtype=data_type_fp, device=device), requires_grad=False) # used for quantization self.q_scales = q_scales self.q_groups = q_groups * 2 if mlp_extra_grouping else q_groups self.merge_count = int(math.log2(merge_count)) self.mp_group = mp_group self.mlp_gemm_func = MLPGemmOp(config) self.vector_matmul_func = VectorMatMulOp(config) self.fused_gemm_gelu = GELUGemmOp(config) self.residual_add_func = ResidualAddOp(config) if len(DeepSpeedMLP._inter_w_buffers) == 0: DeepSpeedMLP._inter_w_buffers = [ torch.empty(self.intm_w_sz_per_partition, self.config.hidden_size, dtype=data_type, device=device), torch.empty(self.intm_w_sz_per_partition, dtype=data_type_fp, device=device) ] def _merge_inter_w(self): inter_w = DeepSpeedMLP._inter_w_buffers[0] inter_w[:self.intm_w_sz_per_partition // 2, :] = self.inter_up_w # type: ignore inter_w[self.intm_w_sz_per_partition // 2:, :] = self.inter_gate_w # type: ignore if self.inter_up_b is not None: inter_b = DeepSpeedMLP._inter_w_buffers[1] inter_b[:self.intm_w_sz_per_partition // 2] = self.inter_up_b # type: ignore inter_b[self.intm_w_sz_per_partition // 2:] = self.inter_gate_b # type: ignore return DeepSpeedMLP._inter_w_buffers def forward(self, input, residual, residual_norm, bias): if self.inter_w is None: self._inter_w, self._inter_b = self._merge_inter_w() else: self._inter_w = self.inter_w self._inter_b = self.inter_b residual_add = None if self.attn_nw is None: output = self.fused_gemm_gelu(input=residual_norm, weight=self._inter_w, bias=self._inter_b, weight_out=self.output_w) else: output, residual_add = self.mlp_gemm_func(input=input, residual=residual, weight_interm=self._inter_w, weight_out=self.output_w, input_bias=bias, bias=self._inter_b, gamma=self.attn_nw, beta=self.attn_nb) residual = self.residual_add_func(hidden_state=output, residual=residual, add_bias=bias is not None, attention_output=input, attention_bias=bias if bias is not None else self.output_b, final_bias=self.output_b, residual_add=residual_add) if self.mp_group is not None and dist.get_world_size(group=self.mp_group) > 1: dist.all_reduce(residual, group=self.mp_group) return residual