325 lines
13 KiB
Python
325 lines
13 KiB
Python
|
|
import numbers
|
|||
|
|
from typing import Union
|
|||
|
|
|
|||
|
|
import ixformer._C as ops
|
|||
|
|
import torch
|
|||
|
|
from torch.nn import init
|
|||
|
|
from torch.nn.parameter import Parameter
|
|||
|
|
|
|||
|
|
|
|||
|
|
# apex interface for trainning add by xuelu.peng 2024/04/07
|
|||
|
|
class FusedRMSNormAffineFunction(torch.autograd.Function):
|
|||
|
|
@staticmethod
|
|||
|
|
def forward(ctx, input, weight, normalized_shape, eps, memory_efficient=False, gradient_accumulation_fusion=False):
|
|||
|
|
ctx.normalized_shape = normalized_shape
|
|||
|
|
ctx.eps = eps
|
|||
|
|
ctx.memory_efficient = memory_efficient
|
|||
|
|
ctx.gradient_accumulation_fusion = gradient_accumulation_fusion
|
|||
|
|
|
|||
|
|
input_ = input.contiguous()
|
|||
|
|
weight_ = weight.contiguous()
|
|||
|
|
output = torch.empty_like(input_)
|
|||
|
|
normalized_shape_size = len(normalized_shape)
|
|||
|
|
assert normalized_shape_size == 1 # 目前只支持normalized_shape_size=1
|
|||
|
|
invvar = torch.empty(
|
|||
|
|
input_.shape[:-normalized_shape_size],
|
|||
|
|
dtype=torch.float,
|
|||
|
|
device=input_.device,
|
|||
|
|
)
|
|||
|
|
ops.train.rms_norm_forward_training(input_, weight_, output, invvar, ctx.eps)
|
|||
|
|
|
|||
|
|
ctx.save_for_backward(input_, weight_, invvar)
|
|||
|
|
return output
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def backward(ctx, grad_output):
|
|||
|
|
input_, weight_, invvar = ctx.saved_tensors
|
|||
|
|
|
|||
|
|
if ctx.gradient_accumulation_fusion:
|
|||
|
|
if weight_.grad == None:
|
|||
|
|
weight_.grad = torch.zeros_like(weight_)
|
|||
|
|
grad_weight = weight_.grad
|
|||
|
|
else:
|
|||
|
|
grad_weight = torch.zeros_like(weight_) # 支持权重梯度累积融合,使用zeros_like,而不是emtpy_like 。
|
|||
|
|
|
|||
|
|
grad_input = torch.empty_like(input_)
|
|||
|
|
|
|||
|
|
if input_.numel() < 4096 * 8192:
|
|||
|
|
ops.train.rms_norm_backward_training(
|
|||
|
|
input_, invvar, weight_, grad_output, grad_weight, grad_input
|
|||
|
|
)
|
|||
|
|
else: ##llama 34b
|
|||
|
|
ops.train.rms_norm_backward_training_opt(
|
|||
|
|
input_, invvar, weight_, grad_output, grad_weight, grad_input
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if ctx.gradient_accumulation_fusion:
|
|||
|
|
grad_weight = None
|
|||
|
|
return grad_input, grad_weight, None, None, None, None
|
|||
|
|
def fused_rms_norm_affine(
|
|||
|
|
input, weight, normalized_shape, eps=1e-6, memory_efficient=False, gradient_accumulation_fusion = False
|
|||
|
|
):
|
|||
|
|
return FusedRMSNormAffineFunction.apply(
|
|||
|
|
input, weight, normalized_shape, eps, memory_efficient, gradient_accumulation_fusion
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FusedRMSNorm(torch.nn.Module):
|
|||
|
|
r"""Applies RMS Normalization over a mini-batch of inputs
|
|||
|
|
|
|||
|
|
Currently only runs on cuda() tensors.
|
|||
|
|
|
|||
|
|
.. math::
|
|||
|
|
y = \frac{x}{\mathrm{RMS}[x]} * \gamma
|
|||
|
|
|
|||
|
|
The root-mean-square is calculated separately over the last
|
|||
|
|
certain number dimensions which have to be of the shape specified by
|
|||
|
|
:attr:`normalized_shape`.
|
|||
|
|
:math:`\gamma` is a learnable affine transform parameter of
|
|||
|
|
:attr:`normalized_shape` if :attr:`elementwise_affine` is ``True``.
|
|||
|
|
`epsilon` is added to the mean-square, then the root of the sum is taken.
|
|||
|
|
|
|||
|
|
.. note::
|
|||
|
|
Unlike Batch Normalization and Instance Normalization, which applies
|
|||
|
|
scalar scale and bias for each entire channel/plane with the
|
|||
|
|
:attr:`affine` option, RMS Normalization applies per-element scale
|
|||
|
|
with :attr:`elementwise_affine`.
|
|||
|
|
|
|||
|
|
This layer uses statistics computed from input data in both training and
|
|||
|
|
evaluation modes.
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
normalized_shape (int or list or torch.Size): input shape from an expected input
|
|||
|
|
of size
|
|||
|
|
|
|||
|
|
.. math::
|
|||
|
|
[* \times \text{normalized}\_\text{shape}[0] \times \text{normalized}\_\text{shape}[1]
|
|||
|
|
\times \ldots \times \text{normalized}\_\text{shape}[-1]]
|
|||
|
|
|
|||
|
|
If a single integer is used, it is treated as a singleton list, and this module will
|
|||
|
|
normalize over the last dimension which is expected to be of that specific size.
|
|||
|
|
eps: a value added to the denominator for numerical stability. Default: 1e-5
|
|||
|
|
elementwise_affine: a boolean value that when set to ``True``, this module
|
|||
|
|
has learnable per-element affine parameters initialized to ones (for weights)
|
|||
|
|
and zeros (for biases). Default: ``True``.
|
|||
|
|
|
|||
|
|
Shape:
|
|||
|
|
- Input: :math:`(N, *)`
|
|||
|
|
- Output: :math:`(N, *)` (same shape as input)
|
|||
|
|
|
|||
|
|
Examples::
|
|||
|
|
|
|||
|
|
>>> input = torch.randn(20, 5, 10, 10)
|
|||
|
|
>>> # With Learnable Parameters
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(10)
|
|||
|
|
>>> # Without Learnable Parameters
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(input.size()[1:], elementwise_affine=False)
|
|||
|
|
>>> # Normalize over last dimension of size 10 #目前只支持在最后一维norm
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(10)
|
|||
|
|
>>> # Activating the module
|
|||
|
|
>>> output = m(input)
|
|||
|
|
|
|||
|
|
.. _`Root Mean Square Layer Normalization`: https://arxiv.org/pdf/1910.07467.pdf
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(
|
|||
|
|
self,
|
|||
|
|
normalized_shape,
|
|||
|
|
eps=1e-5,
|
|||
|
|
elementwise_affine=True,
|
|||
|
|
memory_efficient=False,
|
|||
|
|
gradient_accumulation_fusion=False
|
|||
|
|
):
|
|||
|
|
super().__init__()
|
|||
|
|
|
|||
|
|
if isinstance(normalized_shape, numbers.Integral):
|
|||
|
|
normalized_shape = (normalized_shape,)
|
|||
|
|
self.normalized_shape = torch.Size(normalized_shape)
|
|||
|
|
self.eps = eps
|
|||
|
|
self.elementwise_affine = elementwise_affine
|
|||
|
|
self.memory_efficient = memory_efficient
|
|||
|
|
self.gradient_accumulation_fusion = gradient_accumulation_fusion
|
|||
|
|
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
self.weight = Parameter(torch.empty(*normalized_shape))
|
|||
|
|
else:
|
|||
|
|
self.register_parameter("weight", None)
|
|||
|
|
self.reset_parameters()
|
|||
|
|
|
|||
|
|
def reset_parameters(self):
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
init.ones_(self.weight)
|
|||
|
|
|
|||
|
|
def forward(self, input):
|
|||
|
|
if torch.jit.is_tracing() or torch.jit.is_scripting() or not input.is_cuda:
|
|||
|
|
raise NotImplementedError()
|
|||
|
|
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
return fused_rms_norm_affine(
|
|||
|
|
input,
|
|||
|
|
self.weight,
|
|||
|
|
self.normalized_shape,
|
|||
|
|
self.eps,
|
|||
|
|
self.memory_efficient,
|
|||
|
|
self.gradient_accumulation_fusion
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
raise NotImplementedError()
|
|||
|
|
|
|||
|
|
def extra_repr(self):
|
|||
|
|
return "{normalized_shape}, eps={eps}, " "elementwise_affine={elementwise_affine}".format(**self.__dict__)
|
|||
|
|
|
|||
|
|
class FusedRMSNormResFunction(torch.autograd.Function):
|
|||
|
|
@staticmethod
|
|||
|
|
def forward(ctx, input, weight, residual, normalized_shape, eps, gradient_accumulation_fusion=False, memory_efficient=False):
|
|||
|
|
ctx.normalized_shape = normalized_shape
|
|||
|
|
ctx.eps = eps
|
|||
|
|
ctx.memory_efficient = memory_efficient
|
|||
|
|
ctx.gradient_accumulation_fusion = gradient_accumulation_fusion
|
|||
|
|
|
|||
|
|
input_ = input.contiguous()
|
|||
|
|
weight_ = weight.contiguous()
|
|||
|
|
output = torch.empty_like(input_)
|
|||
|
|
normalized_shape_size=len(normalized_shape)
|
|||
|
|
assert normalized_shape_size == 1 #目前只支持normalized_shape_size=1
|
|||
|
|
invvar = torch.empty(input_.shape[:-normalized_shape_size], dtype=torch.float, device=input_.device)
|
|||
|
|
|
|||
|
|
if residual is not None:
|
|||
|
|
ctx.input_res = True
|
|||
|
|
out_res = torch.empty_like(input_)
|
|||
|
|
ops.train.rms_norm_res_forward_training(input_, weight_, output, invvar, ctx.eps, residual, out_res)
|
|||
|
|
else:
|
|||
|
|
ctx.input_res = False
|
|||
|
|
ops.train.rms_norm_forward_training(input_, weight_, output, invvar, ctx.eps)
|
|||
|
|
out_res = input_
|
|||
|
|
|
|||
|
|
# input_res 为 True 时 LN 的 input 为 input+redidual
|
|||
|
|
ctx.save_for_backward(out_res, weight_, invvar)
|
|||
|
|
return output, out_res
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def backward(ctx, grad_output, grad_out_res):
|
|||
|
|
input_, weight_, invvar = ctx.saved_tensors
|
|||
|
|
|
|||
|
|
if ctx.gradient_accumulation_fusion:
|
|||
|
|
if weight_.grad == None:
|
|||
|
|
weight_.grad = torch.zeros_like(weight_)
|
|||
|
|
grad_weight = weight_.grad
|
|||
|
|
else:
|
|||
|
|
grad_weight = torch.zeros_like(weight_) # 算子kernel 支持权重梯度累积融合,使用zeros_like,而不是emtpy_like 。
|
|||
|
|
|
|||
|
|
grad_input = torch.empty_like(input_)
|
|||
|
|
|
|||
|
|
# rms_norm_res_backward_training 本身支持权重梯度累积融合,当不进行融合时,其输入 grad_weight 必须为 zero_like 。
|
|||
|
|
if input_.numel()< 4096*8192:
|
|||
|
|
ops.train.rms_norm_res_backward_training(input_, invvar, weight_,
|
|||
|
|
grad_output, grad_weight, grad_input, grad_out_res)
|
|||
|
|
else:##llama 34b
|
|||
|
|
ops.train.rms_norm_res_backward_training_opt(input_,invvar, weight_,
|
|||
|
|
grad_output,grad_weight,grad_input,grad_out_res)
|
|||
|
|
|
|||
|
|
if ctx.input_res:
|
|||
|
|
grad_res = grad_input
|
|||
|
|
else:
|
|||
|
|
grad_res = None
|
|||
|
|
|
|||
|
|
if ctx.gradient_accumulation_fusion:
|
|||
|
|
grad_weight = None
|
|||
|
|
|
|||
|
|
return grad_input, grad_weight, grad_res, None, None, None, None
|
|||
|
|
|
|||
|
|
class FusedRMSNormRes(torch.nn.Module):
|
|||
|
|
r"""Applies RMS Normalization and resdiual over a mini-batch of inputs, RMS Normalization part comes from FusedRMSNorm.
|
|||
|
|
|
|||
|
|
Currently only runs on cuda() tensors.
|
|||
|
|
|
|||
|
|
.. math::
|
|||
|
|
y = \frac{x}{\mathrm{RMS}[x]} * \gamma
|
|||
|
|
|
|||
|
|
if residual None, x is input and output is equal to x, otherwise, x is input+residual and out_res is equal to x.
|
|||
|
|
|
|||
|
|
The root-mean-square is calculated separately over the last
|
|||
|
|
certain number dimensions which have to be of the shape specified by
|
|||
|
|
:attr:`normalized_shape`.
|
|||
|
|
:math:`\gamma` is a learnable affine transform parameter of
|
|||
|
|
:attr:`normalized_shape` if :attr:`elementwise_affine` is ``True``.
|
|||
|
|
`epsilon` is added to the mean-square, then the root of the sum is taken.
|
|||
|
|
|
|||
|
|
.. note::
|
|||
|
|
Unlike Batch Normalization and Instance Normalization, which applies
|
|||
|
|
scalar scale and bias for each entire channel/plane with the
|
|||
|
|
:attr:`affine` option, RMS Normalization applies per-element scale
|
|||
|
|
with :attr:`elementwise_affine`.
|
|||
|
|
|
|||
|
|
This layer uses statistics computed from input data in both training and
|
|||
|
|
evaluation modes.
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
normalized_shape (int or list or torch.Size): input shape from an expected input
|
|||
|
|
of size
|
|||
|
|
|
|||
|
|
.. math::
|
|||
|
|
[* \times \text{normalized}\_\text{shape}[0] \times \text{normalized}\_\text{shape}[1]
|
|||
|
|
\times \ldots \times \text{normalized}\_\text{shape}[-1]]
|
|||
|
|
|
|||
|
|
If a single integer is used, it is treated as a singleton list, and this module will
|
|||
|
|
normalize over the last dimension which is expected to be of that specific size.
|
|||
|
|
eps: a value added to the denominator for numerical stability. Default: 1e-5
|
|||
|
|
elementwise_affine: a boolean value that when set to ``True``, this module
|
|||
|
|
has learnable per-element affine parameters initialized to ones (for weights)
|
|||
|
|
and zeros (for biases). Default: ``True``.
|
|||
|
|
|
|||
|
|
Shape:
|
|||
|
|
- Input: :math:`(N, *)`
|
|||
|
|
- residual: :math:`(N, *)` (if not None)
|
|||
|
|
- Output: :math:`(N, *)` (same shape as input)
|
|||
|
|
- out_res: :math:`(N, *)`
|
|||
|
|
|
|||
|
|
Examples::
|
|||
|
|
|
|||
|
|
>>> input = torch.randn(20, 5, 10, 10)
|
|||
|
|
>>> res = torch.randn(20, 5, 10, 10)
|
|||
|
|
>>> # With Learnable Parameters
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(10)
|
|||
|
|
>>> # Without Learnable Parameters
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(input.size()[1:], elementwise_affine=False)
|
|||
|
|
>>> # Normalize over last dimension of size 10 #目前只支持在最后一维norm
|
|||
|
|
>>> m = ixformer.FusedRMSNorm(10)
|
|||
|
|
>>> # Activating the module
|
|||
|
|
>>> output, output_res = m(input, res)
|
|||
|
|
|
|||
|
|
.. _`Root Mean Square Layer Normalization`: https://arxiv.org/pdf/1910.07467.pdf
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self, normalized_shape, eps=1e-5, elementwise_affine=True, memory_efficient=False, gradient_accumulation_fusion=False):
|
|||
|
|
super().__init__()
|
|||
|
|
|
|||
|
|
if isinstance(normalized_shape, numbers.Integral):
|
|||
|
|
normalized_shape = (normalized_shape,)
|
|||
|
|
self.normalized_shape = torch.Size(normalized_shape)
|
|||
|
|
self.eps = eps
|
|||
|
|
self.elementwise_affine = elementwise_affine
|
|||
|
|
self.gradient_accumulation_fusion = gradient_accumulation_fusion
|
|||
|
|
self.memory_efficient = memory_efficient
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
self.weight = Parameter(torch.empty(*normalized_shape))
|
|||
|
|
else:
|
|||
|
|
self.register_parameter("weight", None)
|
|||
|
|
self.reset_parameters()
|
|||
|
|
|
|||
|
|
def reset_parameters(self):
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
init.ones_(self.weight)
|
|||
|
|
|
|||
|
|
def forward(self, input, residual=None):
|
|||
|
|
if torch.jit.is_tracing() or torch.jit.is_scripting() or not input.is_cuda:
|
|||
|
|
raise NotImplementedError()
|
|||
|
|
|
|||
|
|
if self.elementwise_affine:
|
|||
|
|
return FusedRMSNormResFunction.apply(input, self.weight, residual, self.normalized_shape, self.eps, self.gradient_accumulation_fusion, self.memory_efficient)
|
|||
|
|
else:
|
|||
|
|
raise NotImplementedError()
|
|||
|
|
|
|||
|
|
def extra_repr(self):
|
|||
|
|
return "{normalized_shape}, eps={eps}, " "elementwise_affine={elementwise_affine}".format(**self.__dict__)
|