Files
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

191 lines
6.6 KiB
Python

# 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
import paddle.distributed as dist
from paddle.distributed import fleet
from paddle.distributed.fleet.utils.sequence_parallel_utils import (
_check_environment_for_overlap,
)
from paddle.framework import core
from paddlenlp.transformers.llama.modeling_auto import get_mesh
def is_fused_matmul_bias_supported():
if paddle.is_compiled_with_cuda() and not paddle.is_compiled_with_rocm() or paddle.is_compiled_with_xpu():
return hasattr(core.eager.ops.legacy, "fused_gemm_epilogue")
else:
return False
ipp = None
id2ipp = {}
paddle_nn_functional_linear = paddle.nn.functional.linear
if is_fused_matmul_bias_supported():
paddle_incubate_nn_functional_fused_linear = paddle.incubate.nn.functional.fused_linear
# modify from Paddle/python/paddle/distributed/auto_parallel/moe_utils.py
def _dist_reshape(
dist_tensor,
global_shape,
mesh,
placements,
):
local_tensor = dist_tensor._local_value()
tgt_global_shape = [dist_tensor.shape[0] * dist_tensor.shape[1], dist_tensor.shape[2]]
tgt_local_shape = [local_tensor.shape[0] * local_tensor.shape[1], local_tensor.shape[2]]
place = paddle.framework._current_expected_place()
place = paddle.framework._get_paddle_place(place)
local_tensor = local_tensor.reshape(tgt_local_shape)
if placements[1].is_shard():
new_placements = [dist.Shard(0), dist.Shard(1)]
else:
new_placements = [dist.Shard(0), dist.Replicate()]
out = paddle.Tensor(
local_tensor,
dims=tgt_global_shape,
process_mesh=mesh,
placements=new_placements,
place=place,
)
out.stop_gradient = dist_tensor.stop_gradient
return out
if is_fused_matmul_bias_supported():
origin_linear = paddle.incubate.nn.functional.fused_linear
else:
origin_linear = paddle.nn.functional.linear
class FusedLinearWithReduceScatter(paddle.autograd.PyLayer):
@staticmethod
def forward(ctx, x, weight, bias=None, name=None):
global ipp
input_parallel = dist.reshard(
x,
get_mesh(ipp),
[dist.Shard(1), dist.Replicate()],
)
y = origin_linear(input_parallel, weight, bias)
ctx.save_for_backward(weight, bias, input_parallel)
return y
@staticmethod
def backward(ctx, dy):
weight, bias, input_parallel = ctx.saved_tensor()
# compute dx
if dy.dtype == weight.dtype:
dinput_parallel = paddle.matmul(dy, weight, transpose_y=True)
else:
dinput_parallel = paddle.matmul(dy, paddle.cast(weight, dtype=dy.dtype), transpose_y=True)
hcg = fleet.get_hybrid_communicate_group()
model_parallel_group = hcg.get_model_parallel_group()
parallelism = model_parallel_group.nranks
assert (
dinput_parallel.shape[0] % parallelism == 0
), f"Input sequence length {dinput_parallel.shape[0]} can't be divided exactly by sequence parallelism {parallelism}"
# reduce-scatter dx
dx_global_shape = dinput_parallel.shape
dx_global_shape[0] = dx_global_shape[0] // parallelism
dinput_parallel_local = dinput_parallel._local_value()
dx_local_shape = dinput_parallel_local.shape
dx_local_shape[0] = dx_local_shape[0] // parallelism
dx_local = paddle.empty(shape=dx_local_shape, dtype=dinput_parallel.dtype)
task = dist.stream.reduce_scatter(
dx_local,
dinput_parallel_local,
op=dist.ReduceOp.SUM,
group=model_parallel_group,
sync_op=False,
)
# compute dw and dbias
_check_environment_for_overlap()
dy = _dist_reshape(dy, [-1, dy.shape[-1]], dy.process_mesh, dy.placements)
input_parallel = _dist_reshape(
input_parallel, [-1, input_parallel.shape[-1]], input_parallel.process_mesh, input_parallel.placements
)
dw = paddle.matmul(
input_parallel,
dy,
transpose_x=True,
)
if bias is None:
task.wait()
place = paddle.framework._current_expected_place()
place = paddle.framework._get_paddle_place(place)
dx = paddle.Tensor(
dx_local,
dims=dx_global_shape,
process_mesh=dinput_parallel.process_mesh,
placements=[dist.Shard(1), dist.Shard(0)],
place=place,
)
dx.stop_gradient = dx.stop_gradient
return dx, dw
else:
dbias = paddle.sum(dy, axis=0)
task.wait()
place = paddle.framework._current_expected_place()
place = paddle.framework._get_paddle_place(place)
dx = paddle.Tensor(
dx_local,
dims=dx_global_shape,
process_mesh=dinput_parallel.process_mesh,
placements=[dist.Shard(1), dist.Shard(0)],
place=place,
)
dx.stop_gradient = dx.stop_gradient
return dx, dw, dbias
def forward_pre_hook(layer, input):
paddle.nn.functional.linear = FusedLinearWithReduceScatter.apply
if is_fused_matmul_bias_supported():
paddle.incubate.nn.functional.fused_linear = FusedLinearWithReduceScatter.apply
global ipp, id2ipp
ipp = id2ipp[id(layer)]
def forward_post_hook(layer, input, output):
paddle.nn.functional.linear = paddle_nn_functional_linear
if is_fused_matmul_bias_supported():
paddle.incubate.nn.functional.fused_linear = paddle_incubate_nn_functional_fused_linear
def mock_layers_sp_async_reduce_scatter(model):
global ipp, id2ipp
for name, layer in model.named_sublayers():
if name.endswith("self_attn") or name.startswith("mlp"):
ipp = layer.ipp
for n in ["qkv_proj", "q_proj", "k_proj", "v_proj", "gate_up_fused_proj", "gate_proj", "up_proj"]:
if name.endswith(n):
id2ipp[id(layer)] = ipp
layer.register_forward_pre_hook(forward_pre_hook)
layer.register_forward_post_hook(forward_post_hook)