Files
paddlepaddle--paddlenlp/paddlenlp/transformers/sequence_parallel_utils.py
T
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

140 lines
4.8 KiB
Python

# Copyright (c) 2024, NVIDIA CORPORATION. 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 numpy as np
import paddle
from paddle import distributed as dist
from paddle.autograd import PyLayer
from paddle.distributed import fleet
####################################################
# #
# Distributed Communication Operator #
# #
####################################################
def get_hcg():
"""
get the hybrid comm group from fleet
"""
return fleet.get_hybrid_communicate_group()
def scatter(input):
hcg = get_hcg()
group = hcg.get_model_parallel_group()
parallelism = group.nranks
rank = group.rank
seq_len = input.shape[0]
assert (
seq_len % parallelism == 0
), "Input sequence length {} can't be divided exactly by sequence parallelism {}".format(seq_len, parallelism)
interval = seq_len // parallelism
input = paddle.slice(input, axes=[0], starts=[interval * rank], ends=[interval * (rank + 1)])
input = paddle.assign(input)
return input
def all_gather(input):
hcg = get_hcg()
group = hcg.get_model_parallel_group()
parallelism = group.nranks
output_shape = input.shape
output_shape[0] = output_shape[0] * parallelism
output = paddle.empty(shape=output_shape, dtype=input.dtype)
group.process_group.all_gather(input, output).wait()
return output
###################################################
# #
# Modified Parallel Linear Operator #
# #
###################################################
class AllGatherVarlenOp(PyLayer):
"""the shape of allgather can be not same for each rank"""
@staticmethod
def forward(ctx, input):
"""Forward pass."""
hcg = fleet.get_hybrid_communicate_group()
group = hcg.get_model_parallel_group()
shape0 = paddle.to_tensor([input.shape[0]])
shape0_all = paddle.empty(shape=[group.nranks], dtype=shape0.dtype)
dist.stream.all_gather(shape0_all, shape0, group=group, use_calc_stream=True)
shape0_all = shape0_all.numpy()
max_shape0 = shape0_all.max()
indices = []
for idx, s in enumerate(shape0_all):
offset = idx * max_shape0
indices.append(list(range(offset, offset + s)))
indices = np.concatenate(indices, axis=0)
indices = indices.reshape([-1] + [1] * (len(input.shape) - 1))
indices = paddle.to_tensor(indices)
padding = max_shape0 - input.shape[0]
ctx.shape0 = input.shape[0]
ctx.max_shape0 = max_shape0
ctx.shape0_all = shape0_all
ctx.padding = padding
ctx.indices = indices
if padding > 0:
input_shape = input.shape
input_shape[0] = padding
padding_tensor = paddle.empty(shape=input_shape, dtype=input.dtype)
input = paddle.concat([input, padding_tensor], axis=0)
output = all_gather(input)
output = paddle.take_along_axis(output, indices, axis=0)
return output
@staticmethod
def backward(ctx, grad):
"""Backward pass."""
input_shape = grad.shape
input_shape[0] = ctx.max_shape0 * ctx.shape0_all.shape[0]
output = paddle.zeros(shape=input_shape, dtype=grad.dtype)
grad = paddle.scatter(output, ctx.indices, grad)
grad = scatter(grad)
if ctx.padding > 0:
grad = grad[: ctx.shape0]
return grad
def sequence_parallel_sparse_mask_labels(labels, ignore_label=-100):
"""allgather sparse label and return sparse idx"""
hcg = fleet.get_hybrid_communicate_group()
group = hcg.get_model_parallel_group()
labels = labels.flatten()
labels_local = paddle.split(labels, group.nranks)[group.rank]
tgt_index = paddle.nonzero(labels_local != ignore_label).squeeze()
# NOTE(hehuang): There will be at least one label in each rank.
if tgt_index.numel() == 0:
tgt_index = paddle.to_tensor([0])
tgt_index = tgt_index.reshape([-1])
labels_local_gather = paddle.take_along_axis(labels_local, tgt_index, axis=0)
labels_all_gather = AllGatherVarlenOp.apply(labels_local_gather)
return labels_all_gather, tgt_index.reshape([-1, 1])