Compare commits

...
99 Commits
Author SHA1 Message Date
William Falcon 2c4052edb6 release v0.11 2019-06-26 18:44:59 -04:00
William Falcon a2f0f20674 finished data parallel 2019-06-26 18:29:38 -04:00
William Falcon a40b21bce0 removed self.model refs 2019-06-26 18:27:25 -04:00
William Falcon b58ec7ad5a removed self.model refs 2019-06-26 18:26:08 -04:00
William Falcon 301a4992f4 removed self.model refs 2019-06-26 18:24:47 -04:00
William Falcon 42fe76f794 removed self.model refs 2019-06-26 18:23:50 -04:00
William Falcon 8f9672603b removed self.model refs 2019-06-26 18:23:02 -04:00
William Falcon 11b4bc3fbc removed self.model refs 2019-06-26 18:21:17 -04:00
William Falcon 787f523a71 removed self.model refs 2019-06-26 18:19:11 -04:00
William Falcon 5c8875130b removed self.model refs 2019-06-26 18:17:40 -04:00
William Falcon bf0f5a5cbb removed self.model refs 2019-06-26 18:12:33 -04:00
William Falcon df4ac681ed removed self.model refs 2019-06-26 18:08:46 -04:00
William Falcon c1cbb1039a removed self.model refs 2019-06-26 18:05:48 -04:00
William Falcon bc0278252e removed self.model refs 2019-06-26 18:04:29 -04:00
William Falcon 12a0e98920 updated args 2019-06-26 17:54:59 -04:00
William Falcon 4a3c9de857 updated args 2019-06-26 17:53:05 -04:00
William Falcon 0b1e22ac51 updated args 2019-06-26 17:52:14 -04:00
William Falcon 808e86b17c updated args 2019-06-26 17:50:09 -04:00
William Falcon 71cd8f549d updated args 2019-06-26 17:49:58 -04:00
William Falcon 1ee6d21db2 updated args 2019-06-26 17:46:55 -04:00
William Falcon f8be24b09c updated args 2019-06-26 17:44:34 -04:00
William Falcon 1b497ac69a updated args 2019-06-25 20:32:20 -04:00
William Falcon d016431a3f updated args 2019-06-25 20:31:29 -04:00
William Falcon a2e4944f60 updated args 2019-06-25 20:31:10 -04:00
William Falcon 4d5123e379 updated args 2019-06-25 20:29:26 -04:00
William Falcon 5ce4e872de updated args 2019-06-25 20:28:33 -04:00
William Falcon 5eaaf82837 updated args 2019-06-25 20:27:17 -04:00
William Falcon 7527167f69 updated args 2019-06-25 20:25:34 -04:00
William Falcon 45331b396f updated args 2019-06-25 20:24:43 -04:00
William Falcon 440f47b864 updated args 2019-06-25 20:24:03 -04:00
William Falcon 88606c581f updated args 2019-06-25 20:22:59 -04:00
William Falcon f49c2f4c25 updated args 2019-06-25 20:22:21 -04:00
William Falcon 51305697c1 updated args 2019-06-25 20:21:11 -04:00
William Falcon 9b46f13230 updated args 2019-06-25 20:20:12 -04:00
William Falcon 078bbc5df5 updated args 2019-06-25 20:19:11 -04:00
William Falcon 4c556e9880 updated args 2019-06-25 20:19:02 -04:00
William Falcon 89a79a5d3c updated args 2019-06-25 20:18:19 -04:00
William Falcon e3f96d6f3a updated args 2019-06-25 20:17:50 -04:00
William Falcon d33048c67b updated args 2019-06-25 20:16:59 -04:00
William Falcon fea10fc792 updated args 2019-06-25 20:15:10 -04:00
William Falcon 7a7a9a9da0 updated args 2019-06-25 20:14:29 -04:00
William Falcon a76ae6bc48 updated args 2019-06-25 20:12:46 -04:00
William Falcon 0460821398 updated args 2019-06-25 20:12:41 -04:00
William Falcon 7cb6e34beb updated args 2019-06-25 20:10:23 -04:00
William Falcon 2ac5cce67a updated args 2019-06-25 20:09:40 -04:00
William Falcon bac0ef2d44 updated args 2019-06-25 20:08:32 -04:00
William Falcon d3b621dfd2 updated args 2019-06-25 20:04:27 -04:00
William Falcon ac88e3f832 updated args 2019-06-25 20:03:27 -04:00
William Falcon 117515db48 updated args 2019-06-25 20:00:43 -04:00
William Falcon 69be732b11 updated args 2019-06-25 19:56:47 -04:00
William Falcon b59af1813b updated args 2019-06-25 19:56:12 -04:00
William Falcon 7814b2d449 updated args 2019-06-25 19:54:28 -04:00
William Falcon c941649532 updated args 2019-06-25 19:52:26 -04:00
William Falcon 0795e4d51b updated args 2019-06-25 19:46:49 -04:00
William Falcon 158aca26e2 updated args 2019-06-25 19:45:31 -04:00
William Falcon cf57be9dca updated args 2019-06-25 19:43:25 -04:00
William Falcon 8df13035eb updated args 2019-06-25 19:42:15 -04:00
William Falcon c54dd94295 updated args 2019-06-25 19:35:11 -04:00
William Falcon e801914d1d updated args 2019-06-25 19:18:27 -04:00
William Falcon 89410e9090 updated args 2019-06-25 19:17:17 -04:00
William Falcon c4da914747 updated args 2019-06-25 19:06:39 -04:00
William Falcon 41a935185c updated args 2019-06-25 19:06:19 -04:00
William Falcon 73b4976500 updated args 2019-06-25 19:04:49 -04:00
William Falcon 4d42b1ed5f updated args 2019-06-25 19:00:38 -04:00
William Falcon 0fd4d5e7a1 updated args 2019-06-25 18:59:37 -04:00
William Falcon bf3b86ce4d updated args 2019-06-25 18:58:45 -04:00
William Falcon 684dfd0a38 updated args 2019-06-25 18:57:25 -04:00
William Falcon d4ca295762 updated args 2019-06-25 18:51:41 -04:00
William Falcon de0f7fc936 updated args 2019-06-25 18:47:11 -04:00
William Falcon 7b22de22a7 updated args 2019-06-25 18:45:19 -04:00
William Falcon d8cb739ab2 updated args 2019-06-25 18:44:50 -04:00
William Falcon c45a329df4 updated args 2019-06-25 18:44:11 -04:00
William Falcon 41f68861d5 updated args 2019-06-25 18:42:44 -04:00
William Falcon 156dc3e5ee updated args 2019-06-25 18:40:34 -04:00
William Falcon 8e10179214 updated args 2019-06-25 18:29:43 -04:00
William Falcon 775ca3736b updated args 2019-06-25 18:29:16 -04:00
William Falcon 242cccc234 updated args 2019-06-25 18:25:51 -04:00
William Falcon a00b8f7861 updated args 2019-06-25 18:25:19 -04:00
William Falcon 338f889e7c updated args 2019-06-25 18:23:29 -04:00
William Falcon e12c8ad21a updated args 2019-06-25 18:22:10 -04:00
William Falcon 35aa67df56 updated args 2019-06-25 18:20:24 -04:00
William Falcon e58cfafa74 updated args 2019-06-25 18:18:40 -04:00
William Falcon e58eee8d6a updated args 2019-06-25 18:18:20 -04:00
William Falcon b9d5397196 updated args 2019-06-25 18:14:48 -04:00
William Falcon 3f8e133303 updated args 2019-06-25 18:13:01 -04:00
William Falcon 983551653d fixed basic trainer 2019-06-25 18:11:13 -04:00
William Falcon 6c705a0525 adding framework level dp 2019-06-25 18:10:15 -04:00
William Falcon 516f441153 adding framework level dp 2019-06-25 18:09:29 -04:00
William Falcon cbc627459a adding framework level dp 2019-06-25 17:56:01 -04:00
William Falcon a519e0755b release v0.1.dev21 2019-06-14 10:05:03 -04:00
William Falcon 9bf3fcd45e adding support for interrupt signals 2019-06-14 09:59:28 -04:00
William Falcon 88ff860c90 adding support for interrupt signals 2019-06-14 09:46:41 -04:00
William Falcon edf03063a1 adding support for interrupt signals 2019-06-14 09:44:19 -04:00
William Falcon 32edc6d7b7 adding support for interrupt signals 2019-06-14 09:42:36 -04:00
William Falcon cd36b63167 adding support for interrupt signals 2019-06-14 09:39:52 -04:00
William Falcon 519d2e9321 adding support for interrupt signals 2019-06-14 09:28:23 -04:00
William Falcon 8cca02d652 adding support for interrupt signals 2019-06-14 09:25:46 -04:00
William Falcon 69274d304d adding support for interrupt signals 2019-06-14 09:24:51 -04:00
William Falcon d98e799404 adding dataparallel 2019-06-07 15:06:22 -04:00
16 changed files with 289 additions and 69 deletions
+3
View File
@@ -116,3 +116,6 @@ ENV/
# mypy
.mypy_cache/
# data
mnist/
+23
View File
@@ -55,6 +55,29 @@ To use lightning do 2 things:
1. [Define a trainer](https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/examples/basic_trainer.py) (which will run ALL your models).
2. [Define a model](https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/examples/example_model.py).
#### Quick demo
Run the following demo to see how it works:
```bash
# install lightning
pip install pytorch-lightning
# clone lightning for the demo
git clone https://github.com/williamFalcon/pytorch-lightning.git
cd pytorch-lightning/docs/source/examples
# run demo (on cpu)
python fully_featured_trainer.py
```
Without changing the model AT ALL, you can run the model on a single gpu, over multiple gpus, or over multiple nodes.
```bash
# run a grid search on two gpus
python fully_featured_trainer.py --gpus "0;1"
# run single model on multiple gpus
python fully_featured_trainer.py --gpus "0;1" --interactive
```
#### Basic trainer example
See [this demo](https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/examples/fully_featured_trainer.py) for a more robust trainer example.
View File
View File
+1
View File
@@ -0,0 +1 @@
from .example_model import ExampleModel
+4 -4
View File
@@ -2,10 +2,10 @@ import os
import sys
from test_tube import HyperOptArgumentParser, Experiment
from pytorch-lightning.models.trainer import Trainer
from pytorch-lightning.utils.arg_parse import add_default_args
from pytorch-lightning.utils.pt_callbacks import EarlyStopping, ModelCheckpoint
from demo.example_model import ExampleModel
from pytorch_lightning.models.trainer import Trainer
from pytorch_lightning.utils.arg_parse import add_default_args
from pytorch_lightning.utils.pt_callbacks import EarlyStopping, ModelCheckpoint
from docs.source.examples.example_model import ExampleModel
def main(hparams):
+28 -13
View File
@@ -1,11 +1,13 @@
import torch.nn as nn
import numpy as np
from pytorch-lightning.root_module.root_module import RootModule
from pytorch_lightning.root_module.root_module import RootModule
from test_tube import HyperOptArgumentParser
from torchvision.datasets import MNIST
import torchvision.transforms as transforms
import torch
import torch.nn.functional as F
import os, pdb
from collections import OrderedDict
class ExampleModel(RootModule):
@@ -40,8 +42,9 @@ class ExampleModel(RootModule):
# TRAINING
# ---------------------
def forward(self, x):
x = self.c_d1(x)
x = F.tanh(x)
x = torch.tanh(x)
x = self.c_d1_bn(x)
x = self.c_d1_drop(x)
@@ -54,7 +57,7 @@ class ExampleModel(RootModule):
nll = F.nll_loss(logits, labels)
return nll
def training_step(self, data_batch):
def training_step(self, data_batch, batch_i):
"""
Called inside the training loop
:param data_batch:
@@ -68,10 +71,16 @@ class ExampleModel(RootModule):
# calculate loss
loss_val = self.loss(y, y_hat)
tqdm_dic = {'tng_loss': loss_val.item()}
return loss_val, tqdm_dic
# tqdm_dic = {'tng_loss': loss_val.item()}
# return loss_val, tqdm_dic
def validation_step(self, data_batch):
output = OrderedDict({
'loss': loss_val,
'tqdm_metrics': {}
})
return output
def validation_step(self, data_batch, batch_i):
"""
Called inside the validation loop
:param data_batch:
@@ -87,9 +96,14 @@ class ExampleModel(RootModule):
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
output = {'y_hat': y_hat, 'val_loss': loss_val.item(), 'val_acc': val_acc}
# output = {'y_hat': y_hat, 'val_loss': loss_val.item(), 'val_acc': val_acc}
output = OrderedDict({
'val_loss': loss_val,
'val_acc': torch.tensor(val_acc),
})
return output
def validation_end(self, outputs):
"""
Called at the end of validation to aggregate outputs
@@ -97,13 +111,14 @@ class ExampleModel(RootModule):
:return:
"""
val_loss_mean = 0
accs = []
val_acc_mean = 0
for output in outputs:
val_loss_mean += output['val_loss']
accs.append(output['val_acc'])
val_acc_mean += output['val_acc']
val_loss_mean /= len(outputs)
tqdm_dic = {'val_loss': val_loss_mean, 'val_acc': np.mean(accs)}
val_acc_mean /= len(outputs)
tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
return tqdm_dic
def update_tng_log_metrics(self, logs):
@@ -177,7 +192,7 @@ class ExampleModel(RootModule):
return self._test_dataloader
@staticmethod
def add_model_specific_args(parent_parser):
def add_model_specific_args(parent_parser, root_dir):
parser = HyperOptArgumentParser(strategy=parent_parser.strategy, parents=[parent_parser])
# param overwrites
@@ -186,11 +201,11 @@ class ExampleModel(RootModule):
# network params
parser.opt_list('--drop_prob', default=0.2, options=[0.2, 0.5], type=float, tunable=False)
parser.add_argument('--in_features', default=28*28)
parser.add_argument('--hidden_dim', default=500)
parser.add_argument('--out_features', default=10)
parser.add_argument('--hidden_dim', default=50000) # use 500 for CPU, 50000 for GPU to see speed difference
# data
parser.add_argument('--data_root', default='/Users/williamfalcon/Developer/personal/research_lib/research_proj/datasets/mnist', type=str)
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
# training params (opt)
parser.opt_list('--learning_rate', default=0.001, type=float, options=[0.0001, 0.0005, 0.001, 0.005],
+28 -19
View File
@@ -5,10 +5,10 @@ from time import sleep
import torch
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
from pytorch-lightning.models.trainer import Trainer
from pytorch-lightning.utils.arg_parse import add_default_args
from pytorch_lightning.models.trainer import Trainer
from pytorch_lightning.utils.arg_parse import add_default_args
from pytorch-lightning.utils.pt_callbacks import EarlyStopping, ModelCheckpoint
from pytorch_lightning.utils.pt_callbacks import EarlyStopping, ModelCheckpoint
SEED = 2334
torch.manual_seed(SEED)
@@ -17,7 +17,7 @@ np.random.seed(SEED)
# ---------------------
# DEFINE MODEL HERE
# ---------------------
from example_model import ExampleModel
from docs.source.examples.example_model import ExampleModel
# ---------------------
AVAILABLE_MODELS = {
@@ -42,9 +42,7 @@ def main(hparams, cluster, results_dict):
:param hparams:
:return:
"""
on_gpu = torch.cuda.is_available()
if hparams.disable_cuda:
on_gpu = False
on_gpu = hparams.gpus is not None and torch.cuda.is_available()
device = 'cuda' if on_gpu else 'cpu'
hparams.__setattr__('device', device)
@@ -93,12 +91,18 @@ def main(hparams, cluster, results_dict):
mode=hparams.model_save_monitor_mode
)
# gpus are ; separated for inside a node and , within nodes
gpu_list = None
if hparams.gpus is not None:
gpu_list = [int(x) for x in hparams.gpus.split(';')]
# configure trainer
trainer = Trainer(
experiment=exp,
cluster=cluster,
checkpoint_callback=checkpoint,
early_stop_callback=early_stop,
gpus=gpu_list
)
# train model
@@ -159,35 +163,40 @@ if __name__ == '__main__':
model_name = 'model_template'
# use default args
root_dir = os.path.split(os.path.dirname(sys.modules['__main__'].__file__))[0]
root_dir = os.path.dirname(os.path.realpath(__file__))
parent_parser = get_default_parser(strategy='random_search', root_dir=root_dir)
# allow model to overwrite or extend args
TRAINING_MODEL = AVAILABLE_MODELS[model_name]
parser = TRAINING_MODEL.add_model_specific_args(parent_parser)
parser = TRAINING_MODEL.add_model_specific_args(parent_parser, root_dir)
hyperparams = parser.parse_args()
# format GPU layout
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
gpu_ids = hyperparams.gpus.split(';')
# ---------------------
# RUN TRAINING
# ---------------------
# cluster and CPU
if hyperparams.on_cluster:
# Gets called when running via HPC cluster
# run on HPC cluster
print('RUNNING ON SLURM CLUSTER')
gpu_ids = hyperparams.gpus.split(';')
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(gpu_ids)
optimize_on_cluster(hyperparams)
elif hyperparams.single_run_gpu:
# run on 1 gpu
print(f'RUNNING 1 TRIAL ON GPU. gpu: {gpu_ids[0]}')
os.environ["CUDA_VISIBLE_DEVICES"] = gpu_ids[0]
elif hyperparams.gpus is None:
# run on cpu
print('RUNNING ON CPU')
main(hyperparams, None, None)
elif hyperparams.local or hyperparams.single_run:
# run 1 trial but on CPU
os.environ["CUDA_VISIBLE_DEVICES"] = '0'
print('RUNNING LOCALLY')
# single or multiple GPUs on same machine
gpu_ids = hyperparams.gpus.split(';')
if hyperparams.interactive:
# run on 1 gpu
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {gpu_ids}')
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(gpu_ids)
main(hyperparams, None, None)
else:
+73 -23
View File
@@ -5,6 +5,7 @@ from pytorch_lightning.root_module.memory import get_gpu_memory_map
import traceback
from pytorch_lightning.root_module.model_saving import TrainerIO
from torch.optim.lr_scheduler import MultiStepLR
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDataParallel
import pdb
try:
@@ -13,6 +14,20 @@ try:
except ModuleNotFoundError:
APEX_AVAILABLE = False
def reduce_distributed_output(output, nb_gpus):
for k, v in output.items():
# recurse on nested dics
if isinstance(output[k], dict):
output[k] = reduce_distributed_output(output[k], nb_gpus)
# reduce only metrics that have the same nb of gpus
elif output[k].size(0) == nb_gpus:
reduced = torch.mean(output[k])
output[k] = reduced
return output
class Trainer(TrainerIO):
def __init__(self,
@@ -21,7 +36,7 @@ class Trainer(TrainerIO):
cluster=None,
process_position=0,
current_gpu_name=0,
on_gpu=False,
gpus=None,
enable_tqdm=True,
overfit_pct=0.0,
track_grad_norm=-1,
@@ -42,7 +57,7 @@ class Trainer(TrainerIO):
self.enable_early_stop = enable_early_stop
self.track_grad_norm = track_grad_norm
self.fast_dev_run = fast_dev_run
self.on_gpu = on_gpu
self.on_gpu = gpus is not None and torch.cuda.is_available()
self.enable_tqdm = enable_tqdm
self.experiment = experiment
self.exp_save_path = experiment.get_data_path(experiment.name, experiment.version)
@@ -62,6 +77,8 @@ class Trainer(TrainerIO):
self.lr_schedulers = []
self.amp_level = amp_level
self.check_grad_nans = check_grad_nans
self.data_parallel_device_ids = gpus
self.data_parallel = gpus is not None and len(gpus) > 0
# training state
self.optimizers = None
@@ -117,7 +134,7 @@ class Trainer(TrainerIO):
tqdm_dic.update(self.tqdm_metrics)
return tqdm_dic
def __layout_bookeeping(self):
def __layout_bookeeping(self, model):
# training bookeeping
self.total_batch_nb = 0
self.running_loss = []
@@ -126,17 +143,17 @@ class Trainer(TrainerIO):
self.tqdm_metrics = {}
# determine number of training batches
self.nb_tng_batches = self.model.nb_batches(self.tng_dataloader)
self.nb_tng_batches = model.nb_batches(self.tng_dataloader)
self.nb_tng_batches = int(self.nb_tng_batches * self.train_percent_check)
# determine number of validation batches
self.nb_val_batches = self.model.nb_batches(self.val_dataloader)
self.nb_val_batches = model.nb_batches(self.val_dataloader)
self.nb_val_batches = int(self.nb_val_batches * self.val_percent_check)
self.nb_val_batches = max(1, self.nb_val_batches)
self.nb_val_batches = self.nb_val_batches
# determine number of test batches
self.nb_test_batches = self.model.nb_batches(self.test_dataloader)
self.nb_test_batches = model.nb_batches(self.test_dataloader)
self.nb_test_batches = int(self.nb_test_batches * self.test_percent_check)
# determine when to check validation
@@ -159,6 +176,7 @@ class Trainer(TrainerIO):
# enable eval mode
model.zero_grad()
model.eval()
model.from_lightning = True
# disable gradients to save memory
torch.set_grad_enabled(False)
@@ -179,7 +197,12 @@ class Trainer(TrainerIO):
# -----------------
# RUN VALIDATION STEP
# -----------------
output = model.validation_step(data_batch, batch_i)
if self.data_parallel:
output = model(data_batch, batch_i)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
else:
output = model.validation_step(data_batch, batch_i)
outputs.append(output)
# batch done
@@ -187,13 +210,17 @@ class Trainer(TrainerIO):
self.prog_bar.update(1)
# give model a chance to do something with the outputs
val_results = model.validation_end(outputs)
if self.data_parallel:
val_results = model.module.validation_end(outputs)
else:
val_results = model.validation_end(outputs)
# enable train mode again
model.train()
# enable gradients to save memory
torch.set_grad_enabled(True)
return val_results
def __get_dataloaders(self, model):
@@ -210,14 +237,14 @@ class Trainer(TrainerIO):
# MODEL TRAINING
# -----------------------------
def fit(self, model):
self.model = model
model.trainer = self
# transfer data loaders from model
self.__get_dataloaders(model)
# init training constants
self.__layout_bookeeping()
self.__layout_bookeeping(model)
# CHOOSE OPTIMIZER
# filter out the weights that were done on gpu so we can load on good old cpus
@@ -225,8 +252,8 @@ class Trainer(TrainerIO):
if self.use_amp:
# An example
self.model, optimizer = amp.initialize(
self.model, self.optimizers[0], opt_level=self.amp_level,
model, optimizer = amp.initialize(
model, self.optimizers[0], opt_level=self.amp_level,
)
self.optimizers[0] = optimizer
model.trainer = self
@@ -242,7 +269,7 @@ class Trainer(TrainerIO):
# put on gpu if needed
if self.on_gpu:
model = model.cuda()
model = LightningDataParallel(model, device_ids=self.data_parallel_device_ids)
# run tiny validation to make sure program won't crash during val
_ = self.validate(model, self.val_dataloader, max_batches=self.nb_sanity_val_steps)
@@ -257,6 +284,7 @@ class Trainer(TrainerIO):
# ---------------------------
# CORE TRAINING LOOP
# ---------------------------
self.model = model
self.__train()
def __train(self):
@@ -266,11 +294,13 @@ class Trainer(TrainerIO):
for lr_scheduler in self.lr_schedulers:
lr_scheduler.step()
self.model.current_epoch = epoch_nb
model = self.model.module if self.data_parallel else self.model
model.current_epoch = epoch_nb
# hook
if self.__is_function_implemented('on_epoch_start'):
self.model.on_epoch_start()
model = self.model.module if self.data_parallel else self.model
model.on_epoch_start()
self.current_epoch = epoch_nb
self.total_batches = self.nb_tng_batches + self.nb_val_batches
@@ -283,7 +313,9 @@ class Trainer(TrainerIO):
for batch_nb, data_batch in enumerate(self.tng_dataloader):
self.batch_nb = batch_nb
self.global_step += 1
self.model.global_step = self.global_step
model = self.model.module if self.data_parallel else self.model
model.global_step = self.global_step
# stop when the flag is changed or we've gone past the amount requested in the batches
self.total_batch_nb += 1
@@ -313,7 +345,10 @@ class Trainer(TrainerIO):
# count items in memory
# nb_params, nb_tensors = count_mem_items()
metrics = self.model.update_tng_log_metrics(self.__tng_tqdm_dic)
if self.data_parallel:
metrics = self.model.module.update_tng_log_metrics(self.__tng_tqdm_dic)
else:
metrics = self.model.update_tng_log_metrics(self.__tng_tqdm_dic)
# add gpu memory
if self.on_gpu:
@@ -322,7 +357,9 @@ class Trainer(TrainerIO):
# add norms
if self.track_grad_norm > 0:
grad_norm_dic = self.model.grad_norm(self.track_grad_norm)
model = self.model.module if self.data_parallel else self.model
grad_norm_dic = model.grad_norm(self.track_grad_norm)
metrics.update(grad_norm_dic)
# log metrics
@@ -331,7 +368,8 @@ class Trainer(TrainerIO):
# hook
if self.__is_function_implemented('on_batch_end'):
self.model.on_batch_end()
model = self.model.module if self.data_parallel else self.model
model.on_batch_end()
# end epoch early
if early_stop_epoch:
@@ -339,7 +377,8 @@ class Trainer(TrainerIO):
# hook
if self.__is_function_implemented('on_epoch_end'):
self.model.on_epoch_end()
model = self.model.module if self.data_parallel else self.model
model.on_epoch_end()
# early stopping
if self.enable_early_stop:
@@ -358,7 +397,9 @@ class Trainer(TrainerIO):
# hook
if self.__is_function_implemented('on_batch_start'):
response = self.model.on_batch_start(data_batch)
model = self.model.module if self.data_parallel else self.model
response = model.on_batch_start(data_batch)
if response == -1:
return -1
@@ -367,7 +408,15 @@ class Trainer(TrainerIO):
# forward pass
# return a scalar value and a dic with tqdm metrics
loss, model_specific_tqdm_metrics_dic = self.model.training_step(data_batch, batch_nb)
if self.data_parallel:
output = self.model(data_batch, batch_nb)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
else:
output = self.model.training_step(data_batch, batch_nb)
model_specific_tqdm_metrics_dic = output['tqdm_metrics']
loss = output['loss']
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
# backward pass
@@ -379,7 +428,8 @@ class Trainer(TrainerIO):
loss.backward()
if self.check_grad_nans:
for param in self.model.parameters():
model = self.model.module if self.data_parallel else self.model
for param in model.parameters():
print(param.grad.float().sum())
self.batch_loss_value += loss.item()
@@ -0,0 +1,105 @@
from torch.nn import DataParallel
import threading
import torch
from torch.cuda._utils import _get_device_index
import pdb
def get_a_var(obj):
if isinstance(obj, torch.Tensor):
return obj
if isinstance(obj, list) or isinstance(obj, tuple):
for result in map(get_a_var, obj):
if isinstance(result, torch.Tensor):
return result
if isinstance(obj, dict):
for result in map(get_a_var, obj.items()):
if isinstance(result, torch.Tensor):
return result
return None
class LightningDataParallel(DataParallel):
"""
Override the forward call in lightning so it goes to training and validation step respectively
"""
def parallel_apply(self, replicas, inputs, kwargs):
return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
def parallel_apply(modules, inputs, kwargs_tup=None, devices=None):
r"""Applies each `module` in :attr:`modules` in parallel on arguments
contained in :attr:`inputs` (positional) and :attr:`kwargs_tup` (keyword)
on each of :attr:`devices`.
Args:
modules (Module): modules to be parallelized
inputs (tensor): inputs to the modules
devices (list of int or torch.device): CUDA devices
:attr:`modules`, :attr:`inputs`, :attr:`kwargs_tup` (if given), and
:attr:`devices` (if given) should all have same length. Moreover, each
element of :attr:`inputs` can either be a single object as the only argument
to a module, or a collection of positional arguments.
"""
assert len(modules) == len(inputs)
if kwargs_tup is not None:
assert len(modules) == len(kwargs_tup)
else:
kwargs_tup = ({},) * len(modules)
if devices is not None:
assert len(modules) == len(devices)
else:
devices = [None] * len(modules)
devices = list(map(lambda x: _get_device_index(x, True), devices))
lock = threading.Lock()
results = {}
grad_enabled = torch.is_grad_enabled()
def _worker(i, module, input, kwargs, device=None):
torch.set_grad_enabled(grad_enabled)
if device is None:
device = get_a_var(input).get_device()
try:
with torch.cuda.device(device):
# this also avoids accidental slicing of `input` if it is a Tensor
if not isinstance(input, (list, tuple)):
input = (input,)
# ---------------
# CHANGE
if module.training:
output = module.training_step(*input, **kwargs)
else:
output = module.validation_step(*input, **kwargs)
# ---------------
with lock:
results[i] = output
except Exception as e:
with lock:
results[i] = e
if len(modules) > 1:
threads = [threading.Thread(target=_worker,
args=(i, module, input, kwargs, device))
for i, (module, input, kwargs, device) in
enumerate(zip(modules, inputs, kwargs_tup, devices))]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
else:
_worker(0, modules[0], inputs[0], kwargs_tup[0], devices[0])
outputs = []
for i in range(len(inputs)):
output = results[i]
if isinstance(output, Exception):
raise output
outputs.append(output)
return outputs
+13 -3
View File
@@ -1,7 +1,8 @@
import torch
import os
import re
import pdb
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDataParallel
class ModelIO(object):
@@ -48,7 +49,8 @@ class TrainerIO(object):
checkpoint['optimizer_states'] = optimizer_states
# request what to save from the model
checkpoint_dict = self.model.get_save_dict()
model = self.model.module if type(self.model) is LightningDataParallel else self.model
checkpoint_dict = model.get_save_dict()
# merge trainer and model saving items
checkpoint.update(checkpoint_dict)
@@ -99,6 +101,9 @@ class TrainerIO(object):
# PRIVATE OPS
# ----------------------------------
def hpc_save(self, folderpath, experiment):
# make sure the checkpoint folder exists
os.makedirs(folderpath, exist_ok=True)
# save exp to make sure we get all the metrics
experiment.save()
@@ -126,10 +131,15 @@ class TrainerIO(object):
self.restore_training_state(checkpoint)
# load model state
self.model.load_model_specific(checkpoint)
model = self.model.module if type(self.model) is LightningDataParallel else self.model
model.load_model_specific(checkpoint)
def max_ckpt_in_folder(self, path):
files = os.listdir(path)
files = [x for x in files if 'ckpt_' in x]
if len(files) == 0:
return 0
ckpt_vs = []
for name in files:
name = name.split('ckpt_')[-1]
@@ -25,6 +25,7 @@ class RootModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
self.gradient_clip = hparams.gradient_clip
self.num = 2
self.trainer = None
self.from_lightning = True
# track if gpu was requested for checkpointing
self.on_gpu = False
+6 -6
View File
@@ -1,3 +1,5 @@
import pdb
def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None):
# tng, test, val check intervals
@@ -45,10 +47,8 @@ def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None
parser.add_argument('--log_stdout', dest='log_stdout', action='store_true')
# GPU
parser.add_argument('--per_experiment_nb_gpus', default=1, type=int)
parser.add_argument('--gpus', default='0', type=str)
parser.add_argument('--gpus', default=None, type=str)
parser.add_argument('--single_run_gpu', dest='single_run_gpu', action='store_true')
parser.add_argument('--disable_cuda', dest='disable_cuda', action='store_true')
parser.add_argument('--default_tensor_type', default='torch.cuda.FloatTensor', type=str)
parser.add_argument('--use_amp', dest='use_amp', action='store_true')
parser.add_argument('--check_grad_nans', dest='check_grad_nans', action='store_true')
@@ -68,9 +68,9 @@ def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None
if rand_seed is not None:
parser.add_argument('--random_seed', default=rand_seed, type=int)
parser.add_argument('--live', dest='live', action='store_true', help='runs on gpu without cluster')
parser.add_argument('--enable_debug', dest='debug', action='store_true', help='enables/disables test tube')
parser.add_argument('--enable_local', dest='local', action='store_true', help='enables local tng')
parser.add_argument('--interactive', dest='interactive', action='store_true', help='runs on gpu without cluster')
parser.add_argument('--debug', dest='debug', action='store_true', help='enables/disables test tube')
parser.add_argument('--local', dest='local', action='store_true', help='enables local tng')
# optimizer
parser.add_argument('--lr_scheduler_milestones', default=None, type=str)
+3
View File
@@ -1,5 +1,6 @@
import numpy as np
import os, shutil
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDataParallel
class Callback(object):
@@ -33,6 +34,8 @@ class Callback(object):
self.params = params
def set_model(self, model):
if type(model) is LightningDataParallel:
model = model.module
self.model = model
def on_epoch_begin(self, epoch, logs=None):
+1 -1
View File
@@ -7,7 +7,7 @@ from setuptools import setup, find_packages
# http://blog.ionelmc.ro/2014/05/25/python-packaging/
setup(
name="pytorch-lightning",
version='0.1.dev2',
version='0.11',
description="The Keras for ML researchers using PyTorch",
author="William Falcon",
author_email="waf2107@columbia.edu",