acoustic-van-30942
05/20/2023, 1:54 AM@pytorch_parallel decorator. I'm still rather new to distributed training, so learning the ropes. I've tried fsdp to do sharded training, but it was having some trouble with the model parameters. I was getting this error - valueerror: optimizer got an empty parameter list. When I printed out the params though, they're definitely there. I also tried ddp as the strategy, which didn't give any explicit error, but it just stalled and didn't have any progress output in the stdout logs...
I have a reproducible example here - https://github.com/rileyhun/llm_finetuning_metaflow/blob/main/gpt-j-8bit-flow.py. Any pointers or guidance would be greatly appreciated.hallowed-glass-14538
05/20/2023, 6:28 AM@pytorch_parallel so you have multiple Jobs spawned with gang scheduling to run the distributed training (over multiple nodes (with multiple GPUS per node?).
1. Did other tasks start in the image you shared. AWS batch can take up some time to start all the nodes you need and then place the containers on the nodes. Can you verify if other tasks started coz it seems the "control task" is waiting on the child tasks to start and stuck in the barrier. "control task" is the main that that will get the MASTER_IP and to which other tasks will communicate with.
2. I think the DDP support for PT Lightning has changed since we built the @pytorch_parallel. This short version is that now it calls the parent script under the hood on its own and it also has introduced abstractions to handle how a ClusterEnviornment performs DDP or SFDP. you can try using LightningEnvironment if that helps? `ClusterEnvironment`s can be passed to PT lightning Trainer as a plugins.acoustic-van-30942
05/20/2023, 6:52 AMg5.4xlarge ), and they all started up and were running.
I can look into ClusterEnvironmentacoustic-van-30942
05/20/2023, 9:02 AMenv = LightningEnvironment()
env.world_size = lambda: int(current.parallel.node_index)
env.global_rank = lambda: int(current.parallel.num_nodes)
ddp = DDPStrategy(
find_unused_parameters=True,
cluster_environment=env,
process_group_backend="gloo",
accelerator="gpu"
)
trainer = pl.Trainer(
log_every_n_steps=1,
devices=self.num_gpus,
num_nodes=self.num_parallel,
max_epochs=config.num_epochs,
deterministic=True,
enable_checkpointing=True,
enable_model_summary=True,
profiler="simple",
precision=16,
callbacks=[TQDMProgressBar(refresh_rate=0)],
strategy=ddp
)
trainer.fit(finetuner)
But looks like it is still stalling without any logs in stdoutcrooked-jordan-29960
05/20/2023, 3:05 PMvalueerror: optimizer got an empty parameter list and DDP issue is the Adam8bit parts. I wonder if setting this arg when HuggingFace loads model will help:
self.model = GPTJForCausalLM.from_pretrained(..., load_in_8bit=True)
I see in the DDP version of the flow output it is using 16bit AMP, so maybe the optimizer is getting confused and not reading the optimizer state correctly since the instantiated Adam is 8bit.
FYI I haven't had a chance to reproduce yet, so this is just a guess.acoustic-van-30942
05/20/2023, 8:43 PMacoustic-van-30942
05/22/2023, 5:38 AMTimeoutError: The client socket has timed out after 1800s while trying to connect to (10.14.52.26, 51371).hallowed-glass-14538
05/22/2023, 4:13 PMacoustic-van-30942
05/22/2023, 8:43 PMhallowed-glass-14538
05/22/2023, 9:54 PMgloo and try it out ? I noticed a comment in our code that says that nccl didn't play nice with AWS batch.acoustic-van-30942
05/22/2023, 9:56 PMos.environ["MASTER_PORT"] = "12345"
os.environ["MASTER_ADDR"] = "localhost"
os.environ["WORLD_SIZE"] = str(current.parallel.num_nodes)
os.environ["NODE_RANK"] = str(current.parallel.node_index)
I also removed the cluster environment/lightning environment.hallowed-glass-14538
05/22/2023, 10:03 PMhallowed-glass-14538
05/22/2023, 10:03 PMcurrent.parallel.main_ip to set that IPacoustic-van-30942
05/22/2023, 10:03 PMhallowed-glass-14538
05/22/2023, 10:04 PMmaster_port can be set in @pytorch_parallel. So something like : @pytorch_parallel(master_port=9001)acoustic-van-30942
05/22/2023, 10:05 PMacoustic-van-30942
05/22/2023, 11:22 PMgloo backend as you suggested.acoustic-van-30942
05/23/2023, 12:06 AMRuntimeError: [enforce fail at /opt/conda/conda-bld/pytorch_1656352645774/work/third_party/gloo/gloo/context.cc:27] rank < size. 1 vs 1
RuntimeError: [enforce fail at /opt/conda/conda-bld/pytorch_1656352645774/work/third_party/gloo/gloo/context.cc:27] rank < size. 2 vs 1
RuntimeError: [enforce fail at /opt/conda/conda-bld/pytorch_1656352645774/work/third_party/gloo/gloo/context.cc:27] rank < size. 3 vs 1hallowed-glass-14538
05/23/2023, 12:18 AMdevices and num_nodes in your Trainer ?acoustic-van-30942
05/23/2023, 12:19 AMdevices is 1 and num_nodes is 4hallowed-glass-14538
05/23/2023, 12:20 AMLOCAL_RANK=0 onceacoustic-van-30942
05/23/2023, 12:22 AMos.environ["MASTER_ADDR"] = str(current.parallel.main_ip)
os.environ["WORLD_SIZE"] = str(current.parallel.num_nodes)
os.environ["NODE_RANK"] = str(current.parallel.node_index)
os.environ["LOCAL_RANK"] = 0acoustic-van-30942
05/23/2023, 12:24 AMGLOBAL_RANK as well?acoustic-van-30942
05/23/2023, 12:40 AMhallowed-glass-14538
05/23/2023, 12:49 AMos.environ in your task processes get get all the actual values of MASTER_ADDR , GLOBAL_RANK etc. I wanted to ensure that we are not modifying something from the MF side at runtime. can you also share your code by any chance ? Wanted to see all configurations once.acoustic-van-30942
05/23/2023, 12:50 AMhallowed-glass-14538
05/23/2023, 1:01 AMacoustic-van-30942
05/23/2023, 1:02 AMstr though otherwise it errors out.hallowed-glass-14538
05/23/2023, 1:02 AMstr.hallowed-glass-14538
05/23/2023, 1:03 AMacoustic-van-30942
05/23/2023, 1:03 AMacoustic-van-30942
05/23/2023, 1:58 AMRuntimeError: [/opt/conda/conda-bld/pytorch_1656352645774/work/third_party/gloo/gloo/transport/tcp/pair.cc:598] Connection closed by peer [10.14.52.10]:5558
Also got this error -
ValueError: Invalid rank 1, rank should be in the interval [0, 0]hallowed-glass-14538
05/23/2023, 1:59 AMhallowed-glass-14538
05/23/2023, 2:01 AMmaster_port=9001 when you called this ?acoustic-van-30942
05/23/2023, 2:01 AMos.environ["MASTER_ADDR"] = str(current.parallel.main_ip)
env = LightningEnvironment()
env.world_size = lambda: int(current.parallel.num_nodes)
env.global_rank = lambda: int(current.parallel.num_nodes)
env.node_rank = lambda: int(current.parallel.node_index)
env.local_rank = lambda: int(os.environ.get("LOCAL_RANK", 0))
print(os.environ)
print(env)acoustic-van-30942
05/23/2023, 2:01 AM@pytorch_parallel(master_port=9001)hallowed-glass-14538
05/23/2023, 2:02 AM[10.14.52.10]:5558 so may even have to pluck and replace the main_port propertyacoustic-van-30942
05/23/2023, 2:02 AMhallowed-glass-14538
05/23/2023, 2:03 AMacoustic-van-30942
05/23/2023, 2:15 AM'MF_PARALLEL_MAIN_IP': '10.14.51.206', 'MF_PARALLEL_NUM_NODES': '4', 'MF_PARALLEL_NODE_INDEX': '0', 'MASTER_PORT': '9001', 'MASTER_ADDR': '10.14.51.206', 'NODE_RANK': '0', 'WORLD_SIZE': '4', 'NUM_NODES': '4', 'PL_TORCH_DISTRIBUTED_BACKEND': 'gloo', 'PYTORCH_NVML_BASED_CUDA_CHECK': '1', 'CRC32C_SW_MODE': 'auto'acoustic-van-30942
05/23/2023, 2:16 AMValueError: Invalid rank 2, rank should be in the interval [0, 0]crooked-jordan-29960
05/23/2023, 3:34 AMtorch.distributed sees worldsize as 1. Does this specific error go away if you uncomment the line:
os.environ["WORLD_SIZE"] = str(current.parallel.num_nodes)acoustic-van-30942
05/23/2023, 3:35 AMcrooked-jordan-29960
05/23/2023, 3:36 AMacoustic-van-30942
05/23/2023, 3:38 AMLightningEnvironment to set up the cluster config:
commenting out world_size
os.environ["MASTER_ADDR"] = str(current.parallel.main_ip)
os.environ["MASTER_PORT"] = "9001"
env = LightningEnvironment()
# env.world_size = lambda: int(current.parallel.num_nodes)
env.global_rank = lambda: int(current.parallel.node_index)
env.node_rank = lambda: int(current.parallel.node_index)
env.local_rank = lambda: int(os.environ.get("LOCAL_RANK", 0))
fsdp_native = DDPFullyShardedNativeStrategy(
cpu_offload=CPUOffload(offload_params=True),
cluster_environment=env,
process_group_backend="gloo"
)crooked-jordan-29960
05/23/2023, 3:39 AMacoustic-van-30942
05/23/2023, 3:47 AMRuntimeError: [enforce fail at /opt/conda/conda-bld/pytorch_1656352645774/work/third_party/gloo/gloo/context.cc:27] rank < size. 8 vs 1hallowed-glass-14538
05/23/2023, 3:57 AMClusterEnvironment :
import logging
import os
from metaflow import current
from lightning.fabric.plugins.environments.cluster_environment import ClusterEnvironment
log = logging.getLogger(__name__)
class MetaflowEnvironment(ClusterEnvironment):
"""
Quick Dirty MF environment in PTL for Single GPU Multi-node training.
"""
@property
def creates_processes_externally(self) -> bool:
return True
@property
def main_address(self) -> str:
return current.parallel.main_ip
@property
def main_port(self) -> int:
return 9001 # Fix me
@staticmethod
def detect() -> bool:
return True
def world_size(self) -> int:
return int(current.parallel.num_nodes)
def set_world_size(self, size: int) -> None:
log.debug("MetaflowEnvironment.set_world_size was called, but setting world size is not allowed. Ignored.")
def global_rank(self) -> int:
return int(current.parallel.node_index)
def set_global_rank(self, rank: int) -> None:
log.debug("MetaflowEnvironment.set_global_rank was called, but setting global rank is not allowed. Ignored.")
def local_rank(self) -> int:
return 0
def node_rank(self) -> int:
return self.global_rank()hallowed-glass-14538
05/23/2023, 3:57 AMacoustic-van-30942
05/23/2023, 3:58 AMacoustic-van-30942
05/23/2023, 4:24 AMValueError: Invalid rank 10, rank should be in the interval [0, 0]hallowed-glass-14538
05/23/2023, 4:25 AMacoustic-van-30942
05/23/2023, 4:26 AMhallowed-glass-14538
05/23/2023, 4:27 AMhallowed-glass-14538
05/23/2023, 4:32 AMacoustic-van-30942
05/23/2023, 4:34 AMacoustic-van-30942
05/23/2023, 4:35 AMacoustic-van-30942
05/23/2023, 4:59 AMddp instead, and it worked!acoustic-van-30942
05/23/2023, 4:59 AMfsdp integration, perhaps?hallowed-glass-14538
05/23/2023, 5:02 AMhallowed-glass-14538
05/23/2023, 5:03 AMDataLoader ; I think if we customize the dataloader a little to use distributed sampling from the top-level then we should be even able to support FSDPhallowed-glass-14538
05/23/2023, 5:03 AMacoustic-van-30942
05/24/2023, 5:03 PMDataLoader in a distributed sampler already?hallowed-glass-14538
05/24/2023, 6:41 PMacoustic-van-30942
05/24/2023, 6:46 PMnccl as the process group backend? I don't think gloo is recommended for communication between GPUs, correct me if I'm wrong?hallowed-glass-14538
05/24/2023, 6:49 PMacoustic-van-30942
05/31/2023, 4:50 AMfsdp wasn't working unless process group is using nccl backend. But the DistributedSampler worked I believe because it got me out of that rank issue I was experiencing.
This is the new error I was getting:
RuntimeError: no support for _allgather_base in Gloo process group
I did some research and currently looking into whether disabling IOMMU will help get NCCL working with AWS Batch.acoustic-van-30942
05/31/2023, 11:04 PM@parallel decorator works nicely with NCCL now! I tried this w/ DDP and worked like a charm.
I basically added this env variable:
"NCCL_SOCKET_IFNAME": "eth0"
The bad news is that I don't think FSDP is working as it's supposed to.
Using DDP with NCCL process group, it only took 3 minutes to train. Super fast!
But FSDP just hangs. No networking error, no rank error, or any error for that matter. Just hanging for about 1.5hrs...
My DistributedSampler looks like this -
train_sampler = DistributedSampler(
train_dataset,
rank=current.parallel.node_index,
num_replicas=current.parallel.num_nodes,
shuffle=True
)
train_kwargs = {
"batch_size": self.batch_size,
"sampler": train_sampler,
"num_workers": 1,
"shuffle": False,
"drop_last": True,
"pin_memory": True
}
train_loader = DataLoader(
train_dataset, **train_kwargs
)
val_sampler = DistributedSampler(
val_dataset,
rank=current.parallel.node_index,
num_replicas=current.parallel.num_nodes,
shuffle=True
)
val_kwargs = {
"batch_size": self.batch_size,
"sampler": val_sampler,
"num_workers": 1,
"shuffle": False,
"drop_last": True,
"pin_memory": True
}
val_loader = DataLoader(
val_dataset, **val_kwargs
)
test_sampler = DistributedSampler(
test_dataset,
rank=current.parallel.node_index,
num_replicas=current.parallel.num_nodes,
shuffle=True
)
test_kwargs = {
"batch_size": self.batch_size,
"sampler": test_sampler,
"num_workers": 1,
"shuffle": False,
"drop_last": True,
"pin_memory": True
}
test_loader = DataLoader(
test_dataset, **test_kwargs
)
Any guidance or advice?hallowed-glass-14538
05/31/2023, 11:57 PMhallowed-glass-14538
05/31/2023, 11:58 PMhallowed-glass-14538
06/01/2023, 12:08 AMacoustic-van-30942
06/01/2023, 12:12 AM1.12 in my @conda_base seems to result in the training session not being able to find cuda installed. So I just kept it at 1.12.acoustic-van-30942
06/01/2023, 3:30 AMCPUOffload for the params. Although, I'm not sure why the model summary looks like this. Seems like it can't detect the params?hallowed-glass-14538
06/01/2023, 4:02 AMhallowed-glass-14538
06/01/2023, 4:04 AMhallowed-glass-14538
06/01/2023, 4:04 AMhallowed-glass-14538
06/01/2023, 4:04 AMacoustic-van-30942
06/01/2023, 4:06 AMhallowed-glass-14538
06/01/2023, 4:06 AMacoustic-van-30942
06/01/2023, 4:06 AMacoustic-van-30942
06/01/2023, 4:38 AMRuntimeError: Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument index in method wrapper__index_select)
lol. This is never-ending.acoustic-van-30942
06/01/2023, 4:43 AM@pytorch_parallel decorator is working really well and doing what it needs to be doing! This is great! Super excited!