hotfix to unblock hparams and OmniConf - removes auto_register_init_args by default (#2025)

* ogc install

* cleaned up tests

* hot fix

* hot fix

* hot fix

* hot fix

* hot fix

* hot fix

* hot fix

* hot fix

* hot fix
This commit is contained in:
William Falcon
2020-05-31 08:29:51 -04:00
committed by GitHub
parent 9893681859
commit 0e37e8c4d2
8 changed files with 120 additions and 98 deletions
+9 -8
View File
@@ -33,7 +33,7 @@ else:
CHECKPOINT_KEY_MODULE_ARGS = 'module_arguments'
class LightningModule(ABC, DeviceDtypeModuleMixin, GradInformation, ModelIO, ModelHooks):
class LightningModule(ABC, DeviceDtypeModuleMixin, GradInformation, ModelIO, ModelHooks, torch.nn.Module):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -76,9 +76,6 @@ class LightningModule(ABC, DeviceDtypeModuleMixin, GradInformation, ModelIO, Mod
#: device reference
self._device = torch.device('cpu')
# register all params passed into the child module in __init__
self._auto_collect_arguments()
@property
def on_gpu(self):
"""
@@ -1701,7 +1698,7 @@ class LightningModule(ABC, DeviceDtypeModuleMixin, GradInformation, ModelIO, Mod
" and this method will be removed in v1.0.0", DeprecationWarning)
return self.get_progress_bar_dict()
def _auto_collect_arguments(self):
def auto_collect_arguments(self):
"""Collect all arguments module arguments."""
frame = inspect.currentframe()
@@ -1717,9 +1714,13 @@ class LightningModule(ABC, DeviceDtypeModuleMixin, GradInformation, ModelIO, Mod
@property
def module_arguments(self) -> dict:
"""Aggregate this module and all parents arguments."""
args = dict(self._module_parents_arguments)
args.update(self._module_self_arguments)
return args
try:
args = dict(self._module_parents_arguments)
args.update(self._module_self_arguments)
return args
except AttributeError as e:
rank_zero_warn('you called `module.module_arguments` without calling self.auto_collect_arguments()')
return {}
def _collect_init_args(frame, path_args: list) -> list:
+2 -1
View File
@@ -8,4 +8,5 @@ wandb>=0.8.21
trains>=0.14.1
matplotlib>=3.1.1
# no need to install with [pytorch] as pytorch is already installed and torchvision is required only for Horovod examples
horovod>=0.19.1
horovod>=0.19.1
omegaconf==2.0.0
+2
View File
@@ -53,6 +53,8 @@ class EvalModelTemplate(
**kwargs) -> object:
# init superclass
super().__init__()
self.auto_collect_arguments()
self.drop_prob = drop_prob
self.batch_size = batch_size
self.in_features = in_features
+6 -10
View File
@@ -23,16 +23,12 @@ class TrainingStepVariations(ABC):
loss_val = self.loss(y, y_hat)
# alternate possible outputs to test
if self.trainer.batch_idx % 1 == 0:
output = OrderedDict({
'loss': loss_val,
'progress_bar': {'some_val': loss_val * loss_val},
'log': {'train_some_val': loss_val * loss_val},
})
return output
if self.trainer.batch_idx % 2 == 0:
return loss_val
output = OrderedDict({
'loss': loss_val,
'progress_bar': {'some_val': loss_val * loss_val},
'log': {'train_some_val': loss_val * loss_val},
})
return output
def training_step__inf_loss(self, batch, batch_idx, optimizer_idx=None):
output = self.training_step(batch, batch_idx, optimizer_idx)
+26 -19
View File
@@ -20,28 +20,35 @@ class ValidationEpochEndVariations(ABC):
# recursive mean for multilevel dicts
return torch.stack([x[key] if isinstance(x, dict) else _mean(x, key) for x in res]).mean()
# return torch.stack(outputs).mean()
val_loss_mean = _mean(outputs, 'val_loss')
val_acc_mean = _mean(outputs, 'val_acc')
for output in outputs:
val_loss = self.get_output_metric(output, 'val_loss')
# reduce manually when using dp
if self.trainer.use_dp or self.trainer.use_ddp2:
val_loss = torch.mean(val_loss)
val_loss_mean += val_loss
# reduce manually when using dp
val_acc = self.get_output_metric(output, 'val_acc')
if self.trainer.use_dp or self.trainer.use_ddp2:
val_acc = torch.mean(val_acc)
val_acc_mean += val_acc
if outputs: # skip zero divisions
val_loss_mean /= len(outputs)
val_acc_mean /= len(outputs)
metrics_dict = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
results = {'progress_bar': metrics_dict, 'log': metrics_dict}
return results
def validation_epoch_end_multiple_dataloaders(self, outputs):
"""
Called at the end of validation to aggregate outputs
Args:
outputs: list of individual outputs of each validation step
"""
# if returned a scalar from validation_step, outputs is a list of tensor scalars
# we return just the average in this case (if we want)
def _mean(res, key):
return torch.stack([x[key] for x in res]).mean()
pbar = {}
logs = {}
for dl_output_list in outputs:
output_keys = dl_output_list[0].keys()
output_keys = [x for x in output_keys if 'val_' in x]
for key in output_keys:
metric_out = _mean(dl_output_list, key)
pbar[key] = metric_out
logs[key] = metric_out
results = {'progress_bar': pbar, 'log': logs}
return results
+13 -58
View File
@@ -23,33 +23,14 @@ class ValidationStepVariations(ABC):
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
val_acc = torch.tensor(val_acc).type_as(x)
if self.on_gpu:
val_acc = val_acc.cuda(loss_val.device.index)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
val_acc = val_acc.unsqueeze(0)
# alternate possible outputs to test
if batch_idx % 1 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
})
return output
if batch_idx % 2 == 0:
return val_acc
if batch_idx % 3 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
'test_dic': {'val_loss_a': loss_val}
})
return output
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
'test_dic': {'val_loss_a': loss_val}
})
return output
def validation_step__multiple_dataloaders(self, batch, batch_idx, dataloader_idx, **kwargs):
"""
@@ -66,36 +47,10 @@ class ValidationStepVariations(ABC):
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
val_acc = torch.tensor(val_acc).type_as(x)
if self.on_gpu:
val_acc = val_acc.cuda(loss_val.device.index)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
val_acc = val_acc.unsqueeze(0)
# alternate possible outputs to test
if batch_idx % 1 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
})
return output
if batch_idx % 2 == 0:
return val_acc
if batch_idx % 3 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
'test_dic': {'val_loss_a': loss_val}
})
return output
if batch_idx % 5 == 0:
output = OrderedDict({
f'val_loss_{dataloader_idx}': loss_val,
f'val_acc_{dataloader_idx}': val_acc,
})
return output
output = OrderedDict({
f'val_loss_{dataloader_idx}': loss_val,
f'val_acc_{dataloader_idx}': val_acc,
})
return output
+60 -2
View File
@@ -3,9 +3,65 @@ import os
import pytest
import torch
from pytorch_lightning import Trainer
from pytorch_lightning import Trainer, LightningModule
from pytorch_lightning.core.lightning import CHECKPOINT_KEY_MODULE_ARGS
from tests.base import EvalModelTemplate
from omegaconf import OmegaConf
import sys
class OmegaConfModel(EvalModelTemplate):
def __init__(self, ogc):
super().__init__()
self.ogc = ogc
self.size = ogc.list[0]
def test_class_nesting(tmpdir):
class Module(LightningModule):
def forward(self):
return 0
# make sure PL modules are always nn.Module
a = Module()
assert isinstance(a, torch.nn.Module)
def test_outside():
a = Module()
print(a.module_arguments)
class A:
def test(self):
a = Module()
print(a.module_arguments)
def test2(self):
test_outside()
test_outside()
A().test2()
A().test()
def test_omegaconf(tmpdir):
# ogc only for 3.8
major = sys.version_info[0]
minor = sys.version_info[1]
if major < 3 and minor < 8:
return
conf = OmegaConf.create({"k": "v", "list": [15.4, {"a": "1", "b": "2"}]})
model = OmegaConfModel(conf)
# ensure ogc passed values correctly
assert model.size == 15.4
trainer = Trainer(default_root_dir=tmpdir, max_epochs=2, overfit_pct=0.5)
result = trainer.fit(model)
assert result == 1
class SubClassEvalModel(EvalModelTemplate):
@@ -14,6 +70,7 @@ class SubClassEvalModel(EvalModelTemplate):
def __init__(self, *args, subclass_arg=1200, **kwargs):
super().__init__(*args, **kwargs)
self.subclass_arg = subclass_arg
self.auto_collect_arguments()
class SubSubClassEvalModel(SubClassEvalModel):
@@ -25,6 +82,7 @@ class AggSubClassEvalModel(SubClassEvalModel):
def __init__(self, *args, my_loss=torch.nn.CrossEntropyLoss(), **kwargs):
super().__init__(*args, **kwargs)
self.my_loss = my_loss
self.auto_collect_arguments()
@pytest.mark.parametrize("cls", [EvalModelTemplate,
@@ -47,7 +105,7 @@ def test_collect_init_arguments(tmpdir, cls):
assert isinstance(model.my_loss, torch.nn.CosineEmbeddingLoss)
# verify that the checkpoint saved the correct values
trainer = Trainer(max_steps=5, default_root_dir=tmpdir)
trainer = Trainer(default_root_dir=tmpdir, max_epochs=2, overfit_pct=0.5)
trainer.fit(model)
raw_checkpoint_path = os.listdir(trainer.checkpoint_callback.dirpath)
raw_checkpoint_path = [x for x in raw_checkpoint_path if '.ckpt' in x][0]
+2
View File
@@ -74,6 +74,7 @@ def test_multiple_val_dataloader(tmpdir):
model = EvalModelTemplate()
model.val_dataloader = model.val_dataloader__multiple
model.validation_step = model.validation_step__multiple_dataloaders
model.validation_epoch_end = model.validation_epoch_end_multiple_dataloaders
# fit model
trainer = Trainer(
@@ -193,6 +194,7 @@ def test_multiple_dataloaders_passed_to_fit(tmpdir):
model = EvalModelTemplate()
model.validation_step = model.validation_step__multiple_dataloaders
model.validation_epoch_end = model.validation_epoch_end_multiple_dataloaders
model.test_step = model.test_step__multiple_dataloaders
# train, multiple val and multiple test passed to fit