mirror of
https://github.com/wassname/pytorch-lightning.git
synced 2026-09-12 12:40:20 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
babaa088d7 | ||
|
|
8217ebe029 | ||
|
|
9311812829 | ||
|
|
2357815640 | ||
|
|
ab87244884 | ||
|
|
2aa0b3be5c | ||
|
|
0fdf290201 | ||
|
|
1a39f703ad | ||
|
|
955e9ea6d5 | ||
|
|
10e031a843 | ||
|
|
229d168c20 | ||
|
|
468bd141f4 | ||
|
|
00678c6053 | ||
|
|
bbb5001aac | ||
|
|
a514674358 | ||
|
|
9757841e67 | ||
|
|
0ac7a8590b | ||
|
|
6e12431e6b |
@@ -40,13 +40,32 @@ In this setting, the model will run on all 8 GPUs at once using DataParallel und
|
|||||||
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
||||||
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
|
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
|
||||||
|
|
||||||
# DEFAULT
|
|
||||||
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7])
|
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7])
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
#### Multi-node
|
#### Multi-node
|
||||||
COMING SOON.
|
Multi-node training is easily done by specifying these flags.
|
||||||
|
```python
|
||||||
|
# train on 12*8 GPUs
|
||||||
|
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7], nb_gpu_nodes=12)
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, make sure to set up your SLURM job correctly via the [SlurmClusterObject](https://williamfalcon.github.io/test-tube/hpc/SlurmCluster/). In particular, specify the number of tasks per node correctly.
|
||||||
|
|
||||||
|
```python
|
||||||
|
cluster = SlurmCluster(
|
||||||
|
hyperparam_optimizer=test_tube.HyperOptArgumentParser(),
|
||||||
|
log_path='/some/path/to/save',
|
||||||
|
)
|
||||||
|
|
||||||
|
# configure cluster
|
||||||
|
cluster.per_experiment_nb_nodes = 12
|
||||||
|
cluster.per_experiment_nb_gpus = 8
|
||||||
|
|
||||||
|
cluster.add_slurm_cmd(cmd='ntasks-per-node', value=8, comment='1 task per gpu')
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
#### Self-balancing architecture
|
#### Self-balancing architecture
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
The trainer handles all the logic for running a val loop, training loop, distributing, etc...
|
The trainer handles all the logic for running a val loop, training loop, distributing, etc...
|
||||||
"""
|
"""
|
||||||
from time import sleep
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
import os
|
import os
|
||||||
import pdb
|
import pdb
|
||||||
|
import re
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from torch.utils.data.distributed import DistributedSampler
|
from torch.utils.data.distributed import DistributedSampler
|
||||||
@@ -146,17 +146,24 @@ class Trainer(TrainerIO):
|
|||||||
self.print_nan_grads = print_nan_grads
|
self.print_nan_grads = print_nan_grads
|
||||||
self.data_parallel_device_ids = None
|
self.data_parallel_device_ids = None
|
||||||
self.world_size = 1
|
self.world_size = 1
|
||||||
|
self.node_rank = 0
|
||||||
self.use_ddp = False
|
self.use_ddp = False
|
||||||
self.use_dp = False
|
self.use_dp = False
|
||||||
|
|
||||||
|
|
||||||
# gpus come in as a string.
|
# gpus come in as a string.
|
||||||
# if gpus = -1 then use all available devices
|
# if gpus = -1 then use all available devices
|
||||||
# otherwise, split the string using commas
|
# otherwise, split the string using commas
|
||||||
if gpus is not None:
|
if gpus is not None:
|
||||||
if gpus == '-1':
|
if type(gpus) is list:
|
||||||
self.data_parallel_device_ids = list(range(0, torch.cuda.device_count()))
|
self.data_parallel_device_ids = gpus
|
||||||
|
elif type(gpus) is str:
|
||||||
|
if gpus == '-1':
|
||||||
|
self.data_parallel_device_ids = list(range(0, torch.cuda.device_count()))
|
||||||
|
else:
|
||||||
|
self.data_parallel_device_ids = [int(x.strip()) for x in gpus.split(',')]
|
||||||
else:
|
else:
|
||||||
self.data_parallel_device_ids = [int(x.strip()) for x in gpus.split(',')]
|
raise Exception('gpus has to be a string or list of ids')
|
||||||
|
|
||||||
# set the correct cuda visible devices (using pci order)
|
# set the correct cuda visible devices (using pci order)
|
||||||
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
||||||
@@ -170,6 +177,15 @@ class Trainer(TrainerIO):
|
|||||||
self.use_dp = distributed_backend == 'dp'
|
self.use_dp = distributed_backend == 'dp'
|
||||||
self.use_ddp = distributed_backend == 'ddp'
|
self.use_ddp = distributed_backend == 'ddp'
|
||||||
|
|
||||||
|
# use ddp automatically if nb_gpu_nodes > 1
|
||||||
|
if nb_gpu_nodes > 1:
|
||||||
|
self.use_ddp = True
|
||||||
|
self.use_ddp = False
|
||||||
|
w = 'DataParallel does not support nb_gpu_nodes > 1. ' \
|
||||||
|
'Switching to DistributedDataParallel for you. ' \
|
||||||
|
'To silence this warning set distributed_backend=ddp'
|
||||||
|
warnings.warn(w)
|
||||||
|
|
||||||
# process info
|
# process info
|
||||||
self.proc_rank = 0
|
self.proc_rank = 0
|
||||||
|
|
||||||
@@ -377,9 +393,14 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# whenever we have the correct number of tasks, we let slurm manage processes
|
# whenever we have the correct number of tasks, we let slurm manage processes
|
||||||
# otherwise we launch the required number of processes
|
# otherwise we launch the required number of processes
|
||||||
nb_slurm_tasks = int(os.environ['SLURM_NTASKS'])
|
try:
|
||||||
nb_requested_gpus = len(self.data_parallel_device_ids)
|
nb_slurm_tasks = int(os.environ['SLURM_NTASKS'])
|
||||||
is_slurm_managing_tasks = nb_slurm_tasks == nb_requested_gpus
|
nb_requested_gpus = len(self.data_parallel_device_ids) * self.nb_gpu_nodes
|
||||||
|
is_slurm_managing_tasks = nb_slurm_tasks == nb_requested_gpus
|
||||||
|
except Exception as e:
|
||||||
|
# likely not on slurm, so set the slurm managed flag to false
|
||||||
|
is_slurm_managing_tasks = False
|
||||||
|
|
||||||
if is_slurm_managing_tasks:
|
if is_slurm_managing_tasks:
|
||||||
task = int(os.environ['SLURM_LOCALID'])
|
task = int(os.environ['SLURM_LOCALID'])
|
||||||
self.ddp_train(task, model)
|
self.ddp_train(task, model)
|
||||||
@@ -388,6 +409,7 @@ class Trainer(TrainerIO):
|
|||||||
You requested {nb_requested_gpus} GPUs but launched {nb_slurm_tasks} slurm tasks.
|
You requested {nb_requested_gpus} GPUs but launched {nb_slurm_tasks} slurm tasks.
|
||||||
We will launch {nb_requested_gpus} processes for you.
|
We will launch {nb_requested_gpus} processes for you.
|
||||||
We recommend you let slurm manage the processes by setting: --ntasks-per-node={nb_requested_gpus}
|
We recommend you let slurm manage the processes by setting: --ntasks-per-node={nb_requested_gpus}
|
||||||
|
If you're not using SLURM, ignore this message!
|
||||||
"""
|
"""
|
||||||
warnings.warn(msg)
|
warnings.warn(msg)
|
||||||
mp.spawn(self.ddp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
|
mp.spawn(self.ddp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
|
||||||
@@ -443,9 +465,10 @@ class Trainer(TrainerIO):
|
|||||||
# node rank using relative slurm id
|
# node rank using relative slurm id
|
||||||
# otherwise default to node rank 0
|
# otherwise default to node rank 0
|
||||||
try:
|
try:
|
||||||
node_rank = int(os.environ['SLURM_NODEID'])
|
node_id = os.environ['SLURM_NODEID']
|
||||||
except KeyError as e:
|
self.node_rank = int(node_id)
|
||||||
node_rank = 0
|
except Exception as e:
|
||||||
|
self.node_rank = 0
|
||||||
|
|
||||||
# recover original exp before went into process
|
# recover original exp before went into process
|
||||||
# init in write mode only on proc 0
|
# init in write mode only on proc 0
|
||||||
@@ -453,10 +476,10 @@ class Trainer(TrainerIO):
|
|||||||
self.experiment = self.experiment.get_non_ddp_exp()
|
self.experiment = self.experiment.get_non_ddp_exp()
|
||||||
|
|
||||||
# show progbar only on prog_rank 0
|
# show progbar only on prog_rank 0
|
||||||
self.prog_bar = self.prog_bar and node_rank == 0 and gpu_nb == 0
|
self.prog_bar = self.prog_bar and self.node_rank == 0 and gpu_nb == 0
|
||||||
|
|
||||||
# determine which process we are and world size
|
# determine which process we are and world size
|
||||||
self.proc_rank = node_rank * len(self.data_parallel_device_ids) + gpu_nb
|
self.proc_rank = self.node_rank * len(self.data_parallel_device_ids) + gpu_nb
|
||||||
self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids)
|
self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids)
|
||||||
|
|
||||||
# set up server using proc 0's ip address
|
# set up server using proc 0's ip address
|
||||||
@@ -501,15 +524,29 @@ class Trainer(TrainerIO):
|
|||||||
port = 12910
|
port = 12910
|
||||||
os.environ['MASTER_PORT'] = f'{port}'
|
os.environ['MASTER_PORT'] = f'{port}'
|
||||||
|
|
||||||
|
root_node = self.__resolve_root_node_address()
|
||||||
|
os.environ['MASTER_ADDR'] = root_node
|
||||||
|
|
||||||
|
dist.init_process_group("nccl", rank=self.proc_rank, world_size=self.world_size)
|
||||||
|
|
||||||
|
|
||||||
|
def __resolve_root_node_address(self):
|
||||||
try:
|
try:
|
||||||
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
|
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
|
||||||
|
|
||||||
|
if '[' in root_node:
|
||||||
|
name = root_node.split('[')[0]
|
||||||
|
number = root_node.split(',')[0]
|
||||||
|
if '-' in number:
|
||||||
|
number = number.split('-')[0]
|
||||||
|
|
||||||
|
number = re.sub('[^0-9]', '', number)
|
||||||
|
root_node = name + number
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
root_node = '127.0.0.2'
|
root_node = '127.0.0.2'
|
||||||
|
|
||||||
os.environ['MASTER_ADDR'] = root_node
|
return root_node
|
||||||
|
|
||||||
sleep(self.proc_rank*0.5)
|
|
||||||
dist.init_process_group("nccl", rank=self.proc_rank, world_size=self.world_size)
|
|
||||||
|
|
||||||
def __run_pretrain_routine(self, model):
|
def __run_pretrain_routine(self, model):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from setuptools import setup, find_packages
|
|||||||
# http://blog.ionelmc.ro/2014/05/25/python-packaging/
|
# http://blog.ionelmc.ro/2014/05/25/python-packaging/
|
||||||
setup(
|
setup(
|
||||||
name="pytorch-lightning",
|
name="pytorch-lightning",
|
||||||
version='0.2.5.1',
|
version='0.3.1',
|
||||||
description="The Keras for ML researchers using PyTorch",
|
description="The Keras for ML researchers using PyTorch",
|
||||||
author="William Falcon",
|
author="William Falcon",
|
||||||
author_email="waf2107@columbia.edu",
|
author_email="waf2107@columbia.edu",
|
||||||
|
|||||||
Reference in New Issue
Block a user