Files
paddlepaddle--paddle/test/auto_parallel/pir/mlp_demo.py
T
2026-07-13 12:40:42 +08:00

278 lines
8.8 KiB
Python

# 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.
import random
import unittest
import numpy as np
from test_to_static_pir_program import (
DemoNet,
create_data_loader,
)
import paddle
import paddle.distributed as dist
from paddle import nn
BATCH_SIZE = 4
BATCH_NUM = 40
IMAGE_SIZE = 16
CLASS_NUM = 8
np.random.seed(2024)
paddle.seed(2024)
class PPDemoNet(nn.Layer):
def __init__(self, mesh1, mesh2):
super().__init__()
self._mesh1 = mesh1
self._mesh2 = mesh2
self.linear_0 = nn.Linear(IMAGE_SIZE, IMAGE_SIZE, bias_attr=False)
self.linear_1 = nn.Linear(IMAGE_SIZE, CLASS_NUM, bias_attr=False)
self.relu_0 = nn.ReLU()
self.relu_1 = nn.ReLU()
self.relu_2 = nn.ReLU()
# shard the weights of this layer
self.linear_0.weight = dist.shard_tensor(
self.linear_0.weight,
self._mesh1,
[dist.Replicate()],
stop_gradient=False,
)
self.linear_1.weight = dist.shard_tensor(
self.linear_1.weight,
self._mesh2,
[dist.Replicate()],
stop_gradient=False,
)
def forward(self, x):
x.stop_gradient = False
out = self.relu_0(x) # trigger backward partial allreduce
out = self.linear_0(out)
out = self.relu_1(out)
out = dist.reshard(out, self._mesh2, [dist.Replicate()])
out = self.linear_1(out)
out = self.relu_2(out) # trigger forward partial allreduce
out = paddle.cast(out, 'float32')
return out
class DPDemoNet(nn.Layer):
def __init__(
self,
mesh,
):
super().__init__()
self._mesh = mesh
self.linear_0 = nn.Linear(IMAGE_SIZE, IMAGE_SIZE, bias_attr=False)
self.linear_1 = nn.Linear(IMAGE_SIZE, CLASS_NUM, bias_attr=False)
self.linear_0.weight = dist.shard_tensor(
self.linear_0.weight,
self._mesh,
[dist.Replicate()],
stop_gradient=False,
)
self.linear_1.weight = dist.shard_tensor(
self.linear_1.weight,
self._mesh,
[dist.Replicate()],
stop_gradient=False,
)
self.relu_0 = nn.ReLU()
self.relu_1 = nn.ReLU()
self.relu_2 = nn.ReLU()
def forward(self, x):
out = self.relu_0(x)
out = self.linear_0(out)
out = self.relu_1(out)
out = self.linear_1(out)
out = self.relu_2(out)
out = paddle.cast(out, 'float32')
return out
class TestMLPTensorParallel(unittest.TestCase):
def test_to_static_program(self):
paddle.base.set_flags({'FLAGS_enable_pir_api': 1})
mesh = dist.ProcessMesh([0, 1], dim_names=["x"])
mp_layer = DemoNet(mesh, True)
opt = paddle.optimizer.SGD(
learning_rate=0.1, parameters=mp_layer.parameters()
)
loss_fn = nn.MSELoss()
loader = create_data_loader()
dist_loader = dist.shard_dataloader(loader, meshes=[mesh])
dist_model = dist.to_static(mp_layer, dist_loader, loss_fn, opt)
dist_model.train()
for batch_id, (image, label) in enumerate(dist_loader()):
loss = dist_model(image, label)
class TestMLPReplicated(unittest.TestCase):
def test_to_static_program(self):
paddle.base.set_flags({'FLAGS_enable_pir_api': 1})
mesh = dist.ProcessMesh([0, 1], dim_names=["x"])
replicated_layer = DemoNet(mesh, False)
opt = paddle.optimizer.SGD(
learning_rate=0.1, parameters=replicated_layer.parameters()
)
loss_fn = nn.MSELoss()
loader = create_data_loader()
dist_loader = dist.shard_dataloader(loader, meshes=[mesh])
dist_model = dist.to_static(replicated_layer, dist_loader, loss_fn, opt)
dist_model.train()
for batch_id, (image, label) in enumerate(dist_loader()):
loss = dist_model(image, label)
class TestMLPPipelineParallel(unittest.TestCase):
def init_env(self):
paddle.seed(1024)
np.random.seed(1024)
random.seed(1024)
def test_to_static_program(self):
paddle.base.set_flags({'FLAGS_enable_pir_api': 1})
mesh1 = dist.ProcessMesh([0], dim_names=["x"])
mesh2 = dist.ProcessMesh([1], dim_names=["y"])
pp_layer = PPDemoNet(mesh1, mesh2)
opt = paddle.optimizer.SGD(
learning_rate=0.1, parameters=pp_layer.parameters()
)
loss_fn = nn.MSELoss()
loader = create_data_loader()
dist_loader = dist.shard_dataloader(loader, meshes=[mesh1, mesh2])
dist_model = dist.to_static(pp_layer, dist_loader, loss_fn, opt)
dist_model.train()
mode = "train"
for batch_id, (image, label) in enumerate(dist_loader()):
loss = dist_model(image, label)
def _pipeline_schedule(
self,
enable_schedule=False,
schedule_mode="FThenB",
accumulate_steps=1,
grad_merge=False,
enable_amp=True,
):
self.init_env()
paddle.set_flags({'FLAGS_enable_pir_api': 1})
mesh1 = dist.ProcessMesh([0], dim_names=["x"])
mesh2 = dist.ProcessMesh([1], dim_names=["x"])
pp_layer = PPDemoNet(mesh1, mesh2)
opt = paddle.optimizer.SGD(
learning_rate=0.1, parameters=pp_layer.parameters()
)
loss_fn = nn.MSELoss()
loader = create_data_loader(
BATCH_SIZE, BATCH_NUM, IMAGE_SIZE, CLASS_NUM
)
strategy = dist.Strategy()
strategy.pipeline.enable = enable_schedule
strategy.pipeline.schedule_mode = schedule_mode
strategy.pipeline.accumulate_steps = accumulate_steps
if enable_amp:
amp = strategy.amp
amp.enable = True
amp.dtype = 'float16'
amp.level = 'O2'
amp.use_master_weight = True
amp.use_master_grad = True
amp.use_promote = True
amp.init_loss_scaling = 1024.0
if grad_merge:
gradient_merge = strategy.gradient_merge
gradient_merge.enable = True
gradient_merge.k_steps = accumulate_steps
gradient_merge.avg = True
dist_loader = dist.shard_dataloader(loader, meshes=[mesh1, mesh2])
dist_model = dist.to_static(
pp_layer, dist_loader, loss_fn, opt, strategy
)
dist_model.train()
loss = None
for batch_id, (image, label) in enumerate(dist_loader()):
loss = dist_model(image, label)
if accumulate_steps > 1 and loss is not None:
loss = np.mean(loss)
return loss
def test_pp_pass(self):
ref_loss = self._pipeline_schedule()
# only split_program
loss_split_prog_acc1 = self._pipeline_schedule(
enable_schedule=False, schedule_mode="FThenB", accumulate_steps=1
)
self.assertEqual(ref_loss, loss_split_prog_acc1)
loss_split_prog_acc4 = self._pipeline_schedule(
enable_schedule=True,
schedule_mode="FThenB",
accumulate_steps=4,
grad_merge=True,
)
if ref_loss is None:
self.assertEqual(ref_loss, loss_split_prog_acc4)
else:
ret_1 = np.allclose(
loss_split_prog_acc4,
ref_loss,
rtol=1e-3,
atol=1e-2,
equal_nan=True,
)
self.assertEqual(ret_1, True)
def test_pp_pass_amp(self):
loss_split_prog_acc1 = self._pipeline_schedule(
enable_schedule=False,
schedule_mode="FThenB",
accumulate_steps=1,
enable_amp=True,
)
loss_split_prog_acc4 = self._pipeline_schedule(
enable_schedule=True,
schedule_mode="FThenB",
accumulate_steps=4,
grad_merge=True,
enable_amp=True,
)
cur_rank = paddle.distributed.get_rank()
if cur_rank == 1:
ret_1 = np.allclose(
loss_split_prog_acc4,
loss_split_prog_acc1,
rtol=1e-3,
atol=1e-2,
equal_nan=True,
)
self.assertEqual(ret_1, True)
if __name__ == "__main__":
unittest.main()