MindSpeed介绍

MindSpeed 是针对华为昇腾设备的大模型加速库。

大模型训练是一种非常复杂的过程,涉及到许多技术和挑战,其中大模型训练需要大量的显存资源是一个难题,对计算卡提出了不小的挑战。 为了在单个计算卡显存资源不足时,可以通过多张计算卡进行计算,业界出现了类似 Megatron、DeepSpeed 等第三方大模型加速库,对模型、输入数据等进行切分并分配到不同的计算卡上,最后再通过集合通信对结果进行汇总。

昇腾提供 MindSpeed 加速库,使能客户大模型业务快速迁移至昇腾设备,并且支持昇腾专有算法,确保开箱可用。

参考链接:https://gitee.com/ascend/MindSpeed/tree/master

MindSpeed目录介绍:
MindSpeed/

├── ci/ # 门禁执行

├── docs/ # 相关文档

│ ├── features/ #特性相关

│ ├── ops/ #算子相关

├── mindspeed/ #特性放置及使能

│ ├── core/ #性能优化相关特性

│ ├── model/ # 数据集相关

│ ├── moe/ #moe相关

│ ├── ops/ # 自定义算子

│ ├── optimizer/ # 优化器相关特性

│ ├── tokenizer/ # 处理tokenizer相关特性

│ ├── arguments.py #特性使能相关参数

│ ├── megatron_adaptor.py #特性调用

├── tests_extend/ #特性相关UT

│ ├── model_tests/ # 模型测试

│ ├── system_tests/ #模型训练系统测试

│ ├── unit_tests/ #特性UT

├── setup.py #编译安装

MindSpeed特性开发流程

这里以特性fused_swiglu为例,介绍开发流程。

特性分析

在megatron中,MLP部分不同场景下使用了不同的激活函数,swiglu是多数场景下使用的激活函数,以下为megatron部分代码。昇腾提供了swiglu的融合算子,现在要将该融合算子作为特性添加到mindspeed上。

class ParallelMLP(MegatronModule):
    """MLP.

    MLP will take the input with h hidden state, project it to 4*h
    hidden dimension, perform nonlinear transformation, and project the
    state back into h hidden dimension.
    """

    def __init__(self, config, is_expert=False):
        super(ParallelMLP, self).__init__()
        args = get_args()

        self.add_bias = config.add_bias_linear

        ffn_hidden_size = config.ffn_hidden_size
        if config.gated_linear_unit:
            ffn_hidden_size *= 2

        # Project to 4h. If using swiglu double the output width, see https://arxiv.org/pdf/2002.05202.pdf
        self.dense_h_to_4h = tensor_parallel.ColumnParallelLinear(
            config.hidden_size,
            ffn_hidden_size,
            config=config,
            init_method=config.init_method,
            bias=self.add_bias,
            gather_output=False,
            skip_bias_add=True,
            is_expert=is_expert,
        )

        self.bias_gelu_fusion = False
        self.activation_func = None
        self.swiglu = args.swiglu

        if args.openai_gelu:
            self.activation_func = openai_gelu
        elif args.onnx_safe:
            self.activation_func = erf_gelu
        elif args.swiglu:
            def swiglu(x):
                x = torch.chunk(x, 2, dim=-1)
                return F.silu(x[0]) * x[1]
            self.activation_func = swiglu
        elif args.squared_relu:
            def squared_relu(x):
                return torch.pow(F.relu(x), 2)
            self.activation_func = squared_relu
        else:
            self.bias_gelu_fusion = args.bias_gelu_fusion
            self.activation_func = F.gelu

特性开发

为了不侵入式修改megatron,这里以patch的方式添加fused_swiglu特性。patch内容如下,位置为mindspeed/model/transformer.py

def parallel_mlp_init_wrapper(fn):
    @wraps(fn)
    def wrapper(self, *args, **kwargs):
        fn(self, *args, **kwargs)
        self.layer_number = None
        args = get_args()
        if args.swiglu and args.use_fused_swiglu:
            self.activation_func = fused_swiglu
    return wrapper

其中fusedz_swiglu定义位置为mindspeed/core/fusions/fused_bias_swiglu.py

def fused_swiglu(x):
    return torch_npu.npu_swiglu(x, dim=-1)

在开发完patch后需要提供参数进行控制,代码片段如下,位置为mindspeed/arguments.py

def _add_network_size_args(parser):
    group = parser.add_argument_group(title='network size')
    group.add_argument("--use-fused-rmsnorm", action='store_true',
                       help="Use fused rmsnorm.")
    group.add_argument("--use-fused-swiglu", action='store_true',
                       help="Use fused swiglu.")
    group.add_argument("--use-fused-rotary-pos-emb", action='store_true',
                       help="Use fused rotary-pos-emb.")

特性使能

在完成特性开发后,需要使能特性,这里以调用patch的方式实现,代码片段如下,位置为

def megatron_legacy_adaptation(aspm):
    from .core.fusions.fused_layer_norm import FusedLayerNormAffineFunction, FastLayerNormFN, fused_layer_norm_affine
    from .core.fusions.fused_softmax import is_kernel_available, ScaledUpperTriangMaskedSoftmax, ScaledMaskedSoftmax, \
        ScaledSoftmax, forward_fused_softmax
    from .core.fusions.rms_norm import rms_norm_init_wrapper, rms_norm_forward_wrapper
    from .model.transformer import parallel_mlp_init_wrapper, flash_self_attention_forward, flash_self_attention_init_wrapper, parallel_mlp_forward_wrapper, parallel_transformer_init_wrapper, \
        parallel_transformer_forward_wrapper


aspm.register_patch('megatron.legacy.model.transformer.ParallelMLP.__init__', parallel_mlp_init_wrapper)

特性UT

为了验证,看护该特性,需要提供该特性UT,以下为代码,位置为tests_extend/unit_tests/ops/cann/test_npu_swiglu.py

import pytest
import torch
import torch_npu
from mindspeed import megatron_adaptor
from megatron.legacy.model.transformer import ParallelMLP
from unit_tests.common import DistributedTest
from commons import initialize_model_parallel
from megatron.training.global_vars import set_args
from megatron.training.arguments import parse_args
from megatron.core.tensor_parallel.random import model_parallel_cuda_manual_seed
from megatron.core.transformer.transformer_config import TransformerConfig

DEVICE_NAME = torch_npu.npu.get_device_name(0)[:10]


def create_test_args(swiglu=True, use_fused_swiglu=False):
    args = parse_args(None, True)
    args.swiglu = swiglu
    args.use_fused_swiglu = use_fused_swiglu
    return args


class TestNpuSwiglu(DistributedTest):
    world_size = 1

    def patch_ori_op_exec(self, hidden_states):
        args = create_test_args(True, False)
        set_args(args)
        model_parallel_cuda_manual_seed(123)
        self.patch_ori_mlp = ParallelMLP(self.transformer_config).npu().to(hidden_states.dtype)
        hidden_states, output_bias = self.patch_ori_mlp(hidden_states)
        return hidden_states

    def patch_fused_op_exec(self, hidden_states):
        args = create_test_args(True, True)
        set_args(args)
        model_parallel_cuda_manual_seed(123)
        self.patch_fused_mlp = ParallelMLP(self.transformer_config).npu().to(hidden_states.dtype)
        hidden_states, output_bias = self.patch_fused_mlp(hidden_states)
        return hidden_states

    @pytest.mark.skipif(DEVICE_NAME != 'Ascend910B', reason='device type is not supported, skip this UT!')
    @pytest.mark.parametrize('dtype', [torch.float16, torch.bfloat16])
    def test_npu_swiglu(self, dtype):
        args = parse_args(None, True)
        set_args(args)
        sequence_length, batch_size, hidden_size = 32, 2, 12
        initialize_model_parallel(1, 1)
        self.transformer_config = TransformerConfig(num_layers=2, hidden_size=hidden_size, num_attention_heads=4,
                                                    use_cpu_initialization=False, gated_linear_unit=True)
        hidden_states = torch.randn((sequence_length, batch_size, hidden_size)).npu().to(dtype)
        output_patch_ori = self.patch_ori_op_exec(hidden_states)
        output_patch_fused = self.patch_fused_op_exec(hidden_states)
        tol = 0.004 if dtype == torch.bfloat16 else 0.001
        assert torch.allclose(output_patch_ori, output_patch_fused, rtol=tol, atol=tol)

特性上库

完成自验后就可以提交上库了,按照上文中特性开发对应的位置进行上库,由mindspeed的commiter进行代码检视、合入。注意在PR中将自己的自验结果展示。

Logo

昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链

更多推荐