chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .layer.fused_dropout_add import FusedDropoutAdd
|
||||
from .layer.fused_dropout_nd import FusedDropout # noqa: F401
|
||||
from .layer.fused_linear import FusedLinear
|
||||
from .layer.fused_transformer import (
|
||||
FusedBiasDropoutResidualLayerNorm,
|
||||
FusedFeedForward,
|
||||
FusedMultiHeadAttention,
|
||||
FusedMultiTransformer,
|
||||
FusedTransformerEncoderLayer,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'FusedMultiHeadAttention',
|
||||
'FusedFeedForward',
|
||||
'FusedTransformerEncoderLayer',
|
||||
'FusedMultiTransformer',
|
||||
'FusedLinear',
|
||||
'FusedBiasDropoutResidualLayerNorm',
|
||||
'FusedDropoutAdd',
|
||||
]
|
||||
@@ -0,0 +1,275 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# The following codes are from https://github.com/facebookresearch/xformers
|
||||
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class AttentionBias(ABC):
|
||||
@abstractmethod
|
||||
def materialize(self, shape, dtype=paddle.float32):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LowerTriangularMask(AttentionBias):
|
||||
def materialize(self, shape, dtype=paddle.float32):
|
||||
create_as = dtype if dtype is not paddle.bfloat16 else paddle.float32
|
||||
tensor = paddle.full(
|
||||
shape=shape, fill_value=float("-inf"), dtype=create_as
|
||||
)
|
||||
return paddle.triu(tensor, diagonal=1).astype(dtype)
|
||||
|
||||
def add_bias(self, bias):
|
||||
return LowerTriangularMaskWithTensorBias(bias)
|
||||
|
||||
|
||||
class LowerTriangularMaskWithTensorBias(LowerTriangularMask):
|
||||
def __init__(self, bias):
|
||||
self._bias = bias
|
||||
|
||||
def materialize(self, shape, dtype=paddle.float32):
|
||||
return super().materialize(shape, dtype) + self._bias
|
||||
|
||||
|
||||
@dataclass
|
||||
class SeqLenInfo:
|
||||
seqstart: paddle.Tensor
|
||||
max_seqlen: int
|
||||
seqstart_py: list[int]
|
||||
|
||||
def intervals(self):
|
||||
yield from zip(self.seqstart_py, self.seqstart_py[1:])
|
||||
|
||||
@classmethod
|
||||
def from_seqlens(cls, seqlens):
|
||||
seqstart_py = [0]
|
||||
max_seqlen = -1
|
||||
for seqlen in seqlens:
|
||||
max_seqlen = max(max_seqlen, seqlen)
|
||||
seqstart_py.append(seqstart_py[-1] + seqlen)
|
||||
seqstart = paddle.to_tensor(seqstart_py, dtype=paddle.int32)
|
||||
return cls(
|
||||
max_seqlen=max_seqlen, seqstart=seqstart, seqstart_py=seqstart_py
|
||||
)
|
||||
|
||||
def split(self, x, batch_sizes=None):
|
||||
assert self.seqstart_py[-1] == x.shape[1] and x.shape[0] == 1
|
||||
if batch_sizes is None:
|
||||
batch_sizes = [1] * (len(self.seqstart_py) - 1)
|
||||
split_chunks = []
|
||||
it = 0
|
||||
for batch_size in batch_sizes:
|
||||
split_chunks.append(
|
||||
self.seqstart_py[it + batch_size] - self.seqstart_py[it]
|
||||
)
|
||||
it += batch_size
|
||||
return [
|
||||
tensor.reshape([bs, -1, *tensor.shape[2:]])
|
||||
for bs, tensor in zip(batch_sizes, x.split(split_chunks, axis=1))
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PaddedSeqLenInfo(SeqLenInfo):
|
||||
seqlen: paddle.Tensor
|
||||
seqlen_py: Sequence[int]
|
||||
|
||||
def intervals(self):
|
||||
for (start, _), length in zip(super().intervals(), self.seqlen_py):
|
||||
yield start, start + length
|
||||
|
||||
@classmethod
|
||||
def from_seqlens(cls, seqlens):
|
||||
raise NotImplementedError(
|
||||
"Please use SeqLenInfo.from_seq_lens() or PaddedSeqLenInfo.from_seq_lens_padded()."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_seqlens_padded(cls, seqlens, padding):
|
||||
assert all(seqlen <= padding for seqlen in seqlens)
|
||||
seqstart_py = list(range(0, len(seqlens) * padding + 1, padding))
|
||||
return cls(
|
||||
seqlen=paddle.to_tensor(seqlens, dtype=paddle.int32),
|
||||
seqlen_py=seqlens,
|
||||
max_seqlen=max(seqlens),
|
||||
seqstart=paddle.to_tensor(seqstart_py, dtype=paddle.int32),
|
||||
seqstart_py=seqstart_py,
|
||||
)
|
||||
|
||||
def split(self, x, batch_sizes=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlockDiagonalMask(AttentionBias):
|
||||
q_seqinfo: SeqLenInfo
|
||||
k_seqinfo: SeqLenInfo
|
||||
_batch_sizes: Sequence[int] | None = None
|
||||
|
||||
def _create_block_mask(self, shape, dtype=paddle.float32):
|
||||
return paddle.zeros(shape=shape, dtype=dtype)
|
||||
|
||||
def materialize(self, shape, dtype=paddle.float32):
|
||||
assert shape[-1] == self.k_seqinfo.seqstart_py[-1]
|
||||
assert shape[-2] == self.q_seqinfo.seqstart_py[-1]
|
||||
mask = paddle.full(shape[-2:], fill_value=float('-inf'), dtype=dtype)
|
||||
for (q_start, q_end), (k_start, k_end) in zip(
|
||||
self.q_seqinfo.intervals(), self.k_seqinfo.intervals()
|
||||
):
|
||||
sub_shape = [q_end - q_start, k_end - k_start]
|
||||
mask[q_start:q_end, k_start:k_end] = self._create_block_mask(
|
||||
sub_shape, dtype
|
||||
)
|
||||
for _ in range(len(shape) - 2):
|
||||
mask = mask.unsqueeze(0)
|
||||
return mask.expand(shape)
|
||||
|
||||
@classmethod
|
||||
def from_seqlens(cls, q_seqlen, kv_seqlen=None):
|
||||
assert kv_seqlen is None or len(q_seqlen) == len(kv_seqlen)
|
||||
q_seqinfo = SeqLenInfo.from_seqlens(q_seqlen)
|
||||
if kv_seqlen is None or q_seqlen == kv_seqlen:
|
||||
k_seqinfo = q_seqinfo
|
||||
else:
|
||||
k_seqinfo = SeqLenInfo.from_seqlens(kv_seqlen)
|
||||
return cls(q_seqinfo=q_seqinfo, k_seqinfo=k_seqinfo)
|
||||
|
||||
@classmethod
|
||||
def from_tensor_list(cls, tensors):
|
||||
batch_sizes = [tensor.shape[0] for tensor in tensors]
|
||||
seqlens = []
|
||||
for x in tensors:
|
||||
for _ in range(x.shape[0]):
|
||||
seqlens.append(x.shape[1])
|
||||
block_diag = cls.from_seqlens(seqlens)
|
||||
block_diag._batch_sizes = batch_sizes
|
||||
concated_tensor = paddle.concat(
|
||||
[x.reshape([1, -1, *x.shape[2:]]) for x in tensors], axis=1
|
||||
)
|
||||
return block_diag, concated_tensor
|
||||
|
||||
@classmethod
|
||||
def from_tensor_lists_qkv(cls, tensors_q, tensors_k, tensors_v=None):
|
||||
assert len(tensors_q) == len(tensors_k)
|
||||
assert tensors_v is None or len(tensors_v) == len(tensors_q)
|
||||
batch_sizes = [tensor.shape[0] for tensor in tensors_q]
|
||||
q_seqlens, kv_seqlens = [], []
|
||||
for i, (q, k) in enumerate(zip(tensors_q, tensors_k)):
|
||||
assert q.shape[0] == k.shape[0]
|
||||
q_seqlens.extend([q.shape[1]] * q.shape[0])
|
||||
kv_seqlens.extend([k.shape[1]] * k.shape[0])
|
||||
assert tensors_v is None or tensors_v[i].shape[:2] == k.shape[:2]
|
||||
block_diag = cls.from_seqlens(q_seqlens, kv_seqlens)
|
||||
block_diag._batch_sizes = [x.shape[0] for x in tensors_q]
|
||||
return (
|
||||
block_diag,
|
||||
paddle.concat(
|
||||
[x.reshape([1, -1, *x.shape[2:]]) for x in tensors_q], axis=1
|
||||
),
|
||||
paddle.concat(
|
||||
[x.reshape([1, -1, *x.shape[2:]]) for x in tensors_k], axis=1
|
||||
),
|
||||
(
|
||||
paddle.concat(
|
||||
[x.reshape([1, -1, *x.shape[2:]]) for x in tensors_v],
|
||||
axis=1,
|
||||
)
|
||||
if tensors_v is not None
|
||||
else None
|
||||
),
|
||||
)
|
||||
|
||||
def split_queries(self, tensor):
|
||||
return self.q_seqinfo.split(tensor, self._batch_sizes)
|
||||
|
||||
def split_kv(self, tensor):
|
||||
return self.k_seqinfo.split(tensor, self._batch_sizes)
|
||||
|
||||
def split(self, tensor):
|
||||
assert self.q_seqinfo is self.k_seqinfo
|
||||
return self.q_seqinfo.split(tensor, self._batch_sizes)
|
||||
|
||||
def make_causal(self):
|
||||
return BlockDiagonalCausalMask(
|
||||
q_seqinfo=self.q_seqinfo,
|
||||
k_seqinfo=self.k_seqinfo,
|
||||
_batch_sizes=self._batch_sizes,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlockDiagonalCausalMask(BlockDiagonalMask):
|
||||
def _create_block_mask(self, shape, dtype=paddle.float32):
|
||||
return LowerTriangularMask().materialize(shape=shape, dtype=dtype)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlockDiagonalCausalWithOffsetPaddedKeysMask(AttentionBias):
|
||||
q_seqinfo: SeqLenInfo
|
||||
k_seqinfo: PaddedSeqLenInfo
|
||||
causal_diagonal: paddle.Tensor | None = None
|
||||
|
||||
def _create_block_mask(self, shape, offset=0, dtype=paddle.float32):
|
||||
create_as = dtype if dtype is not paddle.bfloat16 else paddle.float32
|
||||
tensor = paddle.full(shape, dtype=create_as, fill_value=float('-inf'))
|
||||
return paddle.triu(tensor, diagonal=1 + offset).astype(dtype)
|
||||
|
||||
def materialize(self, shape, dtype=paddle.float32):
|
||||
assert shape[-1] == self.k_seqinfo.seqstart_py[-1]
|
||||
assert shape[-2] == self.q_seqinfo.seqstart_py[-1]
|
||||
mask = paddle.full(shape[-2:], dtype=dtype, fill_value=float('-inf'))
|
||||
for i, ((q_start, q_end), (k_start, k_end)) in enumerate(
|
||||
zip(self.q_seqinfo.intervals(), self.k_seqinfo.intervals())
|
||||
):
|
||||
mask[q_start:q_end, k_start:k_end] = self._create_block_mask(
|
||||
(q_end - q_start, k_end - k_start),
|
||||
offset=(
|
||||
0
|
||||
if self.causal_diagonal is None
|
||||
else int(self.causal_diagonal[i].item())
|
||||
),
|
||||
dtype=dtype,
|
||||
)
|
||||
for _ in range(len(shape) - 2):
|
||||
mask = mask.unsqueeze(0)
|
||||
return mask.expand(shape)
|
||||
|
||||
@classmethod
|
||||
def from_seqlens(
|
||||
cls, q_seqlen, kv_padding, kv_seqlen, causal_diagonal=None
|
||||
):
|
||||
assert kv_seqlen is None or len(q_seqlen) == len(kv_seqlen)
|
||||
q_seqinfo = SeqLenInfo.from_seqlens(q_seqlen)
|
||||
k_seqinfo = PaddedSeqLenInfo.from_seqlens_padded(kv_seqlen, kv_padding)
|
||||
return cls(
|
||||
q_seqinfo=q_seqinfo,
|
||||
k_seqinfo=k_seqinfo,
|
||||
causal_diagonal=causal_diagonal,
|
||||
)
|
||||
@@ -0,0 +1,123 @@
|
||||
# ruff: noqa: F401
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from .batched_gemm import batched_gemm
|
||||
from .blha_get_max_len import blha_get_max_len
|
||||
from .block_multihead_attention import (
|
||||
block_multihead_attention,
|
||||
block_multihead_attention_xpu,
|
||||
)
|
||||
|
||||
# from .moe_gate_dispatch_permute import moe_gate_dispatch_permute
|
||||
from .build_src_rank_and_local_expert_id import (
|
||||
build_src_rank_and_local_expert_id,
|
||||
)
|
||||
from .cal_aux_loss import cal_aux_loss
|
||||
from .cross_entropy_with_softmax_bwd_w_downcast import (
|
||||
cross_entropy_with_softmax_bwd_w_downcast,
|
||||
)
|
||||
from .embedding_grad_add_to import embedding_grad_add_to_
|
||||
from .expand_modality_expert_id import expand_modality_expert_id
|
||||
from .fast_ln import fast_ln
|
||||
from .fast_rms_norm import fast_rms_norm
|
||||
from .fp8 import (
|
||||
fp8_gemm_blockwise,
|
||||
fp8_quant_blockwise,
|
||||
fused_act_dequant,
|
||||
fused_stack_transpose_quant,
|
||||
fused_swiglu_weighted_bwd,
|
||||
fused_transpose_split_quant,
|
||||
fused_transpose_wlch_split_quant,
|
||||
fused_weighted_swiglu_act_quant,
|
||||
)
|
||||
from .fused_bias_act import fused_bias_act
|
||||
from .fused_dot_product_attention import (
|
||||
cudnn_flash_attention,
|
||||
fused_dot_product_attention,
|
||||
)
|
||||
from .fused_dropout_add import fused_dropout_add
|
||||
from .fused_gate_attention import fused_gate_attention
|
||||
from .fused_layer_norm import fused_layer_norm
|
||||
from .fused_matmul_bias import (
|
||||
fused_linear,
|
||||
fused_linear_activation,
|
||||
fused_matmul_bias,
|
||||
)
|
||||
from .fused_partial_rope import fused_partial_rope
|
||||
from .fused_rms_norm import fused_rms_norm
|
||||
from .fused_rms_norm_ext import fused_rms_norm_ext
|
||||
from .fused_rotary_position_embedding import fused_rotary_position_embedding
|
||||
from .fused_transformer import (
|
||||
fused_bias_dropout_residual_layer_norm,
|
||||
fused_feedforward,
|
||||
fused_multi_head_attention,
|
||||
fused_multi_transformer,
|
||||
)
|
||||
from .int_bincount import int_bincount
|
||||
from .masked_multihead_attention import masked_multihead_attention
|
||||
from .moe_combine import moe_combine
|
||||
from .moe_combine_no_weight import moe_combine_no_weight
|
||||
from .moe_gate_dispatch import moe_gate_dispatch
|
||||
from .moe_gate_dispatch_and_quant import moe_gate_dispatch_and_quant
|
||||
from .moe_gate_dispatch_partial_nosoftmaxtopk import (
|
||||
moe_gate_dispatch_partial_nosoftmaxtopk,
|
||||
)
|
||||
from .moe_gate_dispatch_permute import moe_gate_dispatch_permute
|
||||
from .swiglu import swiglu
|
||||
from .variable_length_memory_efficient_attention import (
|
||||
variable_length_memory_efficient_attention,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'embedding_grad_add_to_',
|
||||
'fp8_gemm_blockwise',
|
||||
'cross_entropy_with_softmax_bwd_w_downcast',
|
||||
'fp8_quant_blockwise',
|
||||
'fast_ln',
|
||||
'fast_rms_norm',
|
||||
'fused_act_dequant',
|
||||
'fused_multi_head_attention',
|
||||
'fused_feedforward',
|
||||
'fused_multi_transformer',
|
||||
'fused_matmul_bias',
|
||||
'fused_linear',
|
||||
'fused_linear_activation',
|
||||
'fused_bias_dropout_residual_layer_norm',
|
||||
'fused_dropout_add',
|
||||
'fused_rotary_position_embedding',
|
||||
'fused_stack_transpose_quant',
|
||||
'fused_transpose_split_quant',
|
||||
'fused_transpose_wlch_split_quant',
|
||||
'variable_length_memory_efficient_attention',
|
||||
"fused_rms_norm",
|
||||
"fused_layer_norm",
|
||||
"fused_bias_act",
|
||||
'fused_swiglu_weighted_bwd',
|
||||
'fused_weighted_swiglu_act_quant',
|
||||
"masked_multihead_attention",
|
||||
"blha_get_max_len",
|
||||
"block_multihead_attention",
|
||||
"moe_combine",
|
||||
"expand_modality_expert_id",
|
||||
"cal_aux_loss",
|
||||
"build_src_rank_and_local_expert_id",
|
||||
"int_bincount",
|
||||
"fused_rms_norm_ext",
|
||||
"moe_gate_dispatch",
|
||||
"moe_gate_dispatch_permute",
|
||||
"moe_gate_dispatch_partial_nosoftmaxtopk",
|
||||
"moe_gate_dispatch_and_quant",
|
||||
]
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from paddle import Tensor, _C_ops
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
|
||||
def batched_gemm(
|
||||
lhs: Tensor,
|
||||
rhs: Tensor,
|
||||
batch_sizes: list,
|
||||
trans_lhs: bool = False,
|
||||
trans_rhs: bool = False,
|
||||
) -> tuple[Tensor]:
|
||||
"""
|
||||
Cluster launched gemm into one op, which can be further fused and optimized.
|
||||
|
||||
Args:
|
||||
lhs (Tensor): A tensor shaped in (total_seq_len, input_hidden_size), meant to be
|
||||
perform gemm operation according to batch range.
|
||||
rhs (Tensor): A tensor shaped in (num_batches, input_hidden_size, output_hidden_size).
|
||||
batch_sizes(list): A list of integers representing the number of rows in each batch.
|
||||
trans_lhs (bool): Whether view lhs matrix as last 2D-transposed. Default: False.
|
||||
trans_rhs (bool): Whether view rhs matrix as last 2D-transposed. Default: False.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- out (Tensor): The result of batched gemm operation.
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.batched_gemm(lhs, rhs, batch_sizes, trans_lhs, trans_rhs)
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def blha_get_max_len(
|
||||
seq_lens_encoder: Tensor, seq_lens_decoder: Tensor, batch_size: Tensor
|
||||
) -> tuple[Tensor, Tensor]:
|
||||
"""
|
||||
Apply Fused BlhaGetMaxLen kernel. Typically used before the block_multihead_attention operator.
|
||||
|
||||
Args:
|
||||
seq_lens_encoder (Tensor): Sentence length of the encoder.
|
||||
seq_lens_decoder (Tensor): Sentence length of the decoder.
|
||||
batch_size (Tensor): the batch size.
|
||||
|
||||
Returns:
|
||||
Tensor|(max_enc_len_this_time, max_dec_len_this_time)
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> seq_lens_encoder = paddle.cast(paddle.randn(shape=[10]), dtype=paddle.int32)
|
||||
>>> seq_lens_decoder = paddle.cast(paddle.randn(shape=[10]), dtype=paddle.int32)
|
||||
>>> bsz = 10
|
||||
>>> batch_size = paddle.ones(shape=[bsz])
|
||||
>>> max_enc_len_this_time, max_dec_len_this_time = paddle.incubate.nn.functional.blha_get_max_len(
|
||||
... seq_lens_encoder, seq_lens_decoder, batch_size
|
||||
... )
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.blha_get_max_len(
|
||||
seq_lens_encoder, seq_lens_decoder, batch_size
|
||||
)
|
||||
|
||||
helper = LayerHelper('blha_get_max_len', **locals())
|
||||
max_enc_len_this_time = helper.create_variable_for_type_inference(
|
||||
dtype="int32"
|
||||
)
|
||||
max_dec_len_this_time = helper.create_variable_for_type_inference(
|
||||
dtype="int32"
|
||||
)
|
||||
|
||||
inputs = {}
|
||||
inputs['seq_lens_encoder'] = seq_lens_encoder
|
||||
inputs['seq_lens_decoder'] = seq_lens_decoder
|
||||
inputs['batch_size'] = batch_size
|
||||
|
||||
outputs = {
|
||||
'max_enc_len_this_time': max_enc_len_this_time,
|
||||
'max_dec_len_this_time': max_dec_len_this_time,
|
||||
}
|
||||
helper.append_op(
|
||||
type='blha_get_max_len',
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
)
|
||||
return max_enc_len_this_time, max_dec_len_this_time
|
||||
@@ -0,0 +1,583 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Literal, TypeAlias
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import (
|
||||
LayerHelper,
|
||||
in_dynamic_or_pir_mode,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
_QuantRoundType: TypeAlias = Literal[0, 1]
|
||||
|
||||
|
||||
def block_multihead_attention(
|
||||
qkv: Tensor,
|
||||
key_cache: Tensor,
|
||||
value_cache: Tensor,
|
||||
seq_lens_encoder: Tensor,
|
||||
seq_lens_decoder: Tensor,
|
||||
seq_lens_this_time: Tensor,
|
||||
padding_offsets: Tensor,
|
||||
cum_offsets: Tensor,
|
||||
cu_seqlens_q: Tensor,
|
||||
cu_seqlens_k: Tensor,
|
||||
block_tables: Tensor,
|
||||
pre_key_cache: Tensor | None = None,
|
||||
pre_value_cache: Tensor | None = None,
|
||||
cache_k_quant_scales: Tensor | None = None,
|
||||
cache_v_quant_scales: Tensor | None = None,
|
||||
cache_k_dequant_scales: Tensor | None = None,
|
||||
cache_v_dequant_scales: Tensor | None = None,
|
||||
qkv_out_scale: Tensor | None = None,
|
||||
qkv_bias: Tensor | None = None,
|
||||
out_shift: Tensor | None = None,
|
||||
out_smooth: Tensor | None = None,
|
||||
max_enc_len_this_time: Tensor | None = None,
|
||||
max_dec_len_this_time: Tensor | None = None,
|
||||
rope_emb: Tensor | None = None,
|
||||
mask: Tensor | None = None,
|
||||
tgt_mask: Tensor | None = None,
|
||||
max_seq_len: int = -1,
|
||||
block_size: int = 64,
|
||||
use_neox_style: bool = False,
|
||||
use_dynamic_cachekv_quant: bool = False,
|
||||
quant_round_type: _QuantRoundType = 1,
|
||||
quant_max_bound: float = 127.0,
|
||||
quant_min_bound: float = -127.0,
|
||||
out_scale: float = -1,
|
||||
compute_dtype: str = "default",
|
||||
rope_theta: float = 10000.0,
|
||||
) -> tuple[Tensor, Tensor, Tensor, Tensor]:
|
||||
"""
|
||||
Block Multi-head attention for text summarization.
|
||||
|
||||
Args:
|
||||
qkv (Tensor): The qkv Tensor. Its shape is [token_num, 3 * num_head * head_size].
|
||||
key_cache (Tensor): The key_cache Tensor. Its shape is [max_block_num, num_head, block_size, head_size].
|
||||
value_cache (Tensor): The value_cache Tensor. Its shape is [max_block_num, num_head, block_size, head_size].
|
||||
seq_lens_encoder (Tensor): The encoder sequence lengths of the sequences in the batch. Its shape is [batchsize, 1].
|
||||
seq_lens_decoder (Tensor): The decoder sequence lengths of the sequences in the batch. Its shape is [batchsize, 1].
|
||||
seq_lens_this_time (Tensor): The real sequence lengths of the sequences in the batch. Its shape is [batchsize, 1].
|
||||
padding_offsets (Tensor): The offsets from unpadding to padding. Its shape is [token_num].
|
||||
cum_offsets (Tensor): The offsets from padding to unpadding. Its shape is [batchsize].
|
||||
cu_seqlens_q (Tensor): The cum sequence lengths of query. Its shape is [batchsize + 1, 1].
|
||||
cu_seqlens_k (Tensor): The cum sequence lengths of key. Its shape is [batchsize + 1, 1].
|
||||
block_tables (Tensor): The block tables, used to index the cache. Its shape is [batchsize, block_num_per_seq].
|
||||
pre_key_cache (Tensor): The pre caches of key. Its shape is [batchsize, num_head, pre_cache_length, head_size].
|
||||
pre_value_cache (Tensor): The pre caches of value. Its shape is [batchsize, num_head, pre_cache_length, head_size].
|
||||
cache_k_quant_scales (Tensor): The quant scales of cache key. Its shape depends on quant mode (dynamic or static). If dynamic quantization is enabled, its shape is [batchsize, num_head], otherwise its shape is [num_head].
|
||||
cache_v_quant_scales (Tensor): The quant scales of cache value. Its shape depends on quant mode (dynamic or static). If dynamic quantization is enabled, its shape is [batchsize, num_head], otherwise its shape is [num_head].
|
||||
cache_k_dequant_scales (Tensor): The dequant scales of cache key. Its shape depends on quant mode (dynamic or static). If dynamic quantization is enabled, its shape is [batchsize, num_head], otherwise its shape is [num_head].
|
||||
cache_v_dequant_scales (Tensor): The dequant scales of cache value. Its shape depends on quant mode (dynamic or static). If dynamic quantization is enabled, its shape is [batchsize, num_head], otherwise its shape is [num_head].
|
||||
qkv_out_scale (Tensor): The dequant scale of qkv, which is the input of BLHA. If the dtype of qkv is `int32`, this input will be applied. Its shape is [3 * num_head * head_size], and its dtype should be `float32`.
|
||||
qkv_bias (Tensor): The bias of qkv. Its shape is [3 * num_head * head_size].
|
||||
out_shift (Tensor): Shift bias of fmha_out, which is the 1st return value. Its shape is [num_head * head_size].
|
||||
out_smooth (Tensor): Smooth weight of fmha_out. Its shape is [num_head * head_size].
|
||||
max_enc_len_this_time (Tensor): Sentence length of the encoder this time. Its shape is [1].
|
||||
max_dec_len_this_time (Tensor): Sentence length of the decoder this time. Its shape is [1].
|
||||
rope_emb (Tensor): The RoPE embedding. Its shape is [2, batchsize, max_seq_len, 1, head_size // 2].
|
||||
mask (Tensor): The mask of qk_matmul in encoder. Its shape is [batchsize, 1, max_seq_len, max_seq_len].
|
||||
tgt_mask (Tensor): The mask of qk_matmul in decoder. Its shape is [batchsize, 1, 1, max_seq_len].
|
||||
max_seq_len (Int): The max length of the input. Default is -1.
|
||||
block_size (Int): The block_size of cache. Default is 64.
|
||||
use_neox_style (Bool): Whether neox_style RoPE is used or not. Default is False.
|
||||
use_dynamic_cachekv_quant (Bool): Whether dynamic cache kv quantization is applied or not. Default is False.
|
||||
quant_round_type (Int): The quant round type in cache kv quantization and fmha_out quantization. If 0 is set, value will be rounding to nearest ties to even. If 1 is set, value will be rounding to nearest ties away from zero.
|
||||
quant_max_bound (Float32): The max bound of float type to int type.
|
||||
quant_min_bound (Float32): The min bound of float type to int type.
|
||||
out_scale (Float32): The quant scale of fmha_out. Default is -1, which means do not apply quantization for fmha_out.
|
||||
compute_dtype (Str): A compute dtype, is used to represent the input data type. Default is "default", which means compute dtype is determined by input dtype. However, if the dtype of input is Int32, this value should be set to actual dtype of the model.
|
||||
rope_theta (Float32): The theta of RoPE. Default is 10000.0.
|
||||
Returns:
|
||||
Tensor|(output, qkv_out, cache_k_out, cache_v_out), which output is the output of
|
||||
block_multihead_attention layers, qkv_out is inplace with input `qkv`, cache_k_out and cache_v_out are inplace with input `cache_k` and `cache_v`.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('Need compile flash attention')
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import numpy as np
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import (
|
||||
... block_multihead_attention,
|
||||
... )
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> def get_padding_offset(bsz, max_seq_len, seq_lens_this_time):
|
||||
... cum_offsets_now = paddle.cumsum(max_seq_len - seq_lens_this_time)
|
||||
... cum_offsets = paddle.zeros(shape=(bsz + 1), dtype="int32")
|
||||
... cum_offsets[1:] = cum_offsets_now
|
||||
... token_num = paddle.sum(seq_lens_this_time)
|
||||
... padding_offsets = paddle.zeros(shape=(token_num), dtype="int32")
|
||||
... cu_seqlens_q = paddle.zeros(shape=(bsz + 1), dtype="int32")
|
||||
... cu_seqlens_k = paddle.zeros(shape=(bsz + 1), dtype="int32")
|
||||
... for i in range(bsz):
|
||||
... seq_len_now = seq_lens_this_time[i]
|
||||
... cum_offset = cum_offsets[i]
|
||||
... for j in range(seq_len_now):
|
||||
... padding_offsets[i * max_seq_len - cum_offset + j] = cum_offset
|
||||
... cum_seq_len = (i + 1) * max_seq_len - cum_offsets[i + 1]
|
||||
... cu_seqlens_q[i + 1] = cum_seq_len
|
||||
... cu_seqlens_k[i + 1] = cum_seq_len
|
||||
... return (
|
||||
... padding_offsets,
|
||||
... cum_offsets[:-1],
|
||||
... cu_seqlens_q,
|
||||
... cu_seqlens_k,
|
||||
... )
|
||||
|
||||
>>> def remove_padding(seq_lens, cu_seq_lens, inputs, token_num):
|
||||
... bsz, num_head, seq_len, head_size = inputs.shape
|
||||
... output = paddle.zeros(
|
||||
... shape=[token_num, num_head * head_size],
|
||||
... dtype=inputs.dtype,
|
||||
... )
|
||||
... inputs = inputs.transpose([0, 2, 1, 3]).reshape([bsz, seq_len, -1])
|
||||
... for i in range(bsz):
|
||||
... seq_len_now = seq_lens[i]
|
||||
... start_idx = cu_seq_lens[i]
|
||||
... end_idx = cu_seq_lens[i + 1]
|
||||
... output[start_idx:end_idx, :] = inputs[i, :seq_len_now, :]
|
||||
... return output
|
||||
|
||||
>>> def create_attn_mask(
|
||||
... mask_type,
|
||||
... batch_size,
|
||||
... seq_lens,
|
||||
... pre_cache_length=0,
|
||||
... ):
|
||||
... max_seq_len = max(seq_lens)
|
||||
... mask = paddle.zeros(
|
||||
... [batch_size, 1, max_seq_len, max_seq_len + pre_cache_length],
|
||||
... dtype=mask_type,
|
||||
... )
|
||||
... mask[:, :, :, :pre_cache_length] = 1
|
||||
... for i in range(batch_size):
|
||||
... seq_len = seq_lens[i]
|
||||
... mask[i, 0, :seq_len, :seq_len] = (paddle.tril(paddle.ones(shape=(seq_len, seq_len), dtype=mask_type)) - 1) * 1e4
|
||||
... return mask
|
||||
|
||||
>>> def naive_attention_impl(
|
||||
... query,
|
||||
... key,
|
||||
... value,
|
||||
... cache_k,
|
||||
... cache_v,
|
||||
... pre_cache_k,
|
||||
... pre_cache_v,
|
||||
... mask,
|
||||
... scale=1.0,
|
||||
... ):
|
||||
... batch = query.shape[0]
|
||||
... heads = query.shape[1]
|
||||
... seq_len = query.shape[2]
|
||||
... head_dim = query.shape[3]
|
||||
... kv_head = key.shape[1]
|
||||
... key = key.reshape([batch, kv_head, 1, seq_len, head_dim])
|
||||
... key = paddle.tile(key, [1, 1, heads // kv_head, 1, 1])
|
||||
... key = key.reshape([batch, heads, seq_len, head_dim])
|
||||
... if pre_cache_k is not None:
|
||||
... key = paddle.concat([pre_cache_k, key], axis=2)
|
||||
... if cache_k is not None:
|
||||
... key = paddle.concat([cache_k, key], axis=2)
|
||||
... value = value.reshape([batch, kv_head, 1, seq_len, head_dim])
|
||||
... value = paddle.tile(value, [1, 1, heads // kv_head, 1, 1])
|
||||
... value = value.reshape([batch, heads, seq_len, head_dim])
|
||||
... if pre_cache_v is not None:
|
||||
... value = paddle.concat([pre_cache_v, value], axis=2)
|
||||
... if cache_v is not None:
|
||||
... value = paddle.concat([cache_v, value], axis=2)
|
||||
... qk_res = paddle.matmul(query, key, transpose_y=True)
|
||||
... attention = qk_res * scale
|
||||
... if mask is not None:
|
||||
... attention = attention + mask
|
||||
... softmax_result = paddle.nn.functional.softmax(attention, -1)
|
||||
... result = paddle.matmul(softmax_result, value)
|
||||
... return result
|
||||
|
||||
>>> batch_size = 2
|
||||
>>> num_head = 8
|
||||
>>> seq_len = 64
|
||||
>>> max_dec_len = 64
|
||||
>>> head_size = 64
|
||||
>>> hid_dim = num_head * head_size
|
||||
>>> block_size = 64
|
||||
>>> block_num_per_seq = (seq_len + max_dec_len + block_size - 1) // block_size
|
||||
>>> max_block_num = block_num_per_seq * batch_size
|
||||
>>> free_list = list(range(max_block_num - 1, -1, -1))
|
||||
>>> token_num = seq_len * batch_size
|
||||
|
||||
>>> dtype = paddle.float16
|
||||
|
||||
>>> seq_lens_encoder = paddle.to_tensor(
|
||||
... [
|
||||
... seq_len,
|
||||
... ]
|
||||
... * batch_size,
|
||||
... "int32",
|
||||
... )
|
||||
>>> seq_lens_decoder = paddle.to_tensor(
|
||||
... [0] * batch_size,
|
||||
... "int32",
|
||||
... )
|
||||
>>> seq_lens_this_time = seq_lens_encoder
|
||||
>>> qkv_shape = (
|
||||
... batch_size,
|
||||
... num_head,
|
||||
... seq_len,
|
||||
... head_size,
|
||||
... )
|
||||
>>> q = paddle.randn(shape=qkv_shape, dtype=dtype)
|
||||
>>> k = paddle.randn(shape=qkv_shape, dtype=dtype)
|
||||
>>> v = paddle.randn(shape=qkv_shape, dtype=dtype)
|
||||
>>> qkv = paddle.stack(
|
||||
... [
|
||||
... q.transpose([0, 2, 1, 3]).reshape([token_num, hid_dim]),
|
||||
... k.transpose([0, 2, 1, 3]).reshape([token_num, hid_dim]),
|
||||
... v.transpose([0, 2, 1, 3]).reshape([token_num, hid_dim]),
|
||||
... ],
|
||||
... axis=1,
|
||||
... ).reshape([token_num, -1])
|
||||
>>> scale = 1.0 / np.sqrt(head_size)
|
||||
>>> cache_shape = (max_block_num, num_head, block_size, head_size)
|
||||
>>> cache_k = paddle.zeros(cache_shape, dtype=dtype)
|
||||
>>> cache_v = paddle.zeros(cache_shape, dtype=dtype)
|
||||
>>> block_tables = paddle.zeros(shape=(batch_size, block_num_per_seq), dtype="int32")
|
||||
>>> for i in range(batch_size):
|
||||
... need_block_num = (seq_len + max_dec_len + block_size - 1) // block_size
|
||||
... for j in range(need_block_num):
|
||||
... block_tables[i, j] = free_list.pop()
|
||||
>>> padding_offset, cum_offset, cu_seqlens_q, cu_seqlens_k = get_padding_offset(batch_size, seq_len, seq_lens_this_time)
|
||||
>>> out = block_multihead_attention(
|
||||
... qkv,
|
||||
... cache_k,
|
||||
... cache_v,
|
||||
... seq_lens_encoder,
|
||||
... seq_lens_decoder,
|
||||
... seq_lens_this_time,
|
||||
... padding_offset,
|
||||
... cum_offset,
|
||||
... cu_seqlens_q,
|
||||
... cu_seqlens_k,
|
||||
... block_tables,
|
||||
... None, # pre_key_cache
|
||||
... None, # pre_value_cache
|
||||
... None, # cache_k_quant_scales
|
||||
... None, # cache_v_quant_scales
|
||||
... None, # cache_k_dequant_scales
|
||||
... None, # cache_v_dequant_scales
|
||||
... None, # qkv_out_scale
|
||||
... None, # qkv_bias
|
||||
... None, # out_shift
|
||||
... None, # out_smooth
|
||||
... None, # max_enc_len_this_time
|
||||
... None, # max_dec_len_this_time
|
||||
... None, # rotary_embs
|
||||
... None, # attn_mask
|
||||
... None, # tgt_mask
|
||||
... seq_len,
|
||||
... block_size,
|
||||
... )[0]
|
||||
|
||||
>>> attention_mask = create_attn_mask(
|
||||
... dtype,
|
||||
... batch_size,
|
||||
... [
|
||||
... seq_len,
|
||||
... ]
|
||||
... * batch_size,
|
||||
... )
|
||||
|
||||
>>> out_ref = naive_attention_impl(q, k, v, None, None, None, None, attention_mask, scale)
|
||||
>>> out_ref = remove_padding(seq_lens_this_time, cu_seqlens_q, out_ref, token_num)
|
||||
>>> # equals to: out_ref = out
|
||||
|
||||
>>> print(out.shape) # [token_num, hid_dim]
|
||||
paddle.Size([128, 512])
|
||||
"""
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.block_multihead_attention_(
|
||||
qkv,
|
||||
key_cache,
|
||||
value_cache,
|
||||
seq_lens_encoder,
|
||||
seq_lens_decoder,
|
||||
seq_lens_this_time,
|
||||
padding_offsets,
|
||||
cum_offsets,
|
||||
cu_seqlens_q,
|
||||
cu_seqlens_k,
|
||||
block_tables,
|
||||
pre_key_cache,
|
||||
pre_value_cache,
|
||||
rope_emb,
|
||||
mask,
|
||||
tgt_mask,
|
||||
cache_k_quant_scales,
|
||||
cache_v_quant_scales,
|
||||
cache_k_dequant_scales,
|
||||
cache_v_dequant_scales,
|
||||
qkv_out_scale,
|
||||
qkv_bias,
|
||||
out_shift,
|
||||
out_smooth,
|
||||
max_enc_len_this_time,
|
||||
max_dec_len_this_time,
|
||||
max_seq_len,
|
||||
block_size,
|
||||
use_neox_style,
|
||||
use_dynamic_cachekv_quant,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
out_scale,
|
||||
compute_dtype,
|
||||
rope_theta,
|
||||
)
|
||||
|
||||
helper = LayerHelper('block_multihead_attention', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=qkv.dtype)
|
||||
|
||||
inputs = {}
|
||||
inputs['qkv'] = qkv
|
||||
inputs['key_cache'] = key_cache
|
||||
inputs['value_cache'] = value_cache
|
||||
inputs['seq_lens_encoder'] = seq_lens_encoder
|
||||
inputs['seq_lens_decoder'] = seq_lens_decoder
|
||||
inputs['seq_lens_this_time'] = seq_lens_this_time
|
||||
inputs['padding_offsets'] = padding_offsets
|
||||
inputs['cum_offsets'] = cum_offsets
|
||||
inputs['cu_seqlens_q'] = cu_seqlens_q
|
||||
inputs['cu_seqlens_k'] = cu_seqlens_k
|
||||
inputs['block_tables'] = block_tables
|
||||
if pre_key_cache is not None:
|
||||
inputs['pre_key_cache'] = pre_key_cache
|
||||
if pre_value_cache is not None:
|
||||
inputs['pre_value_cache'] = pre_value_cache
|
||||
if rope_emb is not None:
|
||||
inputs['rope_emb'] = rope_emb
|
||||
if mask is not None:
|
||||
inputs['mask'] = mask
|
||||
if tgt_mask is not None:
|
||||
inputs['tgt_mask'] = tgt_mask
|
||||
if cache_k_quant_scales is not None:
|
||||
inputs["cache_k_quant_scales"] = cache_k_quant_scales
|
||||
if cache_v_quant_scales is not None:
|
||||
inputs["cache_v_quant_scales"] = cache_v_quant_scales
|
||||
if cache_k_dequant_scales is not None:
|
||||
inputs["cache_k_dequant_scales"] = cache_k_dequant_scales
|
||||
if cache_v_dequant_scales is not None:
|
||||
inputs["cache_v_dequant_scales"] = cache_v_dequant_scales
|
||||
if qkv_out_scale is not None:
|
||||
inputs["qkv_out_scale"] = qkv_out_scale
|
||||
if qkv_bias is not None:
|
||||
inputs["qkv_bias"] = qkv_bias
|
||||
if out_shift is not None:
|
||||
inputs["out_shift"] = out_shift
|
||||
if out_smooth is not None:
|
||||
inputs["out_smooth"] = out_smooth
|
||||
if max_enc_len_this_time is not None:
|
||||
inputs["max_enc_len_this_time"] = max_enc_len_this_time
|
||||
if max_dec_len_this_time is not None:
|
||||
inputs["max_dec_len_this_time"] = max_dec_len_this_time
|
||||
|
||||
outputs = {
|
||||
'fmha_out': out,
|
||||
'qkv_out': qkv,
|
||||
'key_cache_out': key_cache,
|
||||
'value_cache_out': value_cache,
|
||||
}
|
||||
helper.append_op(
|
||||
type='block_multihead_attention',
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
attrs={
|
||||
'max_seq_len': max_seq_len,
|
||||
'block_size': block_size,
|
||||
'use_neox_style': use_neox_style,
|
||||
'dynamic_cachekv_quant': use_dynamic_cachekv_quant,
|
||||
'quant_round_type': quant_round_type,
|
||||
'quant_max_bound': quant_max_bound,
|
||||
'quant_min_bound': quant_min_bound,
|
||||
'out_scale': out_scale,
|
||||
'compute_dtype': compute_dtype,
|
||||
'rope_theta': rope_theta,
|
||||
},
|
||||
)
|
||||
return out, qkv, key_cache, value_cache
|
||||
|
||||
|
||||
def block_multihead_attention_xpu(
|
||||
qkv: Tensor,
|
||||
key_cache: Tensor,
|
||||
value_cache: Tensor,
|
||||
seq_lens_encoder: Tensor,
|
||||
seq_lens_decoder: Tensor,
|
||||
seq_lens_this_time: Tensor,
|
||||
padding_offsets: Tensor,
|
||||
cum_offsets: Tensor,
|
||||
cu_seqlens_q: Tensor,
|
||||
cu_seqlens_k: Tensor,
|
||||
block_tables: Tensor,
|
||||
cache_k_per_batch_maxs: Tensor,
|
||||
cache_v_per_batch_maxs: Tensor,
|
||||
pre_key_cache: Tensor | None = None,
|
||||
pre_value_cache: Tensor | None = None,
|
||||
cache_k_quant_scales: Tensor | None = None,
|
||||
cache_v_quant_scales: Tensor | None = None,
|
||||
cache_k_dequant_scales: Tensor | None = None,
|
||||
cache_v_dequant_scales: Tensor | None = None,
|
||||
qkv_out_scale: Tensor | None = None,
|
||||
qkv_bias: Tensor | None = None,
|
||||
out_shift: Tensor | None = None,
|
||||
out_smooth: Tensor | None = None,
|
||||
max_enc_len_this_time: Tensor | None = None,
|
||||
max_dec_len_this_time: Tensor | None = None,
|
||||
rope_emb: Tensor | None = None,
|
||||
mask: Tensor | None = None,
|
||||
tgt_mask: Tensor | None = None,
|
||||
max_seq_len: int = -1,
|
||||
block_size: int = 64,
|
||||
use_neox_style: bool = False,
|
||||
use_dynamic_cachekv_quant: bool = False,
|
||||
quant_round_type: _QuantRoundType = 1,
|
||||
quant_max_bound: float = 127.0,
|
||||
quant_min_bound: float = -127.0,
|
||||
out_scale: float = -1,
|
||||
compute_dtype: str = "default",
|
||||
rope_theta: float = 10000.0,
|
||||
) -> tuple[Tensor, Tensor, Tensor, Tensor]:
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.block_multihead_attention_xpu(
|
||||
qkv,
|
||||
key_cache,
|
||||
value_cache,
|
||||
seq_lens_encoder,
|
||||
seq_lens_decoder,
|
||||
seq_lens_this_time,
|
||||
padding_offsets,
|
||||
cum_offsets,
|
||||
cu_seqlens_q,
|
||||
cu_seqlens_k,
|
||||
block_tables,
|
||||
cache_k_per_batch_maxs,
|
||||
cache_v_per_batch_maxs,
|
||||
pre_key_cache,
|
||||
pre_value_cache,
|
||||
rope_emb,
|
||||
mask,
|
||||
tgt_mask,
|
||||
cache_k_quant_scales,
|
||||
cache_v_quant_scales,
|
||||
cache_k_dequant_scales,
|
||||
cache_v_dequant_scales,
|
||||
qkv_out_scale,
|
||||
qkv_bias,
|
||||
out_shift,
|
||||
out_smooth,
|
||||
max_enc_len_this_time,
|
||||
max_dec_len_this_time,
|
||||
max_seq_len,
|
||||
block_size,
|
||||
use_neox_style,
|
||||
use_dynamic_cachekv_quant,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
out_scale,
|
||||
compute_dtype,
|
||||
rope_theta,
|
||||
)
|
||||
|
||||
helper = LayerHelper('block_multihead_attention_xpu', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=qkv.dtype)
|
||||
|
||||
inputs = {}
|
||||
inputs['qkv'] = qkv
|
||||
inputs['key_cache'] = key_cache
|
||||
inputs['value_cache'] = value_cache
|
||||
inputs['seq_lens_encoder'] = seq_lens_encoder
|
||||
inputs['seq_lens_decoder'] = seq_lens_decoder
|
||||
inputs['seq_lens_this_time'] = seq_lens_this_time
|
||||
inputs['padding_offsets'] = padding_offsets
|
||||
inputs['cum_offsets'] = cum_offsets
|
||||
inputs['cu_seqlens_q'] = cu_seqlens_q
|
||||
inputs['cu_seqlens_k'] = cu_seqlens_k
|
||||
inputs['block_tables'] = block_tables
|
||||
inputs['cache_k_per_batch_maxs'] = cache_k_per_batch_maxs
|
||||
inputs['cache_v_per_batch_maxs'] = cache_v_per_batch_maxs
|
||||
if pre_key_cache is not None:
|
||||
inputs['pre_key_cache'] = pre_key_cache
|
||||
if pre_value_cache is not None:
|
||||
inputs['pre_value_cache'] = pre_value_cache
|
||||
if rope_emb is not None:
|
||||
inputs['rope_emb'] = rope_emb
|
||||
if mask is not None:
|
||||
inputs['mask'] = mask
|
||||
if tgt_mask is not None:
|
||||
inputs['tgt_mask'] = tgt_mask
|
||||
if cache_k_quant_scales is not None:
|
||||
inputs["cache_k_quant_scales"] = cache_k_quant_scales
|
||||
if cache_v_quant_scales is not None:
|
||||
inputs["cache_v_quant_scales"] = cache_v_quant_scales
|
||||
if cache_k_dequant_scales is not None:
|
||||
inputs["cache_k_dequant_scales"] = cache_k_dequant_scales
|
||||
if cache_v_dequant_scales is not None:
|
||||
inputs["cache_v_dequant_scales"] = cache_v_dequant_scales
|
||||
if qkv_out_scale is not None:
|
||||
inputs["qkv_out_scale"] = qkv_out_scale
|
||||
if qkv_bias is not None:
|
||||
inputs["qkv_bias"] = qkv_bias
|
||||
if out_shift is not None:
|
||||
inputs["out_shift"] = out_shift
|
||||
if out_smooth is not None:
|
||||
inputs["out_smooth"] = out_smooth
|
||||
if max_enc_len_this_time is not None:
|
||||
inputs["max_enc_len_this_time"] = max_enc_len_this_time
|
||||
if max_dec_len_this_time is not None:
|
||||
inputs["max_dec_len_this_time"] = max_dec_len_this_time
|
||||
|
||||
outputs = {
|
||||
'fmha_out': out,
|
||||
'qkv_out': qkv,
|
||||
'key_cache_out': key_cache,
|
||||
'value_cache_out': value_cache,
|
||||
}
|
||||
helper.append_op(
|
||||
type='block_multihead_attention_xpu',
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
attrs={
|
||||
'max_seq_len': max_seq_len,
|
||||
'block_size': block_size,
|
||||
'use_neox_style': use_neox_style,
|
||||
'dynamic_cachekv_quant': use_dynamic_cachekv_quant,
|
||||
'quant_round_type': quant_round_type,
|
||||
'quant_max_bound': quant_max_bound,
|
||||
'quant_min_bound': quant_min_bound,
|
||||
'out_scale': out_scale,
|
||||
'compute_dtype': compute_dtype,
|
||||
'rope_theta': rope_theta,
|
||||
},
|
||||
)
|
||||
return out, qkv, key_cache, value_cache
|
||||
@@ -0,0 +1,164 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def math_cal_aux_loss(
|
||||
gate_prob: Tensor,
|
||||
dispatch_mask: Tensor,
|
||||
tokens_mask: Tensor,
|
||||
dispatch_tokens_mask: Tensor,
|
||||
num_experts: int,
|
||||
use_group: bool,
|
||||
moe_k: int,
|
||||
clip_min: float,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
gate_prob
|
||||
dispatch_mask
|
||||
tokens_mask
|
||||
dispatch_tokens_mask
|
||||
num_experts
|
||||
use_group
|
||||
moe_k
|
||||
clip_min
|
||||
|
||||
Returns:
|
||||
l_aux
|
||||
seqlen_float
|
||||
ce
|
||||
"""
|
||||
if tokens_mask is not None and tokens_mask.dtype != gate_prob.dtype:
|
||||
tokens_mask = tokens_mask.astype(gate_prob.dtype)
|
||||
|
||||
scale = None
|
||||
if dispatch_tokens_mask is not None:
|
||||
seqlen_float = dispatch_tokens_mask.astype(gate_prob.dtype).sum()
|
||||
if (
|
||||
tokens_mask is not None
|
||||
and gate_prob.shape[0] != dispatch_tokens_mask.shape[0]
|
||||
):
|
||||
scale = seqlen_float / paddle.clip(tokens_mask.sum(), min=clip_min)
|
||||
elif tokens_mask is not None:
|
||||
seqlen_float = tokens_mask.sum()
|
||||
else:
|
||||
seqlen_float = gate_prob.numel().astype(gate_prob.dtype) / num_experts
|
||||
seqlen_float = paddle.clip(seqlen_float, min=clip_min)
|
||||
|
||||
if len(dispatch_mask.shape) == 2:
|
||||
dispatch_mask = dispatch_mask.sum(0)
|
||||
ce = dispatch_mask.astype(gate_prob.dtype).detach() / seqlen_float
|
||||
me = paddle.sum(gate_prob, axis=0) / seqlen_float
|
||||
|
||||
l_aux = paddle.sum(me * ce) * num_experts
|
||||
if use_group:
|
||||
l_aux = l_aux / moe_k
|
||||
|
||||
if scale is not None:
|
||||
# forward local me, backward global me
|
||||
one = paddle.ones([], dtype="float32")
|
||||
l_aux = l_aux + (scale - one) * l_aux.detach()
|
||||
|
||||
return l_aux, seqlen_float, ce
|
||||
|
||||
|
||||
def cal_aux_loss(
|
||||
gate_prob: Tensor,
|
||||
dispatch_mask: Tensor,
|
||||
tokens_mask: Tensor,
|
||||
dispatch_tokens_mask: Tensor,
|
||||
num_experts: int,
|
||||
use_group: bool,
|
||||
moe_k: int,
|
||||
clip_min: float,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
gate_prob:
|
||||
dispatch_mask:
|
||||
tokens_mask:
|
||||
dispatch_tokens_mask:
|
||||
num_experts:
|
||||
use_group:
|
||||
moe_k:
|
||||
clip_min:
|
||||
|
||||
Returns:
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
if paddle.is_compiled_with_xpu():
|
||||
return math_cal_aux_loss(
|
||||
gate_prob,
|
||||
dispatch_mask,
|
||||
tokens_mask,
|
||||
dispatch_tokens_mask,
|
||||
num_experts,
|
||||
use_group,
|
||||
moe_k,
|
||||
clip_min,
|
||||
)
|
||||
else:
|
||||
return _C_ops.cal_aux_loss(
|
||||
gate_prob,
|
||||
dispatch_mask,
|
||||
tokens_mask,
|
||||
dispatch_tokens_mask,
|
||||
num_experts,
|
||||
use_group,
|
||||
moe_k,
|
||||
clip_min,
|
||||
)
|
||||
|
||||
helper = LayerHelper('cal_aux_loss', **locals())
|
||||
l_aux_loss = helper.create_variable_for_type_inference(
|
||||
dtype=gate_prob.dtype
|
||||
)
|
||||
seqlen_float = helper.create_variable_for_type_inference(
|
||||
dtype=gate_prob.dtype
|
||||
)
|
||||
ce = helper.create_variable_for_type_inference(dtype=gate_prob.dtype)
|
||||
|
||||
inputs = {
|
||||
'gate_prob': gate_prob,
|
||||
'dispatch_mask': dispatch_mask,
|
||||
'tokens_mask': tokens_mask,
|
||||
'dispatch_tokens_mask': dispatch_tokens_mask,
|
||||
}
|
||||
attrs = {
|
||||
'num_experts': num_experts,
|
||||
'use_group': use_group,
|
||||
'moe_k': moe_k,
|
||||
'clip_min': clip_min,
|
||||
}
|
||||
outputs = {'l_aux_loss': l_aux_loss, 'seqlen_float': seqlen_float, 'ce': ce}
|
||||
helper.append_op(
|
||||
type='cal_aux_loss', inputs=inputs, attrs=attrs, outputs=outputs
|
||||
)
|
||||
return l_aux_loss, seqlen_float, ce
|
||||
@@ -0,0 +1,39 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def cross_entropy_with_softmax_bwd_w_downcast(
|
||||
label: Tensor,
|
||||
softmax: Tensor,
|
||||
loss_grad: Tensor,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.cross_entropy_with_softmax_bwd_w_downcast(
|
||||
label,
|
||||
softmax,
|
||||
loss_grad,
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def embedding_grad_add_to_(
|
||||
token_indices: Tensor,
|
||||
main_grad_: Tensor,
|
||||
out_grad: Tensor,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.embedding_grad_add_to_(
|
||||
token_indices,
|
||||
main_grad_,
|
||||
out_grad,
|
||||
)
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def expand_modality_expert_id(
|
||||
expert_id: Tensor,
|
||||
num_expert_per_modality: int,
|
||||
group_size: int,
|
||||
modality_offset: int,
|
||||
is_group_expert: bool,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
expert_id:
|
||||
num_expert_per_modality:
|
||||
group_size:
|
||||
modality_offset:
|
||||
is_group_expert:
|
||||
|
||||
Returns:
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.expand_modality_expert_id(
|
||||
expert_id,
|
||||
num_expert_per_modality,
|
||||
group_size,
|
||||
modality_offset,
|
||||
is_group_expert,
|
||||
)
|
||||
helper = LayerHelper('expand_modality_expert_id', **locals())
|
||||
expert_id_out = helper.create_variable_for_type_inference(
|
||||
dtype=expert_id.dtype
|
||||
)
|
||||
inputs = {'expert_id': expert_id}
|
||||
attrs = {
|
||||
'num_expert_per_modality': num_expert_per_modality,
|
||||
'group_size': group_size,
|
||||
'modality_offset': modality_offset,
|
||||
'is_group_expert': is_group_expert,
|
||||
}
|
||||
helper.append_op(
|
||||
type='expand_modality_expert_id',
|
||||
inputs=inputs,
|
||||
attrs=attrs,
|
||||
outputs={'expert_id_out': expert_id_out},
|
||||
)
|
||||
return expert_id_out
|
||||
@@ -0,0 +1,52 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fast_ln(
|
||||
x: Tensor,
|
||||
scale: Tensor,
|
||||
bias: Tensor,
|
||||
epsilon: float = 1e-5,
|
||||
) -> tuple[Tensor, Tensor, Tensor]:
|
||||
r"""
|
||||
Apply Fast LayerNorm kernel.
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor..
|
||||
scale (Tensor): the weight Tensor to affine output.
|
||||
bias (Tensor): the bias Tensor to affine output.
|
||||
epsilon (float): a small float number to avoid divide 0.
|
||||
|
||||
Returns:
|
||||
y: the Tensor after performing layernorm.
|
||||
mean: the mean of input tensor
|
||||
invvar: the invert variance(scaling factor) of y
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fast_ln(
|
||||
x,
|
||||
scale,
|
||||
bias,
|
||||
epsilon,
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fast_rms_norm(
|
||||
x: Tensor,
|
||||
scale: Tensor,
|
||||
epsilon: float = 1e-5,
|
||||
) -> tuple[Tensor, Tensor]:
|
||||
r"""
|
||||
Apply Fast LayerNorm kernel.
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor..
|
||||
scale (Tensor): the weight Tensor to affine output.
|
||||
epsilon (float): a small float number to avoid divide 0.
|
||||
|
||||
Returns:
|
||||
y: the Tensor after performing layernorm.
|
||||
invvar: the invert variance(scaling factor) of y
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fast_rms_norm(
|
||||
x,
|
||||
scale,
|
||||
epsilon,
|
||||
)
|
||||
@@ -0,0 +1,486 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import Tensor, _C_ops
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
# special re-use of empty to reduce launch cost.
|
||||
@functools.cache
|
||||
def _empty_tensor() -> Tensor:
|
||||
"""Get tensor with no entries and no data"""
|
||||
return Tensor()
|
||||
|
||||
|
||||
def fused_stack_transpose_quant(
|
||||
x: Sequence[Tensor], transpose: bool = True
|
||||
) -> tuple[Tensor, Tensor]:
|
||||
"""
|
||||
Fused operation that performs stacking, optional transposition, and quantization
|
||||
on a list of bfloat16 tensors.
|
||||
|
||||
Args:
|
||||
x (list[Tensor] or tuple[Tensor]): A list or tuple of bfloat16 tensors, where each tensor
|
||||
has shape `[M, K]`. All tensors should have the same shape and dtype.
|
||||
transpose (bool, optional): If True, applies a transpose before quantization.
|
||||
Default is True.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- out (Tensor): The quantized output tensor with dtype `float8_e4m3fn`.
|
||||
- scale (Tensor): A float32 tensor representing the quantization scale.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('BF16 requires SM80 or higher env')
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.set_device('gpu')
|
||||
|
||||
>>> x_vec = []
|
||||
>>> num_experts = 1
|
||||
>>> seq_len = 2048
|
||||
>>> hidden_size = 128
|
||||
>>> for _ in range(num_experts):
|
||||
... x = paddle.randn([seq_len, hidden_size], dtype='bfloat16')
|
||||
... x = paddle.clip(x, min=-50, max=50)
|
||||
... x_vec.append(x)
|
||||
|
||||
>>> out, scale = F.fused_stack_transpose_quant(x_vec, transpose=True)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([128, 2048])
|
||||
>>> print(scale.shape)
|
||||
paddle.Size([1, 16])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
if transpose:
|
||||
return _C_ops.fused_stack_transpose_quant(x)
|
||||
else:
|
||||
return _C_ops.fused_stack_quant(x)
|
||||
|
||||
|
||||
def fused_act_dequant(
|
||||
x: Tensor,
|
||||
x_scale: Tensor,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Applies fused activation and dequantization operation to convert float8 quantized data back to bfloat16.
|
||||
|
||||
Args:
|
||||
x (Tensor): Input quantized tensor with dtype float8_e4m3fn and shape [M, N]. This tensor contains the quantized
|
||||
activations from previous layers.
|
||||
x_scale (Tensor): Dequantization scale tensor with dtype float32 and shape [M, (N + 127) // 128] or int32 and shape [M, (N + 511) // 512].
|
||||
Each scale value corresponds to a 128-column in the input tensor.
|
||||
|
||||
Returns:
|
||||
Tensor. Dequantized output tensor with dtype bfloat16 and shape [M, N]. The values are
|
||||
computed as input * scale for each corresponding 128-column block.
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_act_dequant(x, x_scale)
|
||||
|
||||
|
||||
def fused_swiglu_weighted_bwd(
|
||||
o1: Tensor,
|
||||
do2_s: Tensor,
|
||||
unzipped_probs: Tensor,
|
||||
name: str | None = None,
|
||||
) -> tuple[Tensor, Tensor, Tensor]:
|
||||
"""
|
||||
Computes gradients for fused weighted SwiGLU activation function in backward pass.
|
||||
|
||||
Note:
|
||||
This function performs the backward propagation for the SwiGLU (Swish-Gated Linear Unit)
|
||||
activation with probability weighting. It computes gradients with respect to both the
|
||||
input activations and the probability weights, while also recomputing forward pass values
|
||||
for memory efficiency. The kernel automatically selects between vectorized and standard
|
||||
implementations based on input dimensions.
|
||||
|
||||
Args:
|
||||
o1 (Tensor): Forward pass input tensor with dtype bfloat16 and shape
|
||||
[..., intermediate_size * 2]. The tensor is split into two halves:
|
||||
- Left half [0:intermediate_size]: x1 values (gate inputs)
|
||||
- Right half [intermediate_size:]: x2 values (activation inputs)
|
||||
This is the same input used in the forward SwiGLU computation.
|
||||
do2_s (Tensor): Upstream gradient tensor with dtype bfloat16 and shape
|
||||
[..., intermediate_size]. Contains gradients flowing back from
|
||||
the next layer, representing ∂L/∂output before probability weighting.
|
||||
Each element corresponds to the gradient of one output element.
|
||||
unzipped_probs (Tensor): Probability weighting tensor with dtype float32 and
|
||||
shape matching the batch dimensions of o1 and do2_s
|
||||
[...]. Each probability value was used to weight the
|
||||
corresponding row's output in the forward pass.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- do1 (Tensor). Input gradients with dtype bfloat16 and shape
|
||||
[..., intermediate_size * 2]. Layout matches o1:
|
||||
- [0:intermediate_size]: ∂L/∂x1 (gradients w.r.t. gate inputs)
|
||||
- [intermediate_size:]: ∂L/∂x2 (gradients w.r.t. activation inputs)
|
||||
- probs_grad (Tensor). Probability gradients with dtype float32 and
|
||||
shape [...]. Each element is ∂L/∂prob for the corresponding batch item,
|
||||
computed as the sum of (∂L/∂output_i * SwiGLU_output_i) across the
|
||||
intermediate dimension.
|
||||
- o2_s (Tensor). Recomputed forward output with dtype bfloat16 and
|
||||
shape [..., intermediate_size]. Contains SwiGLU(x1, x2) * prob values.
|
||||
This avoids storing forward activations, trading computation for memory.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('BF16 requires SM80 or higher env')
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.set_device('gpu')
|
||||
|
||||
>>> batch_size, seq_len = 32, 128
|
||||
>>> intermediate_size = 2048
|
||||
|
||||
>>> o1 = paddle.randn(
|
||||
... [batch_size, seq_len, intermediate_size * 2],
|
||||
... dtype='bfloat16',
|
||||
... )
|
||||
>>> do2_s = paddle.randn([batch_size, seq_len, intermediate_size], dtype='bfloat16')
|
||||
>>> expert_probs = paddle.rand([batch_size, seq_len, 1], dtype='float32')
|
||||
|
||||
>>> do1, probs_grad, o2_s = F.fused_swiglu_weighted_bwd(o1, do2_s, expert_probs)
|
||||
>>> print(do1.shape)
|
||||
paddle.Size([32, 128, 4096])
|
||||
>>> print(probs_grad.shape)
|
||||
paddle.Size([32, 128, 1])
|
||||
>>> print(o2_s.shape)
|
||||
paddle.Size([32, 128, 2048])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_swiglu_weighted_bwd(o1, do2_s, unzipped_probs)
|
||||
|
||||
|
||||
def fused_transpose_split_quant(
|
||||
x, input_scales, tokens_per_expert, pow_2_scales=False
|
||||
):
|
||||
"""
|
||||
Applies fused transpose, split, and quantization operation for Mixture of Experts (MoE) models.
|
||||
|
||||
Note:
|
||||
This function performs three operations in a single optimized CUDA kernel:
|
||||
1. Quantizes input from bfloat16 to float8_e4m3fn format using column-wise scaling
|
||||
2. Transposes the matrix from [M, K] to [K, M] layout
|
||||
3. Splits the transposed data across multiple experts based on token distribution
|
||||
|
||||
Args:
|
||||
x (Tensor): Input tensor of shape [M, K] with dtype bfloat16, where M is the total
|
||||
number of tokens and K is the feature dimension. M must be divisible by 128
|
||||
for optimal performance.
|
||||
tokens_per_expert (List[int]): List containing the number of tokens assigned to each expert.
|
||||
Each value should be a multiple of 128 for optimal performance.
|
||||
The sum should equal M (total tokens). Values can be 0 for
|
||||
unused experts.
|
||||
pow_2_scales (bool, optional): Whether to constrain quantization scales to powers of 2
|
||||
for better hardware efficiency. If True, scales will be
|
||||
rounded to the nearest power of 2. Default: False.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- outs (List[Tensor]). List of quantized and transposed output tensors, one per expert.
|
||||
Each tensor has shape [K, tokens_per_expert[i]] and dtype float8_e4m3fn.
|
||||
Empty tensors are included for experts with 0 tokens.
|
||||
- scales (List[Tensor]). List of dequantization scale tensors, one per expert.
|
||||
Each tensor has shape [K // 128, tokens_per_expert[i] // 128]
|
||||
and dtype float32. These are the reciprocal of quantization scales.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('BF16 requires SM80 or higher env')
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.set_device('gpu')
|
||||
|
||||
>>> x = paddle.randn([384, 512], dtype='bfloat16')
|
||||
>>> x = paddle.clip(x, min=-50, max=50)
|
||||
>>> tokens_per_expert = [128, 128, 128]
|
||||
>>> outs, scales = F.fused_transpose_split_quant(x, None, tokens_per_expert, pow_2_scales=True)
|
||||
>>> print(outs[0].shape)
|
||||
paddle.Size([512, 128])
|
||||
>>> print(scales[0].shape)
|
||||
paddle.Size([1, 512])
|
||||
"""
|
||||
tokens_per_expert = [int(t) for t in tokens_per_expert]
|
||||
|
||||
if x.shape[0] == 0 or x.shape[1] == 0:
|
||||
return [], []
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_transpose_split_quant(
|
||||
x, input_scales, tokens_per_expert, pow_2_scales
|
||||
)
|
||||
|
||||
|
||||
def fused_transpose_wlch_split_quant(
|
||||
x: Tensor, tokens_per_expert: Sequence[int], pow_2_scales: bool = False
|
||||
) -> tuple[list[Tensor], list[Tensor]]:
|
||||
tokens_per_expert = [int(t) for t in tokens_per_expert]
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_transpose_wlch_split_quant(
|
||||
x, tokens_per_expert, pow_2_scales
|
||||
)
|
||||
|
||||
|
||||
def fused_weighted_swiglu_act_quant(
|
||||
x: Tensor,
|
||||
prob: Tensor | None = None,
|
||||
using_pow2_scaling: bool = False,
|
||||
name: str | None = None,
|
||||
) -> tuple[Tensor, Tensor]:
|
||||
"""
|
||||
Applies fused weighted SwiGLU activation followed by quantization to float8_e4m3fn format.
|
||||
|
||||
Note:
|
||||
This function combines four operations into a single optimized CUDA kernel:
|
||||
1. SwiGLU activation: SwiGLU(x1, x2) = SiLU(x1) * x2 = (x1 * sigmoid(x1)) * x2
|
||||
2. Probability weighting: multiply by optional probability factors
|
||||
3. Activation computation: compute final activation values in float32 precision
|
||||
4. Quantization: convert results to float8_e4m3fn with computed scaling factors
|
||||
|
||||
The input tensor is split into two halves along the last dimension:
|
||||
- Left half [0, cols/2): first input to SwiGLU (gate values)
|
||||
- Right half [cols/2, cols): second input to SwiGLU (activation values)
|
||||
|
||||
Args:
|
||||
x (Tensor): Input tensor with dtype bfloat16 and shape [..., cols], where cols
|
||||
must be even. The tensor is interpreted as two concatenated matrices:
|
||||
gate values [0:cols/2] and activation values [cols/2:cols].
|
||||
Typical shapes: [batch_size, sequence_length, hidden_dim] or
|
||||
[tokens, expert_dim] in MoE scenarios.
|
||||
prob (Tensor, optional): Probability weighting tensor with dtype float32 and
|
||||
shape matching x's batch dimensions [...]. Each value
|
||||
multiplies the corresponding row's activation output.
|
||||
using_pow2_scaling (bool, optional): Whether to use power-of-2 quantization
|
||||
scaling for hardware efficiency.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- out (Tensor). Quantized activation output with dtype float8_e4m3fn
|
||||
and shape [..., cols/2]. Contains the quantized SwiGLU results.
|
||||
- scale (Tensor). Dequantization scales with dtype float32 and shape
|
||||
[..., (cols/2 + 127) // 128]. Each scale corresponds to a 128-element
|
||||
block in the output tensor. To dequantize: original_value = quantized_value / scale.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('BF16 requires SM80 or higher env')
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.set_device('gpu')
|
||||
|
||||
>>> batch_size, seq_len, expert_dim = 32, 128, 2048
|
||||
>>> x = paddle.randn([batch_size, seq_len, expert_dim], dtype='bfloat16')
|
||||
>>> quantized_out, scales = F.fused_weighted_swiglu_act_quant(x)
|
||||
>>> print(x.shape)
|
||||
paddle.Size([32, 128, 2048])
|
||||
>>> print(quantized_out.shape)
|
||||
paddle.Size([4096, 1024])
|
||||
>>> print(scales.shape)
|
||||
paddle.Size([4096, 8])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_weighted_swiglu_act_quant(
|
||||
x, prob, using_pow2_scaling
|
||||
)
|
||||
|
||||
|
||||
def fp8_gemm_blockwise(
|
||||
a,
|
||||
a_decode_scale,
|
||||
b,
|
||||
b_decode_scale,
|
||||
out_dtype,
|
||||
out: Tensor | None = None,
|
||||
bias: Tensor | None = None,
|
||||
accumulate: bool = False,
|
||||
use_split_accumulator: bool = True,
|
||||
is_a_1d_scaled: bool = True,
|
||||
is_b_1d_scaled: bool = True,
|
||||
):
|
||||
assert bias is None, "Bias is not supported"
|
||||
|
||||
if bias is None:
|
||||
bias = _empty_tensor()
|
||||
else:
|
||||
assert bias.dtype in (
|
||||
paddle.float16,
|
||||
paddle.bfloat16,
|
||||
), "Only fp16 and bfloat16 bias are supported."
|
||||
|
||||
M, K = a.shape
|
||||
N, K_b = b.shape
|
||||
|
||||
if out is None:
|
||||
out = paddle.empty((M, N), dtype=out_dtype)
|
||||
else:
|
||||
assert out.shape == [
|
||||
M,
|
||||
N,
|
||||
], f"Expected shape {(M, N)}, got {out.shape}"
|
||||
assert out.is_contiguous(), "Output tensor is not contiguous."
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
# Create workspace tensor for cuBLAS
|
||||
workspace_size = (
|
||||
33_554_432
|
||||
if paddle.device.cuda.get_device_properties().major >= 9
|
||||
else 4_194_304
|
||||
)
|
||||
workspace = paddle.empty([workspace_size], dtype=paddle.uint8)
|
||||
transa, transb = True, False
|
||||
grad = False
|
||||
math_sm_count = 112
|
||||
|
||||
# Call the C++ operator - it returns (output, pre_gelu_out, workspace_out)
|
||||
output, _, _ = _C_ops.fp8_gemm_blockwise_(
|
||||
b,
|
||||
b_decode_scale,
|
||||
a,
|
||||
a_decode_scale,
|
||||
out,
|
||||
bias,
|
||||
_empty_tensor(),
|
||||
workspace,
|
||||
transa,
|
||||
transb,
|
||||
grad,
|
||||
accumulate,
|
||||
use_split_accumulator,
|
||||
math_sm_count,
|
||||
is_b_1d_scaled,
|
||||
is_a_1d_scaled,
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
def fp8_quant_blockwise(
|
||||
x: Tensor,
|
||||
epsilon: float = 0.0,
|
||||
input_transpose: bool = False,
|
||||
output_scale_transpose: bool = True,
|
||||
return_transpose_only: bool = False,
|
||||
using_pow2_scale: bool = True,
|
||||
using_ue8m0_scale: bool = False,
|
||||
quant_method: str = "1x128",
|
||||
output_type: str = "e4m3",
|
||||
name: str | None = None,
|
||||
):
|
||||
"""
|
||||
Applies blockwise FP8 quantization to input tensor with flexible configuration options.
|
||||
Note:
|
||||
This function performs blockwise quantization from higher precision formats (typically bfloat16)
|
||||
to FP8 format (float8_e4m3fn by default). The quantization is performed in blocks (128x128 or 1x128)
|
||||
for better numerical stability and hardware efficiency.
|
||||
Args:
|
||||
x (Tensor): Input tensor to be quantized. Typically has dtype bfloat16 and shape [M, N].
|
||||
epsilon (float, optional): Small constant added to avoid division by zero when computing scales.
|
||||
Default: 0.0.
|
||||
input_transpose (bool, optional): Whether to transpose the input before quantization.
|
||||
If True, input shape [M, N] becomes [N, M]. Default: False.
|
||||
output_scale_transpose (bool, optional): Whether to transpose the output scale tensor.
|
||||
Default: True.
|
||||
return_transpose_only (bool, optional): If True and input_transpose is True, returns only
|
||||
the transposed quantized output and scale. Default: False.
|
||||
using_pow2_scale (bool, optional): Whether to use power-of-2 quantization scaling for
|
||||
better hardware efficiency. Default: True.
|
||||
using_ue8m0_scale (bool, optional): Whether to use unsigned 8-bit with mantissa 0 scaling format.
|
||||
If True, the output scale tensor has dtype int32, where each element contains 4 packed ue8m0 scales.
|
||||
If False, the output scale tensor has dtype float32.
|
||||
Default: False.
|
||||
quant_method (str, optional): Quantization block size method. Options: "1x128" or "128x128".
|
||||
"1x128" uses 1x128 blocks, "128x128" uses 128x128 blocks. Default: "1x128".
|
||||
output_type (str, optional): Output FP8 format. Currently only "e4m3" (float8_e4m3fn) is supported.
|
||||
Default: "e4m3".
|
||||
name (str, optional): Name for the operation. Default: None.
|
||||
Returns:
|
||||
tuple: The return value depends on the configuration:
|
||||
- If not input_transpose: returns (quantized_output, scale)
|
||||
- If return_transpose_only and input_transpose: returns (transposed_quantized_output, transposed_scale)
|
||||
- Otherwise: returns (quantized_output, scale, transposed_quantized_output, transposed_scale)
|
||||
Where:
|
||||
- quantized_output (Tensor): Quantized output tensor with dtype float8_e4m3fn.
|
||||
- scale (Tensor): Dequantization scale tensor with dtype float32.
|
||||
- transposed_quantized_output (Tensor): Transposed quantized output (if input_transpose).
|
||||
- transposed_scale (Tensor): Transposed scale tensor (if input_transpose).
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('BF16 requires SM80 or higher env')
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> x = paddle.randn([1024, 512], dtype='bfloat16')
|
||||
>>> x = paddle.clip(x, min=-50, max=50)
|
||||
# Basic quantization
|
||||
>>> quantized, scale = F.fp8_quant_blockwise(x)
|
||||
>>> print(quantized.shape)
|
||||
paddle.Size([1024, 512])
|
||||
>>> print(scale.shape)
|
||||
paddle.Size([1024, 4])
|
||||
# With transpose
|
||||
>>> quantized, scale, transposed_quantized, transposed_scale = F.fp8_quant_blockwise(
|
||||
... x, input_transpose=True, return_transpose_only=False
|
||||
... )
|
||||
>>> print(transposed_quantized.shape)
|
||||
paddle.Size([512, 1024])
|
||||
"""
|
||||
|
||||
if quant_method == "1x128":
|
||||
using_1x128 = True
|
||||
elif quant_method == "128x128":
|
||||
using_1x128 = False
|
||||
else:
|
||||
raise ValueError("Unsupported quantization method")
|
||||
|
||||
if output_type == "e4m3":
|
||||
using_e5m2 = False
|
||||
else:
|
||||
raise ValueError("Unsupported output type")
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
x_fp8, scale, x_fp8_t, scale_t = _C_ops.fp8_quant_blockwise(
|
||||
x,
|
||||
epsilon,
|
||||
using_1x128,
|
||||
input_transpose,
|
||||
output_scale_transpose,
|
||||
return_transpose_only,
|
||||
using_e5m2,
|
||||
using_pow2_scale,
|
||||
using_ue8m0_scale,
|
||||
)
|
||||
# Aligned with kitchen's logic
|
||||
if not input_transpose:
|
||||
return x_fp8, scale
|
||||
elif return_transpose_only:
|
||||
return x_fp8_t, scale_t
|
||||
else:
|
||||
return x_fp8, scale, x_fp8_t, scale_t
|
||||
@@ -0,0 +1,127 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
|
||||
def fused_bias_act(
|
||||
x: Tensor,
|
||||
bias: Tensor | None = None,
|
||||
dequant_scales: Tensor | None = None,
|
||||
shift: Tensor | None = None,
|
||||
smooth: Tensor | None = None,
|
||||
act_method: str = "gelu",
|
||||
compute_dtype: str = "default",
|
||||
quant_scale: float = -1,
|
||||
quant_round_type: int = 0,
|
||||
quant_max_bound: float = 0,
|
||||
quant_min_bound: float = 0,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Applies fused_bias_act kernel
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor.
|
||||
bias (Tensor, optional): the input bias Tensor. If it is None, no bias addition would be performed. Otherwise, the bias will be added before activation function. Default: None.
|
||||
dequant_scales (Tensor, optional): the dequantization scale tensor, If it is None, no dequantization will be performed. Default: None.
|
||||
shift (Tensor, optional): the shift tensor, used to shift the input tensor before activation function. If None, no translation will be performed. Default: None.
|
||||
smooth (Tensor, optional): the smooth tensor, used to smooth the input tensor before activation function. If None, no smoothing processing will be performed. Default: None.
|
||||
act_method (Str, optional): the activation method, specify the activation function to be used. Default: gelu.
|
||||
compute_dtype (Str, optional): a compute dtype, is used to represent the input data type. Default is "default", which means compute dtype is determined by input dtype.
|
||||
quant_scale (Float, optional): the quant scale. Default: -1.
|
||||
quant_round_type (Int, optional): the quant round type, if 0 is set, value will be rounding to nearest ties to even. If 1 is set, value will be rounding to nearest ties away from zero. Default: 0.
|
||||
quant_max_bound (Float, optional): the max bound of float type to int type. Default: 0.
|
||||
quant_min_bound (Float, optional): the min bound of float type to int type. Default: 0.
|
||||
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_bias_act
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> x = paddle.randn([3, 5])
|
||||
>>> bias = paddle.randn([5])
|
||||
>>> out = fused_bias_act(x, bias)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([3, 5])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_bias_act(
|
||||
x,
|
||||
bias,
|
||||
dequant_scales,
|
||||
shift,
|
||||
smooth,
|
||||
act_method,
|
||||
compute_dtype,
|
||||
quant_scale,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
)
|
||||
helper = LayerHelper("fused_bias_act")
|
||||
if x.dtype == "int32":
|
||||
if compute_dtype == "bf16":
|
||||
dtype = "uint16"
|
||||
elif compute_dtype == "fp16":
|
||||
dtype = "float16"
|
||||
elif compute_dtype == "fp32":
|
||||
dtype = "float32"
|
||||
out = helper.create_variable_for_type_inference(dtype=dtype)
|
||||
else:
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
|
||||
inputs = {}
|
||||
inputs["x"] = x
|
||||
if bias is not None:
|
||||
inputs["bias"] = bias
|
||||
if dequant_scales is not None:
|
||||
inputs["dequant_scales"] = dequant_scales
|
||||
|
||||
if shift is not None:
|
||||
inputs["shift"] = shift
|
||||
|
||||
if smooth is not None:
|
||||
inputs["smooth"] = smooth
|
||||
|
||||
attrs = {
|
||||
"act_method": act_method,
|
||||
"compute_dtype": compute_dtype,
|
||||
"quant_scale": quant_scale,
|
||||
"quant_round_type": quant_round_type,
|
||||
"quant_max_bound": quant_max_bound,
|
||||
"quant_min_bound": quant_min_bound,
|
||||
}
|
||||
|
||||
helper.append_op(
|
||||
type="fused_bias_act",
|
||||
inputs=inputs,
|
||||
outputs={"out": out},
|
||||
attrs=attrs,
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,246 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from paddle import Tensor, _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
|
||||
def cudnn_flash_attention(
|
||||
q: Tensor,
|
||||
k: Tensor,
|
||||
v: Tensor,
|
||||
bias: Tensor | None = None,
|
||||
cu_seqlen_q: Tensor | None = None,
|
||||
cu_seqlen_k: Tensor | None = None,
|
||||
scaling_factor: float = 1.0,
|
||||
dropout_prob: float = 0.0,
|
||||
training: bool = True,
|
||||
mask_type: str | None = None,
|
||||
bias_type: str | None = None,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Fused Dot Product Attention. This is a fusion operator to compute scaled dot product attention in transformer
|
||||
model architecture. This operator only supports running on Ampere and Hopper GPU and need cudnn version >= 8906.
|
||||
|
||||
Args:
|
||||
q (Tensor): The query tensor. The data type is bfloat16, float16.
|
||||
k (Tensor): The key tensor. The data type is bfloat16, float16.
|
||||
v (Tensor): The value tensor. The data type is bfloat16, float16.
|
||||
bias (Tensor, optional): The bias tensor. The data type needs to be the same as `q`, `k`, `v`.
|
||||
The shape of the bias tensor should be [b,1,s,s] or [b,h,s,s] or [1,1,s,s] or [1, h, s, s].
|
||||
cu_seqlen_q (Tensor, optional): The cu_seqlen_q tensor. The data type is int32.
|
||||
cu_seqlen_k (Tensor, optional): The cu_seqlen_k tensor. The data type is int32.
|
||||
scaling_factor (float): The scaling factor for the attention scores.
|
||||
dropout_prob (float): The dropout probability.
|
||||
training (bool): A flag indicating whether it is in train phrase or not.
|
||||
mask_type (str, optional): The mask type. It can be 'none', 'padding', 'causal', 'paddle_causal'. Default is None.
|
||||
bias_type (str, optional): The bias type. It can be 'none', 'pre_scale_bias', 'post_scale_bias'. Default is None.
|
||||
|
||||
|
||||
Returns:
|
||||
A Tensor representing the fused dot product attention, has same shape and data type as `q` .
|
||||
|
||||
Note:
|
||||
This API is provides the full functionality of the cuDNN flash attention. Such as dbias, padding_causal mask, etc.
|
||||
"""
|
||||
|
||||
if mask_type is None:
|
||||
mask_type = "none"
|
||||
if bias_type is None:
|
||||
bias_type = "none"
|
||||
assert mask_type in [
|
||||
'none',
|
||||
'padding',
|
||||
'causal',
|
||||
'paddle_causal',
|
||||
], "mask_type should be 'none', 'padding', 'causal', 'paddle_causal'"
|
||||
assert bias_type in [
|
||||
'none',
|
||||
'pre_scale_bias',
|
||||
'post_scale_bias',
|
||||
], "bias_type should be 'none', 'pre_scale_bias', 'post_scale_bias'"
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
out, _, _ = _C_ops.fused_dot_product_attention(
|
||||
q,
|
||||
k,
|
||||
v,
|
||||
bias,
|
||||
cu_seqlen_q,
|
||||
cu_seqlen_k,
|
||||
scaling_factor,
|
||||
dropout_prob,
|
||||
training,
|
||||
mask_type,
|
||||
bias_type,
|
||||
)
|
||||
return out
|
||||
else:
|
||||
helper = LayerHelper('fused_dot_product_attention', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=q.dtype)
|
||||
softmax_out = helper.create_variable_for_type_inference(
|
||||
dtype="float", stop_gradient=True
|
||||
)
|
||||
rng_state = helper.create_variable_for_type_inference(
|
||||
dtype='int64', stop_gradient=True
|
||||
)
|
||||
|
||||
attrs = {
|
||||
"scaling_factor": scaling_factor,
|
||||
"dropout_probability": dropout_prob,
|
||||
"is_training": training,
|
||||
"mask_type_str": mask_type,
|
||||
"bias_type_str": bias_type,
|
||||
}
|
||||
helper.append_op(
|
||||
type='fused_dot_product_attention',
|
||||
inputs={
|
||||
'q': q,
|
||||
'k': k,
|
||||
'v': v,
|
||||
'bias': bias,
|
||||
'cu_seqlen_q': cu_seqlen_q,
|
||||
'cu_seqlen_k': cu_seqlen_k,
|
||||
},
|
||||
outputs={
|
||||
'out': [out],
|
||||
'softmax_out': [softmax_out],
|
||||
'rng_state': [rng_state],
|
||||
},
|
||||
attrs=attrs,
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def fused_dot_product_attention(
|
||||
query: Tensor,
|
||||
key: Tensor,
|
||||
value: Tensor,
|
||||
attn_mask: Tensor | None = None,
|
||||
dropout_p: float = 0.0,
|
||||
is_causal: bool = False,
|
||||
scaling_factor: float | None = None,
|
||||
training: bool = True,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Fused Dot Product Attention. This is a fusion operator to compute scaled dot product attention in transformer
|
||||
model architecture. This operator only supports running on Ampere and Hopper GPU and need cudnn version >= 8906.
|
||||
|
||||
Args:
|
||||
query(Tensor): The query tensor in the Attention module.
|
||||
4-D tensor with shape:
|
||||
[batch_size, seq_len, num_heads, head_dim].
|
||||
The dtype can be float16 or bfloat16.
|
||||
key(Tensor): The key tensor in the Attention module.
|
||||
4-D tensor with shape:
|
||||
[batch_size, seq_len, num_heads, head_dim].
|
||||
The dtype can be float16 or bfloat16.
|
||||
value(Tensor): The value tensor in the Attention module.
|
||||
4-D tensor with shape:
|
||||
[batch_size, seq_len, num_heads, head_dim].
|
||||
The dtype can be float16 or bfloat16.
|
||||
attn_mask(Tensor,optional): A float mask of the same type as query,
|
||||
key, value that is added to the attention score.
|
||||
dropout_p (float): The dropout probability.
|
||||
is_causal (bool): A flag indicating whether it is causal masking or not. If True, the mask will be ignored.
|
||||
scaling_factor (float): The scaling factor for the attention scores.
|
||||
training (bool): A flag indicating whether it is in train phrase or not.
|
||||
name(str|None, optional): The default value is None. Normally there is no need for user
|
||||
to set this property. For more information, please refer to
|
||||
:ref:`api_guide_Name`.
|
||||
|
||||
Returns:
|
||||
A Tensor representing the fused dot product attention, has same shape and data type as `q` .
|
||||
|
||||
Note:
|
||||
This API is designed to be aligned with `nn.functional.scaled_dot_product_attention` API. So the
|
||||
arguments are almost the same as `nn.functional.scaled_dot_product_attention`. This difference
|
||||
is that `nn.functional.scaled_dot_product_attention` calls the open source flash attention
|
||||
(https://github.com/Dao-AILab/flash-attention). While this API calls the kernel implemented
|
||||
by cuDNN, which achieves better performance on the latest GPU architectures (Hopper and After).
|
||||
|
||||
The mask is passed as a post scale bias in this API. So this mask can be a arbitrary mask, not just padding mask.
|
||||
"""
|
||||
|
||||
if is_causal:
|
||||
assert attn_mask is None, "mask must be None when is_causal is True"
|
||||
mask_type = "causal"
|
||||
bias_type = "none"
|
||||
elif attn_mask is not None:
|
||||
mask_type = "none"
|
||||
bias_type = "post_scale_bias" # pass mask as a post scale bias
|
||||
else:
|
||||
mask_type = "none"
|
||||
bias_type = "none"
|
||||
|
||||
if attn_mask is not None:
|
||||
assert attn_mask.dtype == query.dtype, (
|
||||
"attn_mask dtype should be the same as qkv dtype"
|
||||
)
|
||||
|
||||
cu_seqlen_q = None
|
||||
cu_seqlen_k = None
|
||||
if scaling_factor is None:
|
||||
head_dim = query.shape[3]
|
||||
scaling_factor = head_dim**-0.5
|
||||
if in_dynamic_or_pir_mode():
|
||||
out, _, _ = _C_ops.fused_dot_product_attention(
|
||||
query,
|
||||
key,
|
||||
value,
|
||||
attn_mask,
|
||||
cu_seqlen_q,
|
||||
cu_seqlen_k,
|
||||
scaling_factor,
|
||||
dropout_p,
|
||||
training,
|
||||
mask_type,
|
||||
bias_type,
|
||||
)
|
||||
return out
|
||||
else:
|
||||
helper = LayerHelper('fused_dot_product_attention', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=query.dtype)
|
||||
softmax_out = helper.create_variable_for_type_inference(dtype="float")
|
||||
rng_state = helper.create_variable_for_type_inference(dtype='int64')
|
||||
|
||||
attrs = {
|
||||
"scaling_factor": scaling_factor,
|
||||
"dropout_probability": dropout_p,
|
||||
"is_training": training,
|
||||
"mask_type_str": mask_type,
|
||||
"bias_type_str": bias_type,
|
||||
}
|
||||
helper.append_op(
|
||||
type='fused_dot_product_attention',
|
||||
inputs={
|
||||
'q': query,
|
||||
'k': key,
|
||||
'v': value,
|
||||
'bias': attn_mask,
|
||||
'cu_seqlen_q': cu_seqlen_q,
|
||||
'cu_seqlen_k': cu_seqlen_k,
|
||||
},
|
||||
outputs={
|
||||
'out': [out],
|
||||
'softmax_out': [softmax_out],
|
||||
'rng_state': [rng_state],
|
||||
},
|
||||
attrs=attrs,
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,157 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
import warnings
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.base import core
|
||||
from paddle.common_ops_import import default_main_program
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
flag = [False]
|
||||
|
||||
|
||||
def paddle_dropout_add(x, y, p=0.5, training=True, mode="upscale_in_train"):
|
||||
tmp = paddle.nn.functional.dropout(x, p, training=training, mode=mode)
|
||||
return tmp + y
|
||||
|
||||
|
||||
def fused_dropout_add(
|
||||
x: Tensor,
|
||||
y: Tensor,
|
||||
p: float = 0.5,
|
||||
training: bool = True,
|
||||
mode: Literal[
|
||||
'upscale_in_train', 'downscale_in_infer'
|
||||
] = 'upscale_in_train',
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Fused Dropout and Add.
|
||||
|
||||
Args:
|
||||
x (Tensor): The input tensor. The data type is bfloat16, float16, float32 or float64.
|
||||
y (Tensor): The input tensor. The data type is bfloat16, float16, float32 or float64.
|
||||
|
||||
p (float|int, optional): Probability of setting units to zero. Default: 0.5.
|
||||
training (bool, optional): A flag indicating whether it is in train phrase or not. Default: True.
|
||||
mode(str, optional): ['upscale_in_train'(default) | 'downscale_in_infer'].
|
||||
|
||||
1. upscale_in_train (default), upscale the output at training time
|
||||
|
||||
- train: :math:`out = x \times \frac{mask}{(1.0 - dropout\_prob)} + y`
|
||||
- inference: :math:`out = x + y`
|
||||
|
||||
2. downscale_in_infer, downscale the output at inference
|
||||
|
||||
- train: :math:`out = input \times mask + y`
|
||||
- inference: :math:`out = input \times (1.0 - dropout\_prob) + y`
|
||||
|
||||
name (str, optional): Name for the operation, Default: None. For more information, please refer to :ref:`api_guide_Name`.
|
||||
|
||||
Returns:
|
||||
A Tensor representing the fused dropout and add, has same shape and data type as `x` .
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_dropout_add
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> paddle.seed(2023)
|
||||
>>> x = paddle.randn([4, 10], dtype="float32")
|
||||
>>> y = paddle.randn([4, 10], dtype="float32")
|
||||
>>> out = fused_dropout_add(x, y, p=0.5)
|
||||
>>> print(out)
|
||||
Tensor(shape=[4, 10], dtype=float32, place=Place(gpu:0), stop_gradient=True,
|
||||
[[-0.49133155, 0.53819323, -2.58393312, 0.06336236, -1.09908366,
|
||||
0.22085167, 2.19751787, 0.05034769, 0.53417486, 0.84864247],
|
||||
[ 0.78248203, -1.59652555, -0.14399840, -0.77985179, -0.17006736,
|
||||
-0.30991879, -0.36593807, -0.51025450, 1.46401680, 0.61627960],
|
||||
[ 4.50472546, -0.48472026, 0.60729283, 0.33509624, -0.25593102,
|
||||
-1.45173049, 1.06727099, 0.00440830, -0.77340341, 0.67393088],
|
||||
[ 1.29453969, 0.07568165, 0.71947742, -0.71768606, -2.57172823,
|
||||
1.89179027, 3.26482797, 1.10493207, -1.04569530, -1.04862499]])
|
||||
"""
|
||||
if not flag[0]:
|
||||
flag[0] = True
|
||||
warnings.warn(
|
||||
"Currently, fused_dropout_add maybe has precision problem, so it falls back to dropout + add. "
|
||||
)
|
||||
return paddle_dropout_add(x, y, p, training=training, mode=mode)
|
||||
|
||||
if isinstance(p, (int, float)):
|
||||
# fast return for p == 0
|
||||
if p == 0:
|
||||
return x + y
|
||||
elif p < 0 or p > 1:
|
||||
raise ValueError("p argument should between 0 and 1")
|
||||
if mode not in ('downscale_in_infer', 'upscale_in_train'):
|
||||
raise ValueError(
|
||||
"mode argument should be 'downscale_in_infer' or 'upscale_in_train'"
|
||||
)
|
||||
seed = None
|
||||
if in_dynamic_or_pir_mode():
|
||||
if default_main_program().random_seed != 0:
|
||||
seed = default_main_program().random_seed
|
||||
out, seed_offset = _C_ops.fused_dropout_add(
|
||||
x,
|
||||
y,
|
||||
None,
|
||||
p,
|
||||
not training,
|
||||
mode,
|
||||
seed if seed is not None else 0,
|
||||
seed is not None,
|
||||
)
|
||||
return out
|
||||
else:
|
||||
helper = LayerHelper('fused_dropout_add', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
seed_offset = helper.create_variable_for_type_inference(
|
||||
dtype=core.VarDesc.VarType.INT64, stop_gradient=True
|
||||
)
|
||||
|
||||
def get_attrs(prog, dropout_prob, is_test, seed):
|
||||
if (seed is None or seed == 0) and prog.random_seed != 0:
|
||||
seed = prog.random_seed
|
||||
attrs = {
|
||||
'p': dropout_prob,
|
||||
'is_test': is_test,
|
||||
'mode': mode,
|
||||
'seed': seed if seed is not None else 0,
|
||||
'fix_seed': seed is not None,
|
||||
}
|
||||
return attrs
|
||||
|
||||
attrs = get_attrs(helper.main_program, p, not training, seed)
|
||||
|
||||
helper.append_op(
|
||||
type='fused_dropout_add',
|
||||
inputs={'x': x, 'y': y, 'seed_tensor': None},
|
||||
outputs={'out': [out], 'seed_offset': [seed_offset]},
|
||||
attrs=attrs,
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,174 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _legacy_C_ops
|
||||
from paddle.framework import in_dynamic_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fused_gate_attention(
|
||||
query: Tensor,
|
||||
key: Tensor | None = None,
|
||||
query_weight: Tensor | None = None,
|
||||
key_weight: Tensor | None = None,
|
||||
value_weight: Tensor | None = None,
|
||||
qkv_weight: Tensor | None = None,
|
||||
gate_linear_weight: Tensor | None = None,
|
||||
gate_linear_bias: Tensor | None = None,
|
||||
out_linear_weight: Tensor | None = None,
|
||||
out_linear_bias: Tensor | None = None,
|
||||
nonbatched_bias: Tensor | None = None,
|
||||
attn_mask: Tensor | None = None,
|
||||
has_gating: bool = True,
|
||||
merge_qkv: bool = True,
|
||||
use_flash_attn: bool = False,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Attention maps queries and a set of key-value pairs to outputs, and
|
||||
Gate Attention performs multiple parallel attention to jointly attending
|
||||
to information from different representation subspaces. This API only
|
||||
support self_attention. The pseudo code is as follows:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
c = c ** (-0.5)
|
||||
q = paddle.einsum('nbqa,ahc->nbqhc', q_data, query_w) * c
|
||||
k = paddle.einsum('nbka,ahc->nbkhc', m_data, key_w)
|
||||
v = paddle.einsum('nbka,ahc->nbkhc', m_data, value_w)
|
||||
logits = paddle.einsum('nbqhc,nbkhc->nbhqk', q, k) + bias
|
||||
|
||||
if nonbatched_bias is not None:
|
||||
logits += paddle.unsqueeze(nonbatched_bias, axis=1)
|
||||
|
||||
weights = paddle.nn.functional.softmax(logits)
|
||||
weighted_avg = paddle.einsum('nbhqk,nbkhc->nbqhc', weights, v)
|
||||
|
||||
if has_gating:
|
||||
gate_values = paddle.einsum('nbqc,chv->nbqhv', q_data, gating_w) + gating_b
|
||||
gate_values = paddle.nn.functional.sigmoid(gate_values)
|
||||
weighted_avg *= gate_values
|
||||
|
||||
output = paddle.einsum('nbqhc,hco->nbqo', weighted_avg, output_w) + output_b
|
||||
|
||||
|
||||
Args:
|
||||
query (Tensor): The input query tensor. The shape is [batch_size, msa_len, res_len, q_dim].
|
||||
key (Tensor, optional): The input key tensor, which can be set when
|
||||
merge_qkv is False. The shape is [batch_size, msa_len, m_size, kv_dim]. Default None.
|
||||
query_weight (Tensor, optional): The weight of query linear, which should be set when input
|
||||
key is not None. The shape is [q_dim, num_heads, head_dim]. Default None.
|
||||
key_weight (Tensor, optional): The weight of key linear, which should be set when input key
|
||||
is not None. The shape is [kv_dim, num_heads, head_dim]. Default None.
|
||||
value_weight (Tensor, optional): The weight of value linear, which should be set when input
|
||||
key is not None. The shape is [kv_dim, num_heads, head_dim]. Default None.
|
||||
qkv_weight (Tensor, optional): The weight of qkv linear, which should be set when merge_qkv
|
||||
is True. The shape is [3, num_heads, head_dim, q_dim]. Default None.
|
||||
gate_linear_weight (Tensor, optional): The weight of gating linear, which should be set when
|
||||
has_gating is True. The shape is [q_dim, num_heads, head_dim]. Default None.
|
||||
gate_linear_bias (Tensor, optional): The bias of gating linear, which should be set when
|
||||
has_gating is True. The shape is [num_heads, head_dim]. Default None.
|
||||
out_linear_weight (Tensor, optional): The weight of output linear. The shape is [num_heads, head_dim, q_dim]. Default None.
|
||||
out_linear_bias (Tensor): The bias of output linear, the shape is [q_dim]. Default None.
|
||||
nonbatched_bias (Tensor, optional): The extra bias. The shape is [batch_size, 1, num_heads, res_len, m_size]. Default None.
|
||||
attn_mask (Tensor, optional): The attention mask. The shape is [batch_size, msa_len, 1, 1, res_len]. Default None.
|
||||
has_gating (bool, optional): Whether has the gating linear. Default True.
|
||||
merge_qkv (bool, optional): Whether has the gating linear. Default True.
|
||||
use_flash_attn (bool, optional): Whether use flash-attention to speedup. Default False.
|
||||
|
||||
Returns:
|
||||
Tensor: The output Tensor, the data type and shape is same as `query`.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
|
||||
>>> # batch_size = 2
|
||||
>>> # msa_len = 4
|
||||
>>> # res_len = 2
|
||||
>>> # q_dim = 4
|
||||
>>> # num_heads = 8
|
||||
>>> # head_dim = 4
|
||||
>>> # m_size = res_len (when merge_qkv is True)
|
||||
|
||||
>>> # query: [batch_size, msa_len, res_len, q_dim]
|
||||
>>> query = paddle.rand(shape=[2, 4, 2, 4], dtype="float32")
|
||||
|
||||
>>> # qkv_weight: [3, n_heads, head_dim, q_dim]
|
||||
>>> qkv_weight = paddle.rand(shape=[3, 8, 4, 4], dtype="float32")
|
||||
|
||||
>>> # nonbatched_bias: [batch_size, 1, num_heads, res_len, m_size]
|
||||
>>> nonbatched_bias = paddle.rand(shape=[2, 1, 8, 2, 2], dtype="float32")
|
||||
|
||||
>>> # attn_mask: [batch_size, msa_len, 1, 1, m_size]
|
||||
>>> attn_mask = paddle.rand(shape=[2, 4, 1, 1, 2], dtype="float32")
|
||||
|
||||
>>> # gate_linear_weight: [q_dim, num_heads, head_dim]
|
||||
>>> gate_linear_weight = paddle.rand(shape=[4, 8, 4], dtype="float32")
|
||||
>>> # gate_bias: [num_heads, head_dim]
|
||||
>>> gate_linear_bias = paddle.rand(shape=[8, 4], dtype="float32")
|
||||
|
||||
>>> # out_linear_weight: [num_heads, head_dim, q_dim]
|
||||
>>> out_linear_weight = paddle.rand(shape=[8, 4, 4], dtype="float32")
|
||||
>>> # out_linear_bias: [q_dim]
|
||||
>>> out_linear_bias = paddle.rand(shape=[4], dtype="float32")
|
||||
|
||||
>>> # output: [batch_size, msa_len, res_len, q_dim]
|
||||
>>> output = F.fused_gate_attention(
|
||||
... query=query,
|
||||
... qkv_weight=qkv_weight,
|
||||
... gate_linear_weight=gate_linear_weight,
|
||||
... gate_linear_bias=gate_linear_bias,
|
||||
... out_linear_weight=out_linear_weight,
|
||||
... out_linear_bias=out_linear_bias,
|
||||
... nonbatched_bias=nonbatched_bias,
|
||||
... attn_mask=attn_mask,
|
||||
... has_gating=True,
|
||||
... merge_qkv=True,
|
||||
... )
|
||||
>>> print(output.shape)
|
||||
paddle.Size([2, 4, 2, 4])
|
||||
|
||||
"""
|
||||
if in_dynamic_mode():
|
||||
_, _, _, _, _, _, _, _, out = _legacy_C_ops.fused_gate_attention(
|
||||
query,
|
||||
key,
|
||||
query_weight,
|
||||
key_weight,
|
||||
value_weight,
|
||||
qkv_weight,
|
||||
nonbatched_bias,
|
||||
attn_mask,
|
||||
gate_linear_weight,
|
||||
gate_linear_bias,
|
||||
out_linear_weight,
|
||||
out_linear_bias,
|
||||
'has_gating',
|
||||
has_gating,
|
||||
'merge_qkv',
|
||||
merge_qkv,
|
||||
"use_flash_attn",
|
||||
use_flash_attn,
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,169 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, overload
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
@overload
|
||||
def fused_layer_norm(
|
||||
x: Tensor,
|
||||
norm_weight: Tensor,
|
||||
norm_bias: Tensor,
|
||||
epsilon: float,
|
||||
residual_alpha: float = ...,
|
||||
begin_norm_axis: int = ...,
|
||||
bias: Tensor | None = ...,
|
||||
residual: None = ...,
|
||||
quant_scale: float = ...,
|
||||
quant_round_type: float = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> Tensor: ...
|
||||
|
||||
|
||||
@overload
|
||||
def fused_layer_norm(
|
||||
x: Tensor,
|
||||
norm_weight: Tensor,
|
||||
norm_bias: Tensor,
|
||||
epsilon: float,
|
||||
residual_alpha: float = ...,
|
||||
begin_norm_axis: int = ...,
|
||||
bias: Tensor | None = ...,
|
||||
residual: Tensor = ...,
|
||||
quant_scale: float = ...,
|
||||
quant_round_type: float = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> tuple[Tensor, Tensor]: ...
|
||||
|
||||
|
||||
def fused_layer_norm(
|
||||
x,
|
||||
norm_weight,
|
||||
norm_bias,
|
||||
epsilon,
|
||||
residual_alpha=1.0,
|
||||
begin_norm_axis=1,
|
||||
bias=None,
|
||||
residual=None,
|
||||
quant_scale=-1,
|
||||
quant_round_type=0,
|
||||
quant_max_bound=0,
|
||||
quant_min_bound=0,
|
||||
):
|
||||
r"""
|
||||
Apply Fused LayerNorm kernel. Also support LayerNorm(bias + residual_alpha * residual + x) fused pattern.
|
||||
|
||||
when norm_weight and norm_bias is None, it return fused (bias + residual_alpha * residual + x)
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor..
|
||||
norm_weight (Tensor): the weight Tensor to affine output.
|
||||
norm_bias (Tensor): the bias Tensor to affine output.
|
||||
epsilon (float): a small float number to avoid divide 0.
|
||||
residual_alpha (float): a scale factor for residual. default is 1.
|
||||
begin_norm_axis (int): the begin axis to normalize. default is 1.
|
||||
bias (optional|Tensor): the previous layers's bias to fused.
|
||||
residual (optional|Tensor): the residual input to fused.
|
||||
quant_scale (float): the quant scale.
|
||||
quant_round_type (float): the quant round type.
|
||||
quant_max_bound (float): the quant max bound to clip.
|
||||
quant_min_bound (float): the quant min bound to clip.
|
||||
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> paddle_x = paddle.cast(paddle.randn(shape=[32, 256]), dtype=paddle.float16)
|
||||
>>> paddle_weight = paddle.cast(paddle.randn(shape=[256]), dtype=paddle.float32)
|
||||
>>> paddle_bias = paddle.cast(paddle.randn(shape=[256]), dtype=paddle.float32)
|
||||
>>> epsilon = 1e-6
|
||||
>>> paddle_layernorm = paddle.incubate.nn.functional.fused_layer_norm(paddle_x, paddle_weight, paddle_bias, epsilon, 1)
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_bias_residual_layernorm(
|
||||
x,
|
||||
bias,
|
||||
residual,
|
||||
norm_weight,
|
||||
norm_bias,
|
||||
epsilon,
|
||||
residual_alpha,
|
||||
begin_norm_axis,
|
||||
quant_scale,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
)
|
||||
# static mode
|
||||
helper = LayerHelper('fused_layernorm', **locals())
|
||||
out = None
|
||||
if quant_scale <= 0:
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
else:
|
||||
out = helper.create_variable_for_type_inference(dtype=paddle.int8)
|
||||
outputs_dict = {}
|
||||
outputs_dict['out'] = out
|
||||
outputs_dict['mean'] = helper.create_variable_for_type_inference(
|
||||
dtype=paddle.float32
|
||||
)
|
||||
outputs_dict['variance'] = helper.create_variable_for_type_inference(
|
||||
dtype=paddle.float32
|
||||
)
|
||||
|
||||
residual_out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
outputs_dict['residual_out'] = residual_out
|
||||
|
||||
inputs = {'x': x}
|
||||
if norm_weight is not None:
|
||||
inputs['norm_weight'] = norm_weight
|
||||
if norm_bias is not None:
|
||||
inputs['norm_bias'] = norm_bias
|
||||
if residual is not None:
|
||||
inputs['residual'] = residual
|
||||
if bias is not None:
|
||||
inputs['bias'] = bias
|
||||
|
||||
helper.append_op(
|
||||
type='fused_bias_residual_layernorm',
|
||||
inputs=inputs,
|
||||
attrs={
|
||||
"epsilon": epsilon,
|
||||
"residual_alpha": residual_alpha,
|
||||
"begin_norm_axis": begin_norm_axis,
|
||||
"quant_scale": quant_scale,
|
||||
"quant_round_type": quant_round_type,
|
||||
"quant_max_bound": quant_max_bound,
|
||||
"quant_min_bound": quant_min_bound,
|
||||
},
|
||||
outputs=outputs_dict,
|
||||
)
|
||||
return (out, residual_out, outputs_dict['mean'], outputs_dict['variance'])
|
||||
@@ -0,0 +1,215 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from paddle import _C_ops, _legacy_C_ops
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
from paddle.framework import (
|
||||
in_dynamic_mode,
|
||||
in_dynamic_or_pir_mode,
|
||||
in_pir_mode,
|
||||
)
|
||||
from paddle.tensor.linalg import matmul
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fused_matmul_bias(
|
||||
x: Tensor,
|
||||
y: Tensor,
|
||||
bias: Tensor | None = None,
|
||||
transpose_x: bool = False,
|
||||
transpose_y: bool = False,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Applies matrix multiplication of two tensors and then bias addition if provided.
|
||||
This method requires CUDA version >= 11.6.
|
||||
|
||||
Args:
|
||||
x (Tensor): the first input Tensor to be multiplied.
|
||||
y (Tensor): the second input Tensor to be multiplied. Its rank must be 2.
|
||||
bias (Tensor, optional): the input bias Tensor. If it is None, no bias addition would
|
||||
be performed. Otherwise, the bias is added to the matrix multiplication result. Default: None.
|
||||
transpose_x (bool, optional): Whether to transpose :math:`x` before multiplication. Default: False.
|
||||
transpose_y (bool, optional): Whether to transpose :math:`y` before multiplication. Default: False.
|
||||
name (str, optional): For detailed information, please refer to
|
||||
:ref:`api_guide_Name` . Usually name is no need to set and None by default.
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('fused_gemm_epilogue is only supported when CUDA version >= 11.6')
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_matmul_bias
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> x = paddle.randn([3, 5])
|
||||
>>> y = paddle.randn([4, 5])
|
||||
>>> bias = paddle.randn([5])
|
||||
>>> out = fused_matmul_bias(x, y, bias)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([3, 5])
|
||||
"""
|
||||
if bias is None:
|
||||
return matmul(x, y, transpose_x, transpose_y, name)
|
||||
if in_dynamic_or_pir_mode():
|
||||
out, _ = _C_ops.fused_gemm_epilogue(
|
||||
x, y, bias, transpose_x, transpose_y, "none"
|
||||
)
|
||||
return out
|
||||
|
||||
helper = LayerHelper('fused_matmul_bias', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
helper.append_op(
|
||||
type='fused_gemm_epilogue',
|
||||
inputs={'X': x, 'Y': y, 'Bias': bias},
|
||||
outputs={'Out': out},
|
||||
attrs={'trans_x': transpose_x, 'trans_y': transpose_y},
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def fused_linear(
|
||||
x: Tensor,
|
||||
weight: Tensor,
|
||||
bias: Tensor | None = None,
|
||||
transpose_weight: bool = False,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Fully-connected linear transformation operator. This method requires CUDA version >= 11.6.
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor to be multiplied.
|
||||
weight (Tensor): the weight Tensor to be multiplied. Its rank must be 2.
|
||||
bias (Tensor, optional): the input bias Tensor. If it is None, no bias addition would
|
||||
be performed. Otherwise, the bias is added to the matrix multiplication result. Default: None.
|
||||
transpose_weight (bool, optional): Whether to transpose :math:`weight` before multiplication. Default: False.
|
||||
name (str, optional): For detailed information, please refer to
|
||||
:ref:`api_guide_Name` . Usually name is no need to set and None by default.
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('fused_gemm_epilogue is only supported when CUDA version >= 11.6')
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_linear
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> x = paddle.randn([3, 4])
|
||||
>>> weight = paddle.randn([4, 5])
|
||||
>>> bias = paddle.randn([5])
|
||||
>>> out = fused_linear(x, weight, bias)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([3, 5])
|
||||
"""
|
||||
return fused_matmul_bias(x, weight, bias, False, transpose_weight, name)
|
||||
|
||||
|
||||
def fused_linear_activation(
|
||||
x: Tensor,
|
||||
y: Tensor,
|
||||
bias: Tensor,
|
||||
trans_x: bool = False,
|
||||
trans_y: bool = False,
|
||||
activation: Literal['gelu', 'relu'] | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Fully-connected linear and activation transformation operator. This method requires CUDA version >= 11.6.
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor to be multiplied.
|
||||
y (Tensor): the weight Tensor to be multiplied. Its rank must be 2.
|
||||
bias (Tensor): the input bias Tensor, the bias is added to the matrix multiplication result.
|
||||
trans_x (bool, optional): Whether to transpose :math:`x` before multiplication.
|
||||
trans_y (bool, optional): Whether to transpose :math:`y` before multiplication.
|
||||
activation (str, optional): Activation function, Currently, the available activation functions are
|
||||
limited to "gelu" (Gaussian Error Linear Unit) and "relu" (Rectified Linear Unit).
|
||||
These activation functions are applied to the output of the bias add. Default: None.
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +SKIP('fused_gemm_epilogue is only supported when CUDA version >= 11.6')
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import (
|
||||
... fused_linear_activation,
|
||||
... )
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> x = paddle.randn([3, 4])
|
||||
>>> weight = paddle.randn([4, 5])
|
||||
>>> bias = paddle.randn([5])
|
||||
>>> out = fused_linear_activation(x, weight, bias)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([3, 5])
|
||||
"""
|
||||
if activation is None:
|
||||
activation = "none"
|
||||
|
||||
if in_dynamic_mode():
|
||||
return _legacy_C_ops.fused_gemm_epilogue(
|
||||
x,
|
||||
y,
|
||||
bias,
|
||||
'trans_x',
|
||||
trans_x,
|
||||
'trans_y',
|
||||
trans_y,
|
||||
'activation',
|
||||
activation,
|
||||
)
|
||||
|
||||
if in_pir_mode():
|
||||
out, _ = _C_ops.fused_gemm_epilogue(
|
||||
x,
|
||||
y,
|
||||
bias,
|
||||
trans_x,
|
||||
trans_y,
|
||||
activation,
|
||||
)
|
||||
return out
|
||||
|
||||
helper = LayerHelper('fused_matmul_bias', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
helper.append_op(
|
||||
type='fused_gemm_epilogue',
|
||||
inputs={'X': x, 'Y': y, 'Bias': bias},
|
||||
outputs={'Out': out},
|
||||
attrs={
|
||||
'trans_x': trans_x,
|
||||
'trans_y': trans_y,
|
||||
'activation': activation,
|
||||
},
|
||||
)
|
||||
|
||||
return out
|
||||
@@ -0,0 +1,75 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fused_partial_rope(
|
||||
x: Tensor,
|
||||
cos: Tensor,
|
||||
sin: Tensor,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Applies partial rotary position embedding on the pe_head_dim portion of input.
|
||||
|
||||
Args:
|
||||
x (Tensor): The input tensor. The data type is bfloat16. The shape of x must be [batch_size, seq_len, num_heads, head_dim].
|
||||
cos (Tensor): The input tensor. The data type is bfloat16. The shape of cos must be [1, seq_len, 1, pe_head_dim] and pe_head_dim must be a multiple of 2 and mustn't exceed head_dim.
|
||||
sin (Tensor): The input tensor. The data type is bfloat16. The shape of sin must be [1, seq_len, 1, pe_head_dim] and pe_head_dim must be a multiple of 2 and mustn't exceed head_dim.
|
||||
|
||||
Returns:
|
||||
out: Tensor representing the fused rotary position embedding, has same shape and data type as `x` .
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_partial_rope
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
>>> paddle.seed(2025)
|
||||
|
||||
>>> # x: [batch_size, seq_len, num_heads, head_dim]
|
||||
>>> x = paddle.randn([2, 2, 2, 4], dtype='bfloat16')
|
||||
|
||||
>>> # sin, cos: [1, seq_len, 1, pe_head_dim]
|
||||
>>> cos = paddle.randn([1, 2, 1, 2], dtype='bfloat16')
|
||||
>>> sin = paddle.randn([1, 2, 1, 2], dtype='bfloat16')
|
||||
|
||||
>>> # out: [batch_size, seq_len, num_heads, head_dim]
|
||||
>>> out = fused_partial_rope(x, cos, sin)
|
||||
>>> print(out)
|
||||
Tensor(shape=[2, 2, 2, 4], dtype=bfloat16, place=Place(gpu:0), stop_gradient=True,
|
||||
[[[[-0.17968750, 0.28125000, -0.34765625, -0.92187500],
|
||||
[-0.83593750, 2. , -0.13476562, -0.67187500]],
|
||||
[[ 0.38281250, -0.63281250, 0.25000000, -1.03125000],
|
||||
[-1.92187500, 2.12500000, 1.92968750, -4.21875000]]],
|
||||
[[[-0.90625000, -1.62500000, -0.22167969, -0.68359375],
|
||||
[-0.76562500, 0.23828125, 0.36523438, 0.53515625]],
|
||||
[[ 0.92578125, -0.85156250, -0.75000000, 1.50000000],
|
||||
[ 0.41992188, -1.13281250, 0.73437500, -2.18750000]]]])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_partial_rope(x, cos, sin)
|
||||
@@ -0,0 +1,171 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, overload
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
@overload
|
||||
def fused_layer_norm(
|
||||
x: Tensor,
|
||||
norm_weight: Tensor,
|
||||
norm_bias: Tensor,
|
||||
epsilon: float,
|
||||
begin_norm_axis: int,
|
||||
bias: Tensor | None = ...,
|
||||
residual: None = ...,
|
||||
quant_scale: float = ...,
|
||||
quant_round_type: float = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> Tensor: ...
|
||||
|
||||
|
||||
@overload
|
||||
def fused_layer_norm(
|
||||
x: Tensor,
|
||||
norm_weight: Tensor,
|
||||
norm_bias: Tensor,
|
||||
epsilon: float,
|
||||
begin_norm_axis: int,
|
||||
bias: Tensor | None = ...,
|
||||
residual: Tensor = ...,
|
||||
quant_scale: float = ...,
|
||||
quant_round_type: float = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> tuple[Tensor, Tensor]: ...
|
||||
|
||||
|
||||
def fused_rms_norm(
|
||||
x,
|
||||
norm_weight,
|
||||
norm_bias,
|
||||
epsilon,
|
||||
begin_norm_axis=1,
|
||||
bias=None,
|
||||
residual=None,
|
||||
quant_scale=-1,
|
||||
quant_round_type=0,
|
||||
quant_max_bound=0,
|
||||
quant_min_bound=0,
|
||||
):
|
||||
r"""
|
||||
Apply Fused RMSNorm kernel. Also support RMSNorm(bias + residual + x) fused pattern.
|
||||
|
||||
Args:
|
||||
x (Tensor): the input Tensor..
|
||||
norm_weight (Tensor): the weight Tensor to affine output.
|
||||
norm_bias (Tensor): the bias Tensor to affine output.
|
||||
epsilon (float): a small float number to avoid divide 0.
|
||||
begin_norm_axis (int): the begin axis to normalize.
|
||||
bias (optional|Tensor): the previous layers's bias to fused.
|
||||
residual (optional|Tensor): the residual input to fused.
|
||||
quant_scale (float): the quant scale.
|
||||
quant_round_type (float): the quant round type.
|
||||
quant_max_bound (float): the quant max bound to clip.
|
||||
quant_min_bound (float): the quant min bound to clip.
|
||||
|
||||
|
||||
Returns:
|
||||
Tensor: the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> paddle_x = paddle.cast(paddle.randn(shape=[32, 256]), dtype=paddle.float16)
|
||||
>>> paddle_weight = paddle.cast(paddle.randn(shape=[256]), dtype=paddle.float16)
|
||||
>>> paddle_bias = paddle.cast(paddle.randn(shape=[256]), dtype=paddle.float16)
|
||||
>>> epsilon = 1e-6
|
||||
>>> paddle_rmsnorm = paddle.incubate.nn.functional.fused_rms_norm(paddle_x, paddle_weight, paddle_bias, epsilon, 1)
|
||||
"""
|
||||
input_rank = len(x.shape)
|
||||
if begin_norm_axis < 0:
|
||||
begin_norm_axis += input_rank
|
||||
|
||||
if begin_norm_axis < 0 or begin_norm_axis >= input_rank:
|
||||
raise ValueError(
|
||||
f"begin_norm_axis must be in range [0, {input_rank}), "
|
||||
f"but got {begin_norm_axis}"
|
||||
+ (
|
||||
f" (originally {begin_norm_axis - input_rank})"
|
||||
if begin_norm_axis < 0
|
||||
else ""
|
||||
)
|
||||
)
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_rms_norm_quant(
|
||||
x,
|
||||
bias,
|
||||
residual,
|
||||
norm_weight,
|
||||
norm_bias,
|
||||
epsilon,
|
||||
begin_norm_axis,
|
||||
quant_scale,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
)
|
||||
# static mode
|
||||
helper = LayerHelper('fused_rms_norm_quant', **locals())
|
||||
out = None
|
||||
if quant_scale <= 0:
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
else:
|
||||
out = helper.create_variable_for_type_inference(dtype=paddle.int8)
|
||||
outputs_dict = {}
|
||||
outputs_dict['out'] = out
|
||||
|
||||
residual_out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
outputs_dict['residual_out'] = residual_out
|
||||
|
||||
inv_var = helper.create_variable_for_type_inference(dtype=paddle.float32)
|
||||
outputs_dict['inv_var'] = inv_var
|
||||
|
||||
inputs = {'x': x, 'norm_weight': norm_weight}
|
||||
if norm_bias is not None:
|
||||
inputs['norm_bias'] = norm_bias
|
||||
if residual is not None:
|
||||
inputs['residual'] = residual
|
||||
if bias is not None:
|
||||
inputs['bias'] = bias
|
||||
|
||||
helper.append_op(
|
||||
type='fused_rms_norm_quant',
|
||||
inputs=inputs,
|
||||
attrs={
|
||||
"epsilon": epsilon,
|
||||
"begin_norm_axis": begin_norm_axis,
|
||||
"quant_scale": quant_scale,
|
||||
"quant_round_type": quant_round_type,
|
||||
"quant_max_bound": quant_max_bound,
|
||||
"quant_min_bound": quant_min_bound,
|
||||
},
|
||||
outputs=outputs_dict,
|
||||
)
|
||||
return (out, residual_out, outputs_dict['inv_var'])
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# File: python/paddle/incubate/nn/functional/layer_norm_cuda.py
|
||||
from paddle import _C_ops
|
||||
from paddle.base.data_feeder import convert_dtype
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
|
||||
def fused_rms_norm_ext(x, scale, epsilon=1e-5, name=None):
|
||||
"""
|
||||
Applies Layer Normalization over the last dimension of the input tensor using CUDA implementation.
|
||||
Args:
|
||||
x (Tensor): Input tensor of shape [rows, cols] or higher dimensions (flattened to 2D).
|
||||
scale (Tensor): Scale tensor of shape [cols].
|
||||
bias (Tensor, optional): Bias tensor of shape [cols]. If None, no bias is added.
|
||||
epsilon (float): Small constant to avoid division by zero.
|
||||
name (str, optional): Name of the operator.
|
||||
Returns:
|
||||
y (Tensor): Normalized tensor of same shape as x.
|
||||
mean (Tensor): Tensor of shape [rows], the mean of each row.
|
||||
invvar (Tensor): Tensor of shape [rows], the inverse standard deviation of each row.
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_rms_norm_ext(x, scale, epsilon)
|
||||
helper = LayerHelper('fused_rms_norm_ext', **locals())
|
||||
dtype = convert_dtype(x.dtype)
|
||||
y = helper.create_variable_for_type_inference(dtype)
|
||||
invvar = helper.create_variable_for_type_inference('float32')
|
||||
|
||||
inputs = {'x': x, 'scale': scale}
|
||||
|
||||
helper.append_op(
|
||||
type='fused_rms_norm_ext',
|
||||
inputs=inputs,
|
||||
outputs={'y': y, 'invvar': invvar},
|
||||
attrs={'epsilon': epsilon},
|
||||
)
|
||||
return y, invvar
|
||||
@@ -0,0 +1,158 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def fused_rotary_position_embedding(
|
||||
q: Tensor,
|
||||
k: Tensor | None = None,
|
||||
v: Tensor | None = None,
|
||||
sin: Tensor | None = None,
|
||||
cos: Tensor | None = None,
|
||||
position_ids: Tensor | None = None,
|
||||
use_neox_rotary_style: bool = True,
|
||||
time_major: bool = False,
|
||||
rotary_emb_base: float = 10000.0,
|
||||
) -> tuple[Tensor, Tensor, Tensor]:
|
||||
r"""
|
||||
Fused rotary position embedding.
|
||||
|
||||
Args:
|
||||
q (Tensor): The input tensor. The data type is bfloat16, float16, float32 or float64. The shape of q must be [batch_size, seq_len, num_heads, head_dim] or [seq_len, batch_size, num_heads, head_dim] and head_dim must be a multiple of 2.
|
||||
k (Tensor, optional): The input tensor. The data type is bfloat16, float16, float32 or float64. The shape of k must be [batch_size, seq_len, num_heads, head_dim] or [seq_len, batch_size, num_heads, head_dim] and head_dim must be a multiple of 2.
|
||||
v (Tensor, optional): The input tensor. The data type is bfloat16, float16, float32 or float64. The shape of v must be [batch_size, seq_len, num_heads, head_dim] or [seq_len, batch_size, num_heads, head_dim] and head_dim must be a multiple of 2.
|
||||
sin (Tensor, optional): The input tensor. The data type is bfloat16, float16, float32 or float64. The shape of sin must be [seq_len, head_dim] or [1, seq_len, 1, head_dim] and head_dim must be a multiple of 2.
|
||||
cos (Tensor, optional): The input tensor. The data type is bfloat16, float16, float32 or float64. The shape of cos must be [seq_len, head_dim] or [1, seq_len, 1, head_dim] and head_dim must be a multiple of 2.
|
||||
position_ids (Tensor, optional): The input tensor. The data type is int64. The shape of position_ids must be [batch_size, seq_len].
|
||||
use_neox_rotary_style(optional|bool): When the use_neox_rotary_style is True, every two adjacent numbers are calculated. When the use_neox_rotary_style is False, the numbers corresponding to the positions of the front half and back half segments are calculated. Default True.
|
||||
time_major(optional|bool): Whether the first dimension of the q, k, v input means the time steps. If time_major is True, the shape of Tensor is [seq_len, batch_size, num_heads, head_dim], otherwise [batch_size, seq_len, num_heads, head_dime]. Defaults to False. `time_steps` means the length of input sequence.
|
||||
rotary_emb_base(optional|float): the base of the rotary embedding. Default 10000.
|
||||
|
||||
Returns:
|
||||
out_q/out_k/out_v Tensor representing the fused rotary position embedding, has same shape and data type as `q` .
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import fused_rotary_position_embedding
|
||||
|
||||
>>> paddle.set_device('gpu')
|
||||
|
||||
>>> # batch_size = 2
|
||||
>>> # seq_len = 2
|
||||
>>> # num_heads = 2
|
||||
>>> # head_dim = 2
|
||||
|
||||
>>> paddle.seed(1204)
|
||||
|
||||
>>> # q, k, v: [batch_size, seq_len, num_heads, head_dim]
|
||||
>>> q = paddle.randn([2, 2, 2, 2], dtype='float16')
|
||||
>>> k = paddle.randn([2, 2, 2, 2], dtype='float16')
|
||||
>>> v = paddle.randn([2, 2, 2, 2], dtype='float16')
|
||||
|
||||
>>> # sin, cos: [1, seq_len, 1, head_dim]
|
||||
>>> x = paddle.randn([1, 2, 1, 2], dtype='float16')
|
||||
>>> y = paddle.randn([1, 2, 1, 2], dtype='float16')
|
||||
>>> sin = paddle.sin(x)
|
||||
>>> cos = paddle.cos(y)
|
||||
|
||||
>>> # position_ids: [batch_size, seq_len]
|
||||
>>> position_ids = paddle.randint(high=2, size=[2, 2], dtype='int64')
|
||||
|
||||
>>> # out_q, out_k, out_v: [batch_size, seq_len, num_heads, head_dim]
|
||||
>>> out_q, out_k, out_v = fused_rotary_position_embedding(
|
||||
... q, k, v, sin=sin, cos=cos, position_ids=position_ids, use_neox_rotary_style=False
|
||||
... )
|
||||
>>> print(out_q)
|
||||
>>> # doctest: +SKIP("Random output")
|
||||
Tensor(shape=[2, 2, 2, 2], dtype=float16, place=Place(gpu:0), stop_gradient=True,
|
||||
[[[[-0.54931641, 0.64990234],
|
||||
[-1.08691406, 1.18261719]],
|
||||
[[ 0.57812500, 0.11749268],
|
||||
[-0.63281250, 0.15551758]]],
|
||||
[[[-0.77050781, 0.07733154],
|
||||
[-0.73730469, -0.16735840]],
|
||||
[[ 0.07116699, -0.90966797],
|
||||
[-0.03628540, -0.20202637]]]])
|
||||
>>> # doctest: -SKIP
|
||||
"""
|
||||
if (sin is None) or (cos is None):
|
||||
assert position_ids is None, (
|
||||
"position_ids without sin/cos is not correctly supported now."
|
||||
)
|
||||
assert use_neox_rotary_style, (
|
||||
"rotate_half without sin/cos is not correctly supported now."
|
||||
)
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.fused_rotary_position_embedding(
|
||||
q,
|
||||
k,
|
||||
v,
|
||||
sin,
|
||||
cos,
|
||||
position_ids,
|
||||
use_neox_rotary_style,
|
||||
time_major,
|
||||
rotary_emb_base,
|
||||
)
|
||||
|
||||
helper = LayerHelper('fused_rotary_position_embedding', **locals())
|
||||
out_q = helper.create_variable_for_type_inference(dtype=q.dtype)
|
||||
out_k = (
|
||||
helper.create_variable_for_type_inference(dtype=k.dtype) if k else None
|
||||
)
|
||||
out_v = (
|
||||
helper.create_variable_for_type_inference(dtype=v.dtype) if v else None
|
||||
)
|
||||
|
||||
outputs = {'out_q': out_q}
|
||||
if out_k:
|
||||
outputs.update({'out_k': out_k})
|
||||
if out_v:
|
||||
outputs.update({'out_v': out_v})
|
||||
|
||||
helper.append_op(
|
||||
type='fused_rotary_position_embedding',
|
||||
inputs={
|
||||
'q': q,
|
||||
'k': k,
|
||||
'v': v,
|
||||
'sin': sin,
|
||||
'cos': cos,
|
||||
'position_ids': position_ids,
|
||||
},
|
||||
outputs=outputs,
|
||||
attrs={
|
||||
'use_neox_rotary_style': use_neox_rotary_style,
|
||||
'time_major': time_major,
|
||||
'rotary_emb_base': rotary_emb_base,
|
||||
},
|
||||
)
|
||||
|
||||
return out_q, out_k, out_v
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.base.data_feeder import convert_dtype
|
||||
from paddle.base.framework import (
|
||||
convert_nptype_to_datatype_or_vartype,
|
||||
core,
|
||||
in_dynamic_or_pir_mode,
|
||||
)
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
|
||||
def math_int_bincount(x, low, high, dtype):
|
||||
"""
|
||||
A mathematically equivalent implementation of int_bincount using scatter and sum
|
||||
|
||||
Args:
|
||||
x (Tensor): A 1D or 2D int64 tensor containing category indices.
|
||||
low (int): The minimum possible category index (usually 0).
|
||||
high (int): One past the maximum category index (i.e., number of categories).
|
||||
dtype (paddle.dtype): Data type of the output tensor (e.g., paddle.int64).
|
||||
|
||||
Returns:
|
||||
Tensor: A 1D tensor of shape [high - low], where each element is
|
||||
the count of occurrences of that category in `x`.
|
||||
"""
|
||||
if x.ndim not in [0, 1, 2]:
|
||||
raise ValueError(
|
||||
f"x must be a 0D, 1D or 2D tensor, but got ndim={x.ndim}"
|
||||
)
|
||||
|
||||
if x.dtype not in [paddle.int32, paddle.int64]:
|
||||
raise ValueError(f"x.dtype must be int32 or int64, but got {x.dtype}")
|
||||
|
||||
if dtype not in ['int32', 'int64', paddle.int32, paddle.int64]:
|
||||
raise ValueError(f"dtype must be 'int32' or 'int64', but got '{dtype}'")
|
||||
|
||||
if high < low:
|
||||
raise ValueError(
|
||||
f"'high' ({high}) must be greater than or equal to 'low' ({low})"
|
||||
)
|
||||
|
||||
if x.numel().item() == 0:
|
||||
return paddle.zeros([high - low], dtype=dtype)
|
||||
|
||||
if x.ndim == 0:
|
||||
x = x.reshape([-1]).unsqueeze(0) # Shape: [1, N]
|
||||
elif x.ndim == 1:
|
||||
x = x.unsqueeze(0) # Shape: [1, N]
|
||||
|
||||
x_min = x.min().item()
|
||||
x_max = x.max().item()
|
||||
|
||||
if x_min < 0:
|
||||
raise ValueError(
|
||||
f"Elements of x must be non-negative, but got min={x_min}"
|
||||
)
|
||||
|
||||
max_val = max(x_max + 1, high)
|
||||
mask = paddle.zeros([x.shape[0], max_val], dtype=x.dtype)
|
||||
mask = mask.put_along_axis(
|
||||
x, paddle.to_tensor(1.0, dtype=x.dtype), axis=1, reduce='add'
|
||||
)
|
||||
|
||||
count = paddle.sum(mask, axis=0).cast(dtype)
|
||||
return count[low:high]
|
||||
|
||||
|
||||
def int_bincount(x, low, high, dtype=None, name=None):
|
||||
if in_dynamic_or_pir_mode():
|
||||
if not isinstance(dtype, (core.VarDesc.VarType, core.DataType)):
|
||||
dtype = convert_nptype_to_datatype_or_vartype(dtype)
|
||||
|
||||
if paddle.is_compiled_with_xpu():
|
||||
return math_int_bincount(x, low, high, dtype)
|
||||
else:
|
||||
return _C_ops.int_bincount(x, low, high, dtype)
|
||||
|
||||
helper = LayerHelper("int_bincount", **locals())
|
||||
out_dtype = dtype if dtype is not None else x.dtype
|
||||
y = helper.create_variable_for_type_inference(dtype=out_dtype)
|
||||
dtype_attr = convert_dtype(out_dtype)
|
||||
|
||||
helper.append_op(
|
||||
type="int_bincount",
|
||||
inputs={"x": x},
|
||||
outputs={"y": y},
|
||||
attrs={
|
||||
"low": low,
|
||||
"high": high,
|
||||
"dtype": dtype_attr,
|
||||
},
|
||||
)
|
||||
return y
|
||||
@@ -0,0 +1,244 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, overload
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.utils.deprecated import deprecated
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
@overload
|
||||
def masked_multihead_attention(
|
||||
x: Tensor,
|
||||
cache_kv: Tensor | None = ...,
|
||||
bias: Tensor | None = ...,
|
||||
src_mask: Tensor | None = ...,
|
||||
cum_offsets: Tensor | None = ...,
|
||||
sequence_lengths: Tensor | None = ...,
|
||||
rotary_tensor: Tensor | None = ...,
|
||||
beam_cache_offset: None = ...,
|
||||
qkv_out_scale: Tensor | None = ...,
|
||||
out_shift: Tensor | None = ...,
|
||||
out_smooth: Tensor | None = ...,
|
||||
seq_len: int = ...,
|
||||
rotary_emb_dims: int = ...,
|
||||
use_neox_rotary_style: bool = ...,
|
||||
compute_dtype: str = ...,
|
||||
out_scale: float = ...,
|
||||
quant_round_type: int = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> tuple[Tensor, Tensor]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def masked_multihead_attention(
|
||||
x: Tensor,
|
||||
cache_kv: Tensor | None = ...,
|
||||
bias: Tensor | None = ...,
|
||||
src_mask: Tensor | None = ...,
|
||||
cum_offsets: Tensor | None = ...,
|
||||
sequence_lengths: Tensor | None = ...,
|
||||
rotary_tensor: Tensor | None = ...,
|
||||
beam_cache_offset: Tensor = ...,
|
||||
qkv_out_scale: Tensor | None = ...,
|
||||
out_shift: Tensor | None = ...,
|
||||
out_smooth: Tensor | None = ...,
|
||||
seq_len: int = ...,
|
||||
rotary_emb_dims: int = ...,
|
||||
use_neox_rotary_style: bool = ...,
|
||||
compute_dtype: str = ...,
|
||||
out_scale: float = ...,
|
||||
quant_round_type: int = ...,
|
||||
quant_max_bound: float = ...,
|
||||
quant_min_bound: float = ...,
|
||||
) -> tuple[Tensor, Tensor, Tensor]: ...
|
||||
|
||||
|
||||
@deprecated(
|
||||
since="3.4.0",
|
||||
level=1,
|
||||
update_to="paddle.nn.functional.scaled_dot_product_attention",
|
||||
)
|
||||
def masked_multihead_attention(
|
||||
x,
|
||||
cache_kv=None,
|
||||
bias=None,
|
||||
src_mask=None,
|
||||
cum_offsets=None,
|
||||
sequence_lengths=None,
|
||||
rotary_tensor=None,
|
||||
beam_cache_offset=None,
|
||||
qkv_out_scale=None,
|
||||
out_shift=None,
|
||||
out_smooth=None,
|
||||
seq_len=1,
|
||||
rotary_emb_dims=0,
|
||||
use_neox_rotary_style=False,
|
||||
compute_dtype='default',
|
||||
out_scale=-1,
|
||||
quant_round_type=1,
|
||||
quant_max_bound=127.0,
|
||||
quant_min_bound=-127.0,
|
||||
):
|
||||
r"""
|
||||
Masked Multi-head attention for text summarization.
|
||||
This is a fusion operator to compute masked multi-head attention in transformer model architecture.
|
||||
This operator only supports running on GPU.
|
||||
|
||||
Args:
|
||||
x (Tensor): The input tensor could be 2-D tensor. Its shape is [batch_size, 3 * num_head * head_dim].
|
||||
cache_kv (Tensor): The cache structure tensors for the generation model. Its shape is [2, batch_size, num_head, max_seq_len, head_dim].
|
||||
bias (Tensor, optional): The bias tensor. Its shape is [3, num_head, head_dim].
|
||||
src_mask (Tensor, optional): The src_mask tensor. Its shape is [batch_size, 1, 1, sequence_length].
|
||||
sequence_lengths (Tensor, optional): The sequence_lengths tensor, used to index input. Its shape is [batch_size, 1].
|
||||
rotary_tensor (Tensor, optional): The rotary_tensor tensor. The dtype must be float. Its shape is [batch_size, 1, 1, sequence_length, head_dim].
|
||||
beam_cache_offset (Tensor, optional): The beam_cache_offset tensor. Its shape is [batch_size, beam_size, max_seq_len + max_dec_len].
|
||||
qkv_out_scale (Tensor, optional): The qkv_out_scale tensor, used in quant. Its shape is [3, num_head, head_dim].
|
||||
out_shift (Tensor, optional): The out_shift tensor, used in quant.
|
||||
out_smooth (Tensor, optional): The out_smooth tensor, used in quant.
|
||||
seq_len (int, optional): The seq_len, used to get input length. Default 1.
|
||||
rotary_emb_dims (int, optional): The rotary_emb_dims. Default 1.
|
||||
use_neox_rotary_style (bool, optional): A flag indicating whether neox_rotary_style is needed or not. Default False.
|
||||
compute_dtype (string): A compute dtype, used to represent the input data type.
|
||||
out_scale (float, optional): The out_scale, used in quant.
|
||||
quant_round_type (int, optional): The quant_round_type, used in quant. Default 1.
|
||||
quant_max_bound (float, optional): The quant_max_bound, used in quant. Default 127.0.
|
||||
quant_min_bound (float, optional): The quant_min_bound, used in quant. Default -127.0.
|
||||
|
||||
Returns:
|
||||
Tensor|tuple: If "beam_cache_offset_out" is not none, return the
|
||||
tuple (output, cache_kvs_out, beam_cache_offset_out), which output is the output of
|
||||
masked_multihead_attention layers, cache_kvs_out is inplace with input `cache_kvs`.
|
||||
If "beam_cache_offset_out" is none, return the tuple (output, cache_kvs_out).
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> # input: [batch_size, 3 * num_head * dim_head]
|
||||
>>> x = paddle.rand(shape=(2, 3 * 32 * 128), dtype="float32")
|
||||
|
||||
>>> # src_mask: [batch_size, 1, 1, sequence_length]
|
||||
>>> src_mask = paddle.rand(shape=(2, 1, 1, 10), dtype="float32")
|
||||
|
||||
>>> # cache_kv: [2, batch_size, num_head, max_seq_len, dim_head]
|
||||
>>> cache_kv = paddle.rand(shape=(2, 2, 32, 64, 128), dtype="float32")
|
||||
|
||||
>>> output = F.masked_multihead_attention(
|
||||
... x,
|
||||
... src_mask=src_mask,
|
||||
... cache_kv=cache_kv,
|
||||
... )
|
||||
|
||||
"""
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.masked_multihead_attention_(
|
||||
x,
|
||||
cache_kv,
|
||||
bias,
|
||||
src_mask,
|
||||
cum_offsets,
|
||||
sequence_lengths,
|
||||
rotary_tensor,
|
||||
beam_cache_offset,
|
||||
qkv_out_scale,
|
||||
out_shift,
|
||||
out_smooth,
|
||||
seq_len,
|
||||
rotary_emb_dims,
|
||||
use_neox_rotary_style,
|
||||
compute_dtype,
|
||||
out_scale,
|
||||
quant_round_type,
|
||||
quant_max_bound,
|
||||
quant_min_bound,
|
||||
)
|
||||
|
||||
helper = LayerHelper('masked_multihead_attention', **locals())
|
||||
if x.dtype == "int32":
|
||||
if compute_dtype == "bf16":
|
||||
dtype = "uint16"
|
||||
elif compute_dtype == "fp16":
|
||||
dtype = "float16"
|
||||
elif compute_dtype == "fp32":
|
||||
dtype = "float32"
|
||||
out = helper.create_variable_for_type_inference(dtype=dtype)
|
||||
else:
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
|
||||
inputs = {}
|
||||
inputs['x'] = x
|
||||
inputs['cache_kv'] = cache_kv
|
||||
if bias is not None:
|
||||
inputs['bias'] = bias
|
||||
if src_mask is not None:
|
||||
inputs['src_mask'] = src_mask
|
||||
if cum_offsets is not None:
|
||||
inputs['cum_offsets'] = cum_offsets
|
||||
if sequence_lengths is not None:
|
||||
inputs['sequence_lengths'] = sequence_lengths
|
||||
if rotary_tensor is not None:
|
||||
inputs['rotary_tensor'] = rotary_tensor
|
||||
beam_cache_offset_flag = False
|
||||
if beam_cache_offset is not None:
|
||||
inputs['beam_cache_offset'] = beam_cache_offset
|
||||
beam_cache_offset_flag = True
|
||||
else:
|
||||
beam_cache_offset = helper.create_variable_for_type_inference(
|
||||
dtype="int"
|
||||
)
|
||||
if qkv_out_scale is not None:
|
||||
inputs['qkv_out_scale'] = qkv_out_scale
|
||||
if out_shift is not None:
|
||||
inputs['out_shift'] = out_shift
|
||||
if out_smooth is not None:
|
||||
inputs['out_smooth'] = out_smooth
|
||||
|
||||
outputs = {
|
||||
'out': out,
|
||||
'cache_kv_out': cache_kv,
|
||||
'beam_cache_offset_out': beam_cache_offset,
|
||||
}
|
||||
helper.append_op(
|
||||
type='masked_multihead_attention',
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
attrs={
|
||||
'seq_len': seq_len,
|
||||
'rotary_emb_dims': rotary_emb_dims,
|
||||
'use_neox_rotary_style': use_neox_rotary_style,
|
||||
'compute_dtype': compute_dtype,
|
||||
'out_scale': out_scale,
|
||||
'quant_round_type': quant_round_type,
|
||||
'quant_max_bound': quant_max_bound,
|
||||
'quant_min_bound': quant_min_bound,
|
||||
},
|
||||
)
|
||||
return (
|
||||
(out, cache_kv, beam_cache_offset)
|
||||
if beam_cache_offset_flag is not None
|
||||
else (out, cache_kv)
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_combine(
|
||||
x: Tensor,
|
||||
combine_weights: Tensor,
|
||||
scatter_index: Tensor,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
x: Input tensor [seq, dim]
|
||||
combine_weights: Combination weights [s, k]
|
||||
scatter_index: Scatter indices [k, s] dtype=int32
|
||||
|
||||
Returns:
|
||||
Output Combined output [s, dim]
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
if not (
|
||||
x.process_mesh is None
|
||||
and combine_weights.process_mesh is None
|
||||
and scatter_index.process_mesh is None
|
||||
):
|
||||
# auto parallel mode
|
||||
return _C_ops.moe_combine_auto(x, combine_weights, scatter_index)
|
||||
return _C_ops.moe_combine(x, combine_weights, scatter_index)
|
||||
helper = LayerHelper('moe_combine', **locals())
|
||||
y = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
inputs = {
|
||||
'x': x,
|
||||
'combine_weights': combine_weights,
|
||||
'scatter_index': scatter_index,
|
||||
}
|
||||
helper.append_op(type='moe_combine', inputs=inputs, outputs={'y': y})
|
||||
return y
|
||||
@@ -0,0 +1,57 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_combine_no_weight(
|
||||
x: Tensor,
|
||||
combine_weight: Tensor,
|
||||
scatter_index: Tensor,
|
||||
epsilon: float = 1e-15,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
x: Input tensor [num_tokens, hidden_size]
|
||||
scatter_index: Scatter indices [seq_len, k] dtype=int32
|
||||
|
||||
Returns:
|
||||
Output Combined output [seq_len, hidden_size]
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.moe_combine_no_weight(
|
||||
x, combine_weight, scatter_index, epsilon
|
||||
)
|
||||
helper = LayerHelper('moe_combine_no_weight', **locals())
|
||||
y = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
inputs = {
|
||||
'x': x,
|
||||
'combine_weight': combine_weight,
|
||||
'scatter_index': scatter_index,
|
||||
'epsilon': epsilon,
|
||||
}
|
||||
helper.append_op(
|
||||
type='moe_combine_no_weight', inputs=inputs, outputs={'y': y}
|
||||
)
|
||||
return y
|
||||
@@ -0,0 +1,280 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
|
||||
# from ....framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_gate_dispatch(
|
||||
x: Tensor,
|
||||
gate_logits: Tensor,
|
||||
corr_bias: Tensor,
|
||||
k: int,
|
||||
capacity: int,
|
||||
use_pad: bool,
|
||||
name: str | None = None,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Args:
|
||||
x:
|
||||
gate_logits:
|
||||
corr_bias:
|
||||
k:
|
||||
capacity:
|
||||
use_pad:
|
||||
|
||||
Returns:
|
||||
y:
|
||||
combine_weights:
|
||||
scatter_index:
|
||||
expert_offset:
|
||||
expert_id:
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
if paddle.device.is_compiled_with_custom_device('npu'):
|
||||
return math_moe_gate_dispatch(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad
|
||||
)
|
||||
else:
|
||||
if not (
|
||||
x.process_mesh is None and gate_logits.process_mesh is None
|
||||
):
|
||||
return _C_ops.moe_gate_dispatch_auto(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad
|
||||
)
|
||||
return _C_ops.moe_gate_dispatch(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad
|
||||
)
|
||||
|
||||
helper = LayerHelper('moe_gate_dispatch', **locals())
|
||||
y = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
combine_weights = helper.create_variable_for_type_inference(
|
||||
dtype=paddle.float32
|
||||
)
|
||||
scatter_index = helper.create_variable_for_type_inference(
|
||||
dtype=paddle.int32
|
||||
)
|
||||
expert_offset = helper.create_variable_for_type_inference(
|
||||
dtype=paddle.int64
|
||||
)
|
||||
expert_id = helper.create_variable_for_type_inference(dtype=paddle.int32)
|
||||
|
||||
inputs = {
|
||||
'x': x,
|
||||
'gate_logits': gate_logits,
|
||||
'corr_bias': corr_bias,
|
||||
}
|
||||
attrs = {
|
||||
'k': k,
|
||||
'capacity': capacity,
|
||||
'use_pad': use_pad,
|
||||
}
|
||||
outputs = {
|
||||
'y': y,
|
||||
'combine_weights': combine_weights,
|
||||
'scatter_index': scatter_index,
|
||||
'expert_offset': expert_offset,
|
||||
'expert_id': expert_id,
|
||||
}
|
||||
helper.append_op(
|
||||
type='moe_gate_dispatch',
|
||||
inputs=inputs,
|
||||
attrs=attrs,
|
||||
outputs=outputs,
|
||||
)
|
||||
return y, combine_weights, scatter_index, expert_offset, expert_id
|
||||
|
||||
|
||||
def topk_gating_softmax(
|
||||
gate_logits,
|
||||
corr_bias,
|
||||
topk,
|
||||
):
|
||||
# Calculate scores with bias added (used for Top-K selection)
|
||||
scores_for_selection = (
|
||||
gate_logits + corr_bias if corr_bias is not None else gate_logits
|
||||
)
|
||||
# Get Top-K indices
|
||||
combine_weights, expert_id = paddle.topk(
|
||||
scores_for_selection, k=topk, axis=1
|
||||
)
|
||||
|
||||
# Initialize source_rows: for each column, increment by 1 across rows,
|
||||
# then move to the next column after finishing one full column
|
||||
source_rows = paddle.to_tensor(
|
||||
[
|
||||
k_idx * gate_logits.shape[0] + row_idx
|
||||
for row_idx in range(gate_logits.shape[0])
|
||||
for k_idx in range(topk)
|
||||
]
|
||||
)
|
||||
return combine_weights, expert_id, source_rows
|
||||
|
||||
|
||||
def sorter_kernel(expert_id, source_rows):
|
||||
# Flatten all data
|
||||
flat_expert = expert_id.flatten()
|
||||
|
||||
# Global sorting index (sorted by expert_id in ascending order)
|
||||
sort_idx = paddle.argsort(flat_expert)
|
||||
|
||||
# Apply the sorting
|
||||
sorted_expert = paddle.gather(flat_expert, sort_idx)
|
||||
sorted_source = paddle.gather(source_rows, sort_idx)
|
||||
|
||||
# Reshape back to [num_rows, k]
|
||||
return (sorted_expert.reshape(expert_id.shape), sorted_source)
|
||||
|
||||
|
||||
def compute_total_rows_before_expert(permuted_experts, num_experts):
|
||||
expert_offset = paddle.searchsorted(
|
||||
permuted_experts.flatten(), paddle.arange(num_experts), right=True
|
||||
)
|
||||
return expert_offset
|
||||
|
||||
|
||||
def initialize_moe_routing_matrix(
|
||||
unpermuted_input,
|
||||
gate_logits,
|
||||
expanded_dest_row_to_expanded_source_row,
|
||||
permuted_experts,
|
||||
expert_offset,
|
||||
combine_weights,
|
||||
capacity,
|
||||
use_pad=False,
|
||||
):
|
||||
splits = paddle.concat(
|
||||
[
|
||||
paddle.to_tensor([0]),
|
||||
expert_offset,
|
||||
paddle.to_tensor([len(expanded_dest_row_to_expanded_source_row)]),
|
||||
]
|
||||
)
|
||||
expanded_dest_row_to_expanded_source_row = paddle.concat(
|
||||
[
|
||||
paddle.sort(
|
||||
expanded_dest_row_to_expanded_source_row[
|
||||
splits[i] : splits[i + 1]
|
||||
]
|
||||
)
|
||||
for i in range(len(splits) - 1)
|
||||
]
|
||||
)
|
||||
|
||||
expanded_source_row_to_expanded_dest_row = paddle.scatter_nd(
|
||||
index=expanded_dest_row_to_expanded_source_row.unsqueeze(1),
|
||||
updates=paddle.arange(
|
||||
expanded_dest_row_to_expanded_source_row.shape[0]
|
||||
),
|
||||
shape=[expanded_dest_row_to_expanded_source_row.shape[0]],
|
||||
)
|
||||
|
||||
y = paddle.zeros(
|
||||
[gate_logits.shape[1] * capacity, unpermuted_input.shape[1]],
|
||||
dtype=unpermuted_input.dtype,
|
||||
)
|
||||
|
||||
if use_pad:
|
||||
iexpert = paddle.gather(
|
||||
permuted_experts.flatten(),
|
||||
expanded_source_row_to_expanded_dest_row.flatten(),
|
||||
)
|
||||
|
||||
extended_offset = paddle.concat(
|
||||
[paddle.zeros([1], dtype='int64'), expert_offset]
|
||||
)
|
||||
offset = paddle.gather(extended_offset, iexpert)
|
||||
|
||||
iexpert_cap = iexpert * capacity
|
||||
row_in_expert = (
|
||||
expanded_source_row_to_expanded_dest_row.flatten() - offset
|
||||
)
|
||||
|
||||
input_indices = (
|
||||
paddle.arange(row_in_expert.shape[0]) % unpermuted_input.shape[0]
|
||||
)
|
||||
|
||||
y = paddle.scatter(
|
||||
x=y,
|
||||
index=row_in_expert + iexpert_cap,
|
||||
updates=unpermuted_input[input_indices],
|
||||
overwrite=True,
|
||||
)
|
||||
|
||||
expanded_source_row_to_expanded_dest_row = (
|
||||
expanded_source_row_to_expanded_dest_row
|
||||
+ iexpert_cap.reshape(
|
||||
expanded_source_row_to_expanded_dest_row.shape
|
||||
)
|
||||
- offset.reshape(expanded_source_row_to_expanded_dest_row.shape)
|
||||
)
|
||||
|
||||
expanded_source_row_to_expanded_dest_row = (
|
||||
expanded_source_row_to_expanded_dest_row.reshape(
|
||||
[combine_weights.shape[1], combine_weights.shape[0]]
|
||||
)
|
||||
)
|
||||
mask = (
|
||||
row_in_expert.reshape(
|
||||
[combine_weights.shape[1], combine_weights.shape[0]]
|
||||
)
|
||||
< capacity
|
||||
)
|
||||
|
||||
expanded_source_row_to_expanded_dest_row = paddle.where(
|
||||
mask,
|
||||
expanded_source_row_to_expanded_dest_row,
|
||||
paddle.zeros_like(expanded_source_row_to_expanded_dest_row),
|
||||
)
|
||||
combine_weights = paddle.where(
|
||||
mask.T, combine_weights, paddle.zeros_like(combine_weights)
|
||||
)
|
||||
|
||||
return y, expanded_source_row_to_expanded_dest_row, combine_weights
|
||||
|
||||
|
||||
def math_moe_gate_dispatch(x, gate_logits, corr_bias, k, capacity, use_pad):
|
||||
combine_weights, expert_id, source_rows = topk_gating_softmax(
|
||||
gate_logits, corr_bias, k
|
||||
)
|
||||
|
||||
permuted_experts, permuted_rows = sorter_kernel(expert_id, source_rows)
|
||||
|
||||
expert_offset = compute_total_rows_before_expert(
|
||||
permuted_experts, gate_logits.shape[1]
|
||||
)
|
||||
|
||||
y, scatter_index, combine_weights = initialize_moe_routing_matrix(
|
||||
x,
|
||||
gate_logits,
|
||||
permuted_rows,
|
||||
permuted_experts,
|
||||
expert_offset,
|
||||
combine_weights,
|
||||
capacity,
|
||||
use_pad,
|
||||
)
|
||||
|
||||
return y, combine_weights, scatter_index, expert_offset, expert_id
|
||||
@@ -0,0 +1,91 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.incubate.nn.functional import (
|
||||
fp8,
|
||||
moe_gate_dispatch,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_gate_dispatch_and_quant(
|
||||
x: Tensor,
|
||||
gate_logits: Tensor,
|
||||
corr_bias: Tensor,
|
||||
k: int,
|
||||
capacity: int,
|
||||
use_pad: bool,
|
||||
use_pow2_scale: bool,
|
||||
) -> tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]:
|
||||
"""
|
||||
Args:
|
||||
x: Input tensor [batch_size, seq_len, hidden_dim].
|
||||
gate_logits: Gate logits for choosing experts [batch_size, seq_len, num_experts].
|
||||
corr_bias: Optional correction bias to adjust gate logits.
|
||||
k: Top-k experts to be selected.
|
||||
capacity: The maximum number of tokens an expert can handle.
|
||||
use_pad: Boolean indicating if padding is used for uniform input length.
|
||||
use_pow2_scale: Boolean indicating if power-of-two scaling is applied for quantization.
|
||||
|
||||
Returns:
|
||||
Tuple of Tensors containing:
|
||||
- fp8_out: Processed output tensor in FP8 format.
|
||||
- scale: Scaling factors used during processing.
|
||||
- combine_weights: Weights for combining experts' outputs.
|
||||
- scatter_index: Indices for scattering inputs to experts.
|
||||
- expert_offset: Offset indices for each expert.
|
||||
- expert_id: IDs of selected experts for each position.
|
||||
"""
|
||||
if not in_dynamic_or_pir_mode():
|
||||
raise NotImplementedError('Static graph mode not implemented')
|
||||
else:
|
||||
if paddle.device.is_compiled_with_custom_device('npu'):
|
||||
return math_moe_gate_dispatch_and_quant(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad
|
||||
)
|
||||
else:
|
||||
return _C_ops.moe_gate_dispatch_and_quant(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad, use_pow2_scale
|
||||
)
|
||||
|
||||
|
||||
def math_moe_gate_dispatch_and_quant(
|
||||
x, gate_logits, corr_bias, k, capacity, use_pad, use_pow2_scale
|
||||
):
|
||||
y, combine_weights, scatter_index, expert_offset, expert_id = (
|
||||
moe_gate_dispatch(x, gate_logits, corr_bias, k, capacity, use_pad)
|
||||
)
|
||||
y_fp8, scale = fp8.fp8_quant_blockwise(
|
||||
y,
|
||||
quant_method="1x128",
|
||||
output_scale_transpose=False,
|
||||
using_pow2_scale=use_pow2_scale,
|
||||
)
|
||||
return (
|
||||
y_fp8,
|
||||
scale,
|
||||
combine_weights,
|
||||
scatter_index,
|
||||
expert_offset,
|
||||
expert_id,
|
||||
)
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_gate_dispatch_partial_nosoftmaxtopk(
|
||||
x: Tensor,
|
||||
combine_weights: Tensor,
|
||||
expert_id: Tensor,
|
||||
k: int,
|
||||
capacity: int,
|
||||
num_experts: int,
|
||||
use_pad: bool,
|
||||
expert_start_index: int,
|
||||
expert_end_index: int,
|
||||
reverse_token_drop: bool,
|
||||
name: str | None = None,
|
||||
) -> tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]:
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.moe_gate_dispatch_partial_nosoftmaxtopk(
|
||||
x,
|
||||
combine_weights,
|
||||
expert_id,
|
||||
k,
|
||||
capacity,
|
||||
num_experts,
|
||||
use_pad,
|
||||
expert_start_index,
|
||||
expert_end_index,
|
||||
reverse_token_drop,
|
||||
)
|
||||
helper = LayerHelper("moe_gate_dispatch_partial_nosoftmaxtopk", **locals())
|
||||
y = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
combine_weights_out = helper.create_variable_for_type_inference(
|
||||
dtype=combine_weights.dtype
|
||||
)
|
||||
scatter_index = helper.create_variable_for_type_inference(dtype='int32')
|
||||
scatter_index_rev = helper.create_variable_for_type_inference(dtype='int32')
|
||||
expert_offset = helper.create_variable_for_type_inference(dtype='int64')
|
||||
expert_nums_local = helper.create_variable_for_type_inference(dtype='int64')
|
||||
inputs = {
|
||||
"x": x,
|
||||
"combine_weights": combine_weights,
|
||||
"expert_id": expert_id,
|
||||
}
|
||||
outputs = {
|
||||
"y": y,
|
||||
"combine_weights_out": combine_weights_out,
|
||||
"scatter_index": scatter_index,
|
||||
"scatter_index_rev": scatter_index_rev,
|
||||
"expert_offset": expert_offset,
|
||||
"expert_nums_local": expert_nums_local,
|
||||
}
|
||||
attrs = {
|
||||
"k": k,
|
||||
"capacity": capacity,
|
||||
"num_experts": num_experts,
|
||||
"use_pad": use_pad,
|
||||
"expert_start_index": expert_start_index,
|
||||
"expert_end_index": expert_end_index,
|
||||
"reverse_token_drop": reverse_token_drop,
|
||||
}
|
||||
helper.append_op(
|
||||
type="moe_gate_dispatch_partial_nosoftmaxtopk",
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
attrs=attrs,
|
||||
)
|
||||
return (
|
||||
y,
|
||||
combine_weights_out,
|
||||
scatter_index,
|
||||
scatter_index_rev,
|
||||
expert_offset,
|
||||
expert_nums_local,
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.base.framework import in_dynamic_or_pir_mode
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def moe_gate_dispatch_permute(
|
||||
x: Tensor,
|
||||
gate_logits: Tensor,
|
||||
corr_bias: Tensor,
|
||||
k: int,
|
||||
capacity: int,
|
||||
world_size: int,
|
||||
name: str | None = None,
|
||||
) -> tuple[Tensor, Tensor, Tensor, Tensor, Tensor]:
|
||||
"""
|
||||
Dispatch and permute for Mixture of Experts (MoE).
|
||||
|
||||
Args:
|
||||
x: Input tensor [batch_size, seq_len, hidden_dim].
|
||||
gate_logits: Gate logits for choosing experts [batch_size, seq_len, num_experts].
|
||||
corr_bias: Optional correction bias to adjust gate logits.
|
||||
k: Top-k experts to be selected.
|
||||
capacity: The maximum number of tokens an expert can handle.
|
||||
world_size: Number of distributed processes.
|
||||
name: Optional name for the operation.
|
||||
|
||||
Returns:
|
||||
Tuple of Tensors containing:
|
||||
- y: Output tensor after dispatch and permute.
|
||||
- combine_weights: Weights for combining experts' outputs.
|
||||
- scatter_index: Indices for scattering inputs to experts.
|
||||
- expert_offset: Offset indices for each expert.
|
||||
- expert_id: IDs of selected experts for each position.
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.moe_gate_dispatch_permute(
|
||||
x, gate_logits, corr_bias, k, capacity, world_size
|
||||
)
|
||||
|
||||
helper = LayerHelper('moe_gate_dispatch_permute', **locals())
|
||||
y = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
combine_weights = helper.create_variable_for_type_inference(dtype='float')
|
||||
scatter_index = helper.create_variable_for_type_inference(dtype='int32')
|
||||
expert_offset = helper.create_variable_for_type_inference(dtype='int32')
|
||||
expert_id = helper.create_variable_for_type_inference(dtype='int32')
|
||||
|
||||
inputs = {
|
||||
'x': x,
|
||||
'gate_logits': gate_logits,
|
||||
'corr_bias': corr_bias if corr_bias is not None else None,
|
||||
}
|
||||
attrs = {'k': k, 'capacity': capacity, 'world_size': world_size}
|
||||
outputs = {
|
||||
'y': y,
|
||||
'combine_weights': combine_weights,
|
||||
'scatter_index': scatter_index,
|
||||
'expert_offset': expert_offset,
|
||||
'expert_id': expert_id,
|
||||
}
|
||||
|
||||
helper.append_op(
|
||||
type='moe_gate_dispatch_permute',
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
attrs=attrs,
|
||||
)
|
||||
return y, combine_weights, scatter_index, expert_offset, expert_id
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.utils import deprecated
|
||||
|
||||
from ....framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
@deprecated(
|
||||
since="3.3.0",
|
||||
update_to="paddle.nn.functional.swiglu",
|
||||
level=1,
|
||||
reason="paddle.incubate.nn.functional.swiglu will be removed in future. Please use paddle.nn.functional.swiglu instead.",
|
||||
)
|
||||
def swiglu(
|
||||
x: Tensor, y: Tensor | None = None, name: str | None = None
|
||||
) -> Tensor:
|
||||
"""
|
||||
This function performs SwiGLU activation to the input Tensor.
|
||||
|
||||
.. math::
|
||||
|
||||
out = silu(x) * y when y is not None
|
||||
out = silu(xs[0]) * xs[1] when y is None, where xs = paddle.chunk(x, 2, axis=-1)
|
||||
|
||||
Args:
|
||||
x (Tensor): The first input Tensor of SwiGLU.
|
||||
y (Tensor, optional): The second input Tensor of SwiGLU. Default: None.
|
||||
name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
|
||||
|
||||
Returns:
|
||||
A Tensor with the same data type with x and y.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> import paddle.incubate.nn.functional as F
|
||||
>>> x = paddle.to_tensor([1, 2], dtype='float32')
|
||||
>>> out1, out2 = F.swiglu(x), F.swiglu(x, x)
|
||||
>>> print(out1, out2)
|
||||
Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
|
||||
[1.46211720]) Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
|
||||
[0.73105860, 3.52318811])
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.swiglu(x, y)
|
||||
@@ -0,0 +1,143 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# The following codes are from https://github.com/facebookresearch/xformers
|
||||
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.framework import LayerHelper, in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
def variable_length_memory_efficient_attention(
|
||||
query: Tensor,
|
||||
key: Tensor,
|
||||
value: Tensor,
|
||||
seq_lens: Tensor,
|
||||
kv_seq_lens: Tensor,
|
||||
mask: Tensor | None = None,
|
||||
scale: float | None = None,
|
||||
causal: bool = False,
|
||||
pre_cache_length: int = 0,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Cutlass Memory Efficient Variable Attention.
|
||||
This method requires SM_ARCH in sm70, sm75, sm80.
|
||||
|
||||
Args:
|
||||
query (Tensor): The Query Tensor. Its shape is [batchsize, num_head, seq_len, head_size].
|
||||
key (Tensor): The Key Tensor. Its shape is [batchsize, num_head, seq_len, head_size].
|
||||
value (Tensor): The Value Tensor. Its shape is [batchsize, num_head, seq_len, head_size].
|
||||
seq_lens (Tensor): The sequence lengths of the sequences in the batch, used to index query. Its shape is [batchsize, 1].
|
||||
kv_seq_lens (Tensor): The sequence lengths of the sequences in the batch, used to index key and value. Its shape is [batchsize, 1].
|
||||
mask (Tensor|None, optional): The Mask Tensor. Its shape is [batchsize, 1, query_seq_len, key_seq_len].
|
||||
scale (Float|None, optional): The attention matrix's scale. Default is sqrt(1.0 / head_size).
|
||||
causal (Bool): Whether causal masking is used or not. Default is False.
|
||||
pre_cache_length (Int): The length of the pre-cache. Default is 0.
|
||||
Returns:
|
||||
Tensor, the output Tensor.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import math
|
||||
>>> import paddle
|
||||
>>> from paddle.incubate.nn.functional import (
|
||||
... variable_length_memory_efficient_attention,
|
||||
... )
|
||||
>>> paddle.device.set_device('gpu')
|
||||
|
||||
>>> batch = 1
|
||||
>>> num_head = 8
|
||||
>>> seq_len = 256
|
||||
>>> head_size = 32
|
||||
|
||||
>>> dtype = paddle.float16
|
||||
|
||||
>>> query = paddle.randn([batch, num_head, seq_len, head_size], dtype=dtype)
|
||||
>>> key = paddle.randn([batch, num_head, seq_len, head_size], dtype=dtype)
|
||||
>>> value = paddle.randn([batch, num_head, seq_len, head_size], dtype=dtype)
|
||||
>>> seq_lens = paddle.to_tensor(
|
||||
... [seq_len] * batch,
|
||||
... dtype='int32',
|
||||
... )
|
||||
>>> mask = paddle.randn([batch, 1, seq_len, seq_len], dtype=dtype)
|
||||
|
||||
>>> scale = float(1.0 / math.sqrt(head_size))
|
||||
>>> pre_cache_length = 0
|
||||
|
||||
>>> def naive_attention_impl(query, key, value, mask, scale):
|
||||
... qk_res = paddle.matmul(query, key, transpose_y=True)
|
||||
... attention = qk_res * scale
|
||||
... attention = attention + mask
|
||||
... softmax_result = paddle.nn.functional.softmax(attention, -1)
|
||||
... result = paddle.matmul(softmax_result, value)
|
||||
... return result
|
||||
|
||||
>>> out = naive_attention_impl(query, key, value, mask, scale)
|
||||
>>> # equals to: out = variable_length_memory_efficient_attention(query, key, value, seq_lens, seq_lens, mask, scale, pre_cache_length)
|
||||
|
||||
>>> out.shape # [batch, num_head, seq_len, head_size]
|
||||
paddle.Size([1, 8, 256, 32])
|
||||
"""
|
||||
if scale is None:
|
||||
head_size = query.shape[3]
|
||||
scale = float(1.0 / math.sqrt(head_size))
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.variable_length_memory_efficient_attention(
|
||||
query,
|
||||
key,
|
||||
value,
|
||||
seq_lens,
|
||||
kv_seq_lens,
|
||||
mask,
|
||||
scale,
|
||||
causal,
|
||||
pre_cache_length,
|
||||
)
|
||||
|
||||
helper = LayerHelper(
|
||||
'variable_length_memory_efficient_attention', **locals()
|
||||
)
|
||||
out = helper.create_variable_for_type_inference(dtype=query.dtype)
|
||||
helper.append_op(
|
||||
type='variable_length_memory_efficient_attention',
|
||||
inputs={
|
||||
'query': query,
|
||||
'key': key,
|
||||
'value': value,
|
||||
'seq_lens': seq_lens,
|
||||
'kv_seq_lens': kv_seq_lens,
|
||||
"mask": mask,
|
||||
},
|
||||
attrs={
|
||||
"scale": scale,
|
||||
"causal": causal,
|
||||
"pre_cache_length": pre_cache_length,
|
||||
},
|
||||
outputs={'out': out},
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from paddle.incubate.nn import functional as F
|
||||
from paddle.nn import Layer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
class FusedDropoutAdd(Layer):
|
||||
r"""
|
||||
Fused Dropout and Add.
|
||||
|
||||
Parameters:
|
||||
p (float|int, optional): Probability of setting units to zero. Default: 0.5
|
||||
mode(str, optional): ['upscale_in_train'(default) | 'downscale_in_infer']
|
||||
|
||||
1. upscale_in_train (default), upscale the output at training time
|
||||
|
||||
- train: :math:`out = x \times \frac{mask}{(1.0 - p)} + y`
|
||||
- inference: :math:`out = x + y`
|
||||
|
||||
2. downscale_in_infer, downscale the output at inference
|
||||
|
||||
- train: :math:`out = x \times mask + y`
|
||||
- inference: :math:`out = x \times (1.0 - p) + y`
|
||||
name (str, optional): Name for the operation, Default: None. For more information, please refer to :ref:`api_guide_Name`.
|
||||
|
||||
Shape:
|
||||
- x: N-D tensor.
|
||||
- y: N-D tensor.
|
||||
- output: N-D tensor, the same shape as x.
|
||||
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> paddle.device.set_device('gpu')
|
||||
>>> from paddle.incubate.nn.layer.fused_dropout_add import FusedDropoutAdd
|
||||
|
||||
>>> x = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], dtype="float32")
|
||||
>>> y = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], dtype="float32")
|
||||
|
||||
>>> m = FusedDropoutAdd(p=0.5)
|
||||
|
||||
>>> out = m(x, y)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
p: float = 0.5,
|
||||
mode: Literal[
|
||||
'upscale_in_train', 'downscale_in_infer'
|
||||
] = "upscale_in_train",
|
||||
name: str | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.p = p
|
||||
self.mode = mode
|
||||
self.name = name
|
||||
|
||||
def forward(self, x: Tensor, y: Tensor) -> Tensor:
|
||||
out = F.fused_dropout_add(
|
||||
x,
|
||||
y,
|
||||
p=self.p,
|
||||
training=self.training,
|
||||
mode=self.mode,
|
||||
name=self.name,
|
||||
)
|
||||
return out
|
||||
|
||||
def extra_repr(self) -> str:
|
||||
name_str = f', name={self.name}' if self.name else ''
|
||||
return f'p={self.p}, mode={self.mode}{name_str}'
|
||||
@@ -0,0 +1,141 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import paddle
|
||||
from paddle import _legacy_C_ops
|
||||
from paddle.framework import in_dynamic_mode
|
||||
|
||||
|
||||
class FusedDropout(paddle.nn.Layer):
|
||||
r"""
|
||||
Dropout is a regularization technique for reducing overfitting by preventing
|
||||
neuron co-adaption during training as described in the paper:
|
||||
`Improving neural networks by preventing co-adaptation of feature detectors <https://arxiv.org/abs/1207.0580>`_
|
||||
The dropout operator randomly sets the outputs of some units to zero, while upscale others
|
||||
according to the given dropout probability.
|
||||
|
||||
It is an optimized implementation for ``paddle.nn.Dropout``.
|
||||
|
||||
In dygraph mode, please use ``eval()`` to switch to evaluation mode, where dropout is disabled.
|
||||
|
||||
Parameters:
|
||||
p (float|int, optional): Probability of setting units to zero. Default: 0.5
|
||||
axis (int|list|tuple, optional): The axis along which the dropout is performed. Default: None.
|
||||
mode(str, optional): ['upscale_in_train'(default) | 'downscale_in_infer']
|
||||
|
||||
1. upscale_in_train (default), upscale the output at training time
|
||||
|
||||
- train: :math:`out = input \times \frac{mask}{(1.0 - p)}`
|
||||
- inference: :math:`out = input`
|
||||
|
||||
2. downscale_in_infer, downscale the output at inference
|
||||
|
||||
- train: :math:`out = input \times mask`
|
||||
- inference: :math:`out = input \times (1.0 - p)`
|
||||
name (str, optional): Name for the operation, Default: None. For more information, please refer to :ref:`api_guide_Name`.
|
||||
|
||||
Shape:
|
||||
- input: N-D tensor.
|
||||
- output: N-D tensor, the same shape as input.
|
||||
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> paddle.seed(2023)
|
||||
|
||||
>>> x = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], dtype="float32")
|
||||
>>> m = paddle.incubate.nn.FusedDropout(p=0.5)
|
||||
|
||||
>>> y_train = m(x)
|
||||
>>> print(y_train)
|
||||
Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True,
|
||||
[[0., 0., 6.],
|
||||
[0., 0., 0.]])
|
||||
|
||||
>>> m.eval() # switch the model to test phase
|
||||
>>> y_test = m(x)
|
||||
>>> print(y_test)
|
||||
Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True,
|
||||
[[1., 2., 3.],
|
||||
[4., 5., 6.]])
|
||||
"""
|
||||
|
||||
def __init__(self, p=0.5, axis=None, mode="upscale_in_train", name=None):
|
||||
super().__init__()
|
||||
|
||||
if not isinstance(p, (float, int)):
|
||||
raise TypeError("p argument should be a number")
|
||||
if p < 0 or p > 1:
|
||||
raise ValueError("p argument should between 0 and 1")
|
||||
|
||||
mode = (
|
||||
'downgrade_in_infer' if mode == 'downscale_in_infer' else mode
|
||||
) # semantic transfer
|
||||
if mode not in ('downscale_in_infer', 'upscale_in_train'):
|
||||
raise ValueError(
|
||||
"mode argument should be 'downscale_in_infer' or 'upscale_in_train'"
|
||||
)
|
||||
|
||||
if axis and not isinstance(axis, (int, list, tuple)):
|
||||
raise TypeError("datatype of axis argument should be int or list")
|
||||
|
||||
self.p = p
|
||||
self.mode = mode
|
||||
self.name = name
|
||||
|
||||
self.axis = None
|
||||
if axis is not None:
|
||||
self.axis = [axis] if isinstance(axis, int) else list(axis)
|
||||
|
||||
def forward(self, input):
|
||||
# fast return for p == 0
|
||||
if self.p == 0:
|
||||
return input
|
||||
|
||||
if self.axis is not None and in_dynamic_mode():
|
||||
seed = None
|
||||
if paddle.static.default_main_program().random_seed != 0:
|
||||
seed = paddle.static.default_main_program().random_seed
|
||||
|
||||
out, mask = _legacy_C_ops.dropout_nd(
|
||||
input,
|
||||
'dropout_prob',
|
||||
self.p,
|
||||
'is_test',
|
||||
not self.training,
|
||||
'fix_seed',
|
||||
seed is not None,
|
||||
'seed',
|
||||
seed if seed is not None else 0,
|
||||
'dropout_implementation',
|
||||
self.mode,
|
||||
'axis',
|
||||
self.axis,
|
||||
)
|
||||
else:
|
||||
out = paddle.nn.functional.dropout(
|
||||
input,
|
||||
p=self.p,
|
||||
axis=self.axis,
|
||||
training=self.training,
|
||||
mode=self.mode,
|
||||
name=self.name,
|
||||
)
|
||||
return out
|
||||
|
||||
def extra_repr(self):
|
||||
name_str = f', name={self.name}' if self.name else ''
|
||||
return f'p={self.p}, axis={self.axis}, mode={self.mode}{name_str}'
|
||||
@@ -0,0 +1,110 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle.incubate.nn import functional as F
|
||||
from paddle.nn import Layer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle._typing import ParamAttrLike
|
||||
|
||||
|
||||
class FusedLinear(Layer):
|
||||
r"""
|
||||
Linear layer takes only one multi-dimensional tensor as input with the
|
||||
shape :math:`[batch\_size, *, in\_features]` , where :math:`*` means any
|
||||
number of additional dimensions. It multiplies input tensor with the weight
|
||||
(a 2-D tensor of shape :math:`[in\_features, out\_features]` ) and produces
|
||||
an output tensor of shape :math:`[batch\_size, *, out\_features]` .
|
||||
If :math:`bias\_attr` is not False, the bias (a 1-D tensor of
|
||||
shape :math:`[out\_features]` ) will be created and added to the output.
|
||||
|
||||
Parameters:
|
||||
in_features (int): The number of input units.
|
||||
out_features (int): The number of output units.
|
||||
weight_attr (ParamAttr|None, optional): The attribute for the learnable
|
||||
weight of this layer. The default value is None and the weight will be
|
||||
initialized to zero. For detailed information, please refer to
|
||||
paddle.ParamAttr.
|
||||
transpose_weight (bool): Whether to transpose the `weight` Tensor before
|
||||
multiplication.
|
||||
bias_attr (ParamAttr|bool|None, optional): The attribute for the learnable bias
|
||||
of this layer. If it is set to False, no bias will be added to the output.
|
||||
If it is set to None or one kind of ParamAttr, a bias parameter will
|
||||
be created according to ParamAttr. For detailed information, please refer
|
||||
to paddle.ParamAttr. The default value is None and the bias will be
|
||||
initialized to zero.
|
||||
name (str|None, optional): Normally there is no need for user to set this parameter.
|
||||
For detailed information, please refer to :ref:`api_guide_Name` .
|
||||
|
||||
Attribute:
|
||||
**weight** (Parameter): the learnable weight of this layer.
|
||||
|
||||
**bias** (Parameter): the learnable bias of this layer.
|
||||
|
||||
Shape:
|
||||
- input: Multi-dimensional tensor with shape :math:`[batch\_size, *, in\_features]` .
|
||||
- output: Multi-dimensional tensor with shape :math:`[batch\_size, *, out\_features]` .
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:GPU)
|
||||
>>> import paddle
|
||||
>>> paddle.device.set_device('gpu')
|
||||
>>> from paddle.incubate.nn import FusedLinear
|
||||
|
||||
>>> x = paddle.randn([3, 4])
|
||||
>>> linear = FusedLinear(4, 5)
|
||||
>>> y = linear(x)
|
||||
>>> print(y.shape)
|
||||
paddle.Size([3, 5])
|
||||
"""
|
||||
|
||||
weight: Tensor
|
||||
bias: Tensor
|
||||
transpose_weight: bool
|
||||
name: str | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
in_features: int,
|
||||
out_features: int,
|
||||
weight_attr: ParamAttrLike | None = None,
|
||||
bias_attr: ParamAttrLike | None = None,
|
||||
transpose_weight: bool = False,
|
||||
name: str | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
if transpose_weight:
|
||||
weight_shape = [out_features, in_features]
|
||||
else:
|
||||
weight_shape = [in_features, out_features]
|
||||
dtype = self._helper.get_default_dtype()
|
||||
self.weight = self.create_parameter(
|
||||
shape=weight_shape, attr=weight_attr, dtype=dtype, is_bias=False
|
||||
)
|
||||
self.bias = self.create_parameter(
|
||||
shape=[out_features], attr=bias_attr, dtype=dtype, is_bias=True
|
||||
)
|
||||
self.transpose_weight = transpose_weight
|
||||
self.name = name
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
return F.fused_linear(
|
||||
input, self.weight, self.bias, self.transpose_weight, self.name
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,226 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import paddle
|
||||
|
||||
from ....base.framework import Variable
|
||||
from ....framework import LayerHelper, core
|
||||
|
||||
|
||||
class BlockGuardServ(paddle.static.nn.control_flow.BlockGuard):
|
||||
"""
|
||||
BlockGuardServ class.
|
||||
|
||||
BlockGuardServ class is used to create an op with a block in a program.
|
||||
"""
|
||||
|
||||
def __init__(self, server):
|
||||
if not (isinstance(server, ListenAndServ)):
|
||||
raise TypeError("BlockGuardServ takes a ListenAndServ")
|
||||
super().__init__(server.helper.main_program)
|
||||
self.server = server
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type is not None:
|
||||
return False
|
||||
|
||||
self.server.complete_op()
|
||||
return super().__exit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
|
||||
class ListenAndServ:
|
||||
"""
|
||||
**ListenAndServ Layer**
|
||||
|
||||
ListenAndServ is used to create a rpc server bind and listen
|
||||
on specific TCP port, this server will run the sub-block when
|
||||
received variables from clients.
|
||||
|
||||
Args:
|
||||
endpoint(string): IP:port string which the server will listen on.
|
||||
inputs(list): a list of variables that the server will get from clients.
|
||||
fan_in(int): how many client are expected to report to this server, default: 1.
|
||||
optimizer_mode(bool): whether to run the server as a parameter server, default: True.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # doctest: +REQUIRES(env:DISTRIBUTED)
|
||||
>>> from paddle.incubate.nn.layer.io import ListenAndServ
|
||||
>>> import paddle
|
||||
>>> paddle.enable_static()
|
||||
>>> place = paddle.CPUPlace()
|
||||
>>> main = paddle.static.Program()
|
||||
>>> with paddle.static.program_guard(main):
|
||||
... serv = ListenAndServ("127.0.0.1:6170", ["X"], optimizer_mode=False)
|
||||
... with serv.do():
|
||||
... x = paddle.static.data(shape=[32, 32], dtype='float32', name="X")
|
||||
... paddle.nn.initializer.Constant(value=1.0)(x, main.global_block())
|
||||
... paddle.scale(x=x, scale=10.0)
|
||||
|
||||
>>> exe = paddle.static.Executor(place)
|
||||
>>> exe.run(main)
|
||||
"""
|
||||
|
||||
def __init__(self, endpoint, inputs, fan_in=1, optimizer_mode=True):
|
||||
self.helper = LayerHelper("listen_and_serv")
|
||||
self.inputs = inputs
|
||||
self.outputs = []
|
||||
self.endpoint = endpoint
|
||||
self.fan_in = fan_in
|
||||
# FIXME(typhoonzero): add optimizer_mode is stupid, should make it more
|
||||
# general.
|
||||
self.optimizer_mode = optimizer_mode
|
||||
|
||||
def do(self):
|
||||
return BlockGuardServ(self)
|
||||
|
||||
def get_params_and_grads(self):
|
||||
main_program = self.helper.main_program
|
||||
current_block = main_program.current_block()
|
||||
parent_block = self.parent_block()
|
||||
# params and grads in the same order.
|
||||
params = []
|
||||
grads = []
|
||||
for op in current_block.ops:
|
||||
# FIXME(typhoonzero): op.inputs is None if it's cloned.
|
||||
if self.optimizer_mode:
|
||||
if "Grad" in op.inputs and "Param" in op.inputs:
|
||||
params.append(op.inputs["Param"].name)
|
||||
grads.append(op.inputs["Grad"].name)
|
||||
else:
|
||||
# simple recv mode, recv operators inputs.
|
||||
for iname in op.input_names:
|
||||
for in_var_name in op.input(iname):
|
||||
params.append(parent_block.var(in_var_name))
|
||||
grads.append(parent_block.var(in_var_name))
|
||||
|
||||
return params, grads
|
||||
|
||||
def parent_block(self):
|
||||
prog = self.helper.main_program
|
||||
parent_idx = prog.current_block().parent_idx
|
||||
assert parent_idx >= 0
|
||||
parent_block = prog.block(parent_idx)
|
||||
return parent_block
|
||||
|
||||
def complete_op(self):
|
||||
from paddle.incubate.distributed.fleet.parameter_server.mode import (
|
||||
DistributedMode,
|
||||
)
|
||||
|
||||
main_program = self.helper.main_program
|
||||
current_block = main_program.current_block()
|
||||
parent_block = self.parent_block()
|
||||
|
||||
parent_block.append_op(
|
||||
type='listen_and_serv',
|
||||
inputs={"X": self.inputs},
|
||||
outputs={},
|
||||
attrs={
|
||||
'endpoint': self.endpoint,
|
||||
'Fanin': self.fan_in,
|
||||
'optimize_blocks': [
|
||||
current_block
|
||||
], # did not support multiple optimize blocks in layers
|
||||
'distributed_mode': DistributedMode.SYNC, # did not support async now in layers
|
||||
'grad_to_block_id': [""],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def Send(endpoints, send_vars, dummy_output=None, sync=True):
|
||||
"""
|
||||
Send variables to the server side, and get vars from server
|
||||
side when server have finished running server side program.
|
||||
|
||||
Args:
|
||||
endpoints (str): comma separated IP:PORT pairs in the order
|
||||
of send_vars to send
|
||||
send_vars (list): variables to send to server
|
||||
sync (bool): whether to wait the request finish
|
||||
|
||||
"""
|
||||
assert type(send_vars) == list
|
||||
|
||||
if dummy_output is None:
|
||||
dummy_output = []
|
||||
elif isinstance(dummy_output, Variable):
|
||||
dummy_output = [dummy_output]
|
||||
|
||||
assert type(dummy_output) == list
|
||||
|
||||
epmap = endpoints.split(",")
|
||||
endpoints = list(set(epmap))
|
||||
|
||||
helper = LayerHelper("Send", **locals())
|
||||
rpc_op_role_name = core.op_proto_and_checker_maker.kOpRoleAttrName()
|
||||
|
||||
helper.append_op(
|
||||
type="send",
|
||||
inputs={"X": send_vars},
|
||||
outputs={"Out": dummy_output},
|
||||
attrs={
|
||||
"endpoints": endpoints,
|
||||
"epmap": epmap,
|
||||
rpc_op_role_name: core.op_proto_and_checker_maker.OpRole.RPC,
|
||||
},
|
||||
)
|
||||
if sync:
|
||||
helper.append_op(
|
||||
type="send_barrier",
|
||||
inputs={"X": dummy_output},
|
||||
outputs={"Out": []},
|
||||
attrs={"endpoints": endpoints},
|
||||
)
|
||||
|
||||
|
||||
def Recv(endpoints, get_vars, dummy_input=None, sync=True):
|
||||
"""
|
||||
Receive variables from server side
|
||||
|
||||
Args:
|
||||
endpoints (str): comma separated IP:PORT pairs in the order
|
||||
of send_vars to send
|
||||
get_vars (list): vars to get from server after send completes.
|
||||
sync (bool): whether to wait the request finish
|
||||
|
||||
Returns:
|
||||
list: list of received variables
|
||||
"""
|
||||
assert type(get_vars) == list
|
||||
|
||||
if dummy_input is None:
|
||||
dummy_input = []
|
||||
elif isinstance(dummy_input, Variable):
|
||||
dummy_input = [dummy_input]
|
||||
|
||||
assert type(dummy_input) == list
|
||||
|
||||
epmap = endpoints.split(",")
|
||||
endpoints = list(set(epmap))
|
||||
|
||||
helper = LayerHelper("Recv", **locals())
|
||||
helper.append_op(
|
||||
type="recv",
|
||||
inputs={"X": dummy_input},
|
||||
outputs={"Out": get_vars},
|
||||
attrs={"endpoints": endpoints, "epmap": epmap},
|
||||
)
|
||||
if sync:
|
||||
helper.append_op(
|
||||
type="fetch_barrier",
|
||||
outputs={"Out": get_vars},
|
||||
attrs={"endpoints": endpoints},
|
||||
)
|
||||
return get_vars
|
||||
@@ -0,0 +1,86 @@
|
||||
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from paddle import _C_ops
|
||||
from paddle.base.data_feeder import check_variable_and_dtype
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
from paddle import Tensor
|
||||
|
||||
_ReduceModeStringLiteral: TypeAlias = Literal['mean', 'sum', 'none']
|
||||
_ReduceModeNumberLiteral: TypeAlias = Literal[0, 1, 2]
|
||||
_ReduceMode: TypeAlias = _ReduceModeStringLiteral | _ReduceModeNumberLiteral
|
||||
|
||||
|
||||
def identity_loss(x: Tensor, reduction: _ReduceMode = "none") -> Tensor:
|
||||
r"""Marks a tensor as being part of the loss calculation for IPU.
|
||||
|
||||
This operator is used to handle on the (final) loss of a model so that
|
||||
it is used as the start of backpropagation.
|
||||
|
||||
When `reduction` is `none`, return raw `Out`.
|
||||
|
||||
When `reduction` is `mean`, return
|
||||
|
||||
.. math::
|
||||
Out = MEAN(Out)
|
||||
|
||||
When `reduction` is `sum`, return
|
||||
|
||||
.. math::
|
||||
Out = SUM(Out)
|
||||
|
||||
Parameters:
|
||||
x (Variable): The input tensor. The shapes is [N, *], where N is batch size and `*` means any number of
|
||||
additional dimensions. It's data type should be float32, float64 on CPU and float16, float32 on IPU.
|
||||
reduction(str|int, optional): Reduce the loss output. Supported string values are: 'sum', 'mean', 'none'
|
||||
the corresponding int values are 0, 1, 2 respectively. The default value is "none".
|
||||
|
||||
Returns:
|
||||
Variable: The loss ``Tensor`` with the specified reduction applied.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> paddle.enable_static()
|
||||
>>> loss = paddle.static.data(name="loss", shape=[-1, 1], dtype="float32")
|
||||
>>> out = paddle.incubate.identity_loss(loss, reduction=1)
|
||||
"""
|
||||
if isinstance(reduction, str):
|
||||
reduction = {"sum": 0, "mean": 1, "none": 2}.get(reduction.lower())
|
||||
if reduction is None:
|
||||
raise TypeError("Unsupported reduction type.")
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.identity_loss(x, reduction)
|
||||
|
||||
check_variable_and_dtype(x, 'x', ['float32', 'float64'], "identity_loss")
|
||||
attrs = {'reduction': reduction}
|
||||
helper = LayerHelper('identity_loss', **locals())
|
||||
dtype = helper.input_dtype(input_param_name='x')
|
||||
out = helper.create_variable_for_type_inference(dtype)
|
||||
helper.append_op(
|
||||
type="identity_loss", inputs={"X": x}, outputs={"Out": out}, attrs=attrs
|
||||
)
|
||||
return out
|
||||
@@ -0,0 +1,153 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# The following codes are from https://github.com/facebookresearch/xformers
|
||||
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
from paddle.base.layer_helper import LayerHelper
|
||||
from paddle.framework import in_dynamic_or_pir_mode
|
||||
|
||||
from .attn_bias import (
|
||||
BlockDiagonalCausalMask,
|
||||
BlockDiagonalCausalWithOffsetPaddedKeysMask,
|
||||
BlockDiagonalMask,
|
||||
LowerTriangularMask,
|
||||
LowerTriangularMaskWithTensorBias,
|
||||
)
|
||||
|
||||
SUPPORTED_ATTN_BIAS_TYPES = {
|
||||
type(None),
|
||||
paddle.Tensor,
|
||||
paddle.pir.Value,
|
||||
LowerTriangularMask,
|
||||
LowerTriangularMaskWithTensorBias,
|
||||
BlockDiagonalMask,
|
||||
BlockDiagonalCausalMask,
|
||||
BlockDiagonalCausalWithOffsetPaddedKeysMask,
|
||||
}
|
||||
|
||||
|
||||
def _get_seqlen_info(attn_bias):
|
||||
if isinstance(
|
||||
attn_bias,
|
||||
(BlockDiagonalMask, BlockDiagonalCausalWithOffsetPaddedKeysMask),
|
||||
):
|
||||
return (
|
||||
attn_bias.k_seqinfo.seqstart,
|
||||
attn_bias.q_seqinfo.seqstart,
|
||||
attn_bias.q_seqinfo.max_seqlen,
|
||||
attn_bias.k_seqinfo.max_seqlen,
|
||||
)
|
||||
else:
|
||||
return None, None, -1, -1
|
||||
|
||||
|
||||
def _get_tensor_bias(attn_bias):
|
||||
if isinstance(attn_bias, (paddle.Tensor, paddle.pir.Value)):
|
||||
return attn_bias
|
||||
elif isinstance(attn_bias, LowerTriangularMaskWithTensorBias):
|
||||
return attn_bias._bias
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def memory_efficient_attention(
|
||||
query, key, value, attn_bias=None, p=0.0, scale=None, training=True
|
||||
):
|
||||
assert type(attn_bias) in SUPPORTED_ATTN_BIAS_TYPES
|
||||
causal = isinstance(
|
||||
attn_bias,
|
||||
(
|
||||
LowerTriangularMask,
|
||||
BlockDiagonalCausalMask,
|
||||
BlockDiagonalCausalWithOffsetPaddedKeysMask,
|
||||
),
|
||||
)
|
||||
seqstart_k, seqstart_q, max_seqlen_q, max_seqlen_k = _get_seqlen_info(
|
||||
attn_bias
|
||||
)
|
||||
# NOTE: compute_logsumexp = training
|
||||
causal_diagonal = (
|
||||
attn_bias.causal_diagonal
|
||||
if isinstance(attn_bias, BlockDiagonalCausalWithOffsetPaddedKeysMask)
|
||||
else None
|
||||
)
|
||||
seqlen_k = (
|
||||
attn_bias.k_seqinfo.seqlen
|
||||
if isinstance(attn_bias, BlockDiagonalCausalWithOffsetPaddedKeysMask)
|
||||
else None
|
||||
)
|
||||
if scale is None:
|
||||
scale = -1.0
|
||||
|
||||
bias = _get_tensor_bias(attn_bias)
|
||||
is_test = not training
|
||||
|
||||
if in_dynamic_or_pir_mode():
|
||||
output, logsumexp, seed_and_offset = _C_ops.memory_efficient_attention(
|
||||
query,
|
||||
key,
|
||||
value,
|
||||
bias,
|
||||
seqstart_q,
|
||||
seqstart_k,
|
||||
causal_diagonal,
|
||||
seqlen_k,
|
||||
max_seqlen_q,
|
||||
max_seqlen_k,
|
||||
causal,
|
||||
p,
|
||||
scale,
|
||||
is_test,
|
||||
)
|
||||
return output
|
||||
|
||||
helper = LayerHelper('memory_efficient_attention', **locals())
|
||||
output = helper.create_variable_for_type_inference(dtype=query.dtype)
|
||||
logsumexp = helper.create_variable_for_type_inference(dtype='float')
|
||||
seed_and_offset = helper.create_variable_for_type_inference(dtype='int32')
|
||||
helper.append_op(
|
||||
type='memory_efficient_attention',
|
||||
inputs={
|
||||
'query': query,
|
||||
'key': key,
|
||||
'value': value,
|
||||
'bias': bias,
|
||||
"cu_seqlens_q": seqstart_q,
|
||||
"cu_seqlens_k": seqstart_k,
|
||||
"causal_diagonal": causal_diagonal,
|
||||
"seqlen_k": seqlen_k,
|
||||
},
|
||||
attrs={
|
||||
"max_seqlen_q": max_seqlen_q,
|
||||
"max_seqlen_k": max_seqlen_k,
|
||||
"causal": causal,
|
||||
"dropout_p": p,
|
||||
"scale": scale,
|
||||
"is_test": is_test,
|
||||
},
|
||||
outputs={
|
||||
'output': output,
|
||||
'logsumexp': logsumexp,
|
||||
"seed_and_offset": seed_and_offset,
|
||||
},
|
||||
)
|
||||
|
||||
return output
|
||||
Reference in New Issue
Block a user