Correctly using `ReduceLROnPlateau`
Hello all, I'm trying to use the learning rate scheduler ReduceLROnPlateau, though I'm not sure I'm implementing this correctly. The scheduler doesn't seem to be working properly.
I am essentially using the same code as the Colab MNIST tutorial (I ran this in colab)
import os

import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision import transforms
import pytorch_lightning as pl

class MNISTModel(pl.LightningModule):

    def __init__(self):
        super(MNISTModel, self).__init__()
        # not the best model...
        self.l1 = torch.nn.Linear(28 * 28, 10)

    def forward(self, x):
        return torch.relu(self.l1(x.view(x.size(0), -1)))

    def training_step(self, batch, batch_nb):
        # REQUIRED
        x, y = batch
        y_hat = self.forward(x)
        loss = F.cross_entropy(y_hat, y)
        tensorboard_logs = {'train_loss': loss}
        return {'loss': loss, 'log': tensorboard_logs}

    def validation_step(self, batch, batch_nb):
        # OPTIONAL
        x, y = batch
        y_hat = self.forward(x)
        return {'val_loss': F.cross_entropy(y_hat, y)}

    def validation_end(self, outputs):
        # OPTIONAL
        avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()
        tensorboard_logs = {'val_loss': avg_loss}
        print(avg_loss)
        return {'val_loss': avg_loss, 'log': tensorboard_logs}

    def test_step(self, batch, batch_nb):
        # OPTIONAL
        x, y = batch
        y_hat = self.forward(x)
        return {'test_loss': F.cross_entropy(y_hat, y)}

    def test_end(self, outputs):
        # OPTIONAL
        avg_loss = torch.stack([x['test_loss'] for x in outputs]).mean()
        logs = {'test_loss': avg_loss}
        return {'avg_test_loss': avg_loss, 'log': logs, 'progress_bar': logs}

    def configure_optimizers(self):
        # REQUIRED
        # can return multiple optimizers and learning_rate schedulers
        # (LBFGS it is automatically supported, no need for closure function)
        optimizer = torch.optim.Adam(self.parameters(), lr=0.02)
        scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,
                                                               mode='min',
                                                               factor=0.2,
                                                               patience=2,
                                                               min_lr=1e-6,
                                                               verbose=True)
        return [optimizer], [scheduler]


    @pl.data_loader
    def train_dataloader(self):
        # REQUIRED
        return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=512)

    @pl.data_loader
    def val_dataloader(self):
        # OPTIONAL
        return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=512)

    @pl.data_loader
    def test_dataloader(self):
        # OPTIONAL
        return DataLoader(MNIST(os.getcwd(), train=False, download=True, transform=transforms.ToTensor()), batch_size=512)
The only differences besides the configure_optimizers() method are the batch size (512 vs. 32 originally) and printing (though I don't see how either of these would affect the scheduler behavior).
Question: does the scheduler here automatically receive val_loss computed in the validation_end() step? I've tried running the above code using both avg_val_loss and val_loss as keys in the dictionary returned by validation_end(), and it does not seem to make a difference.
Despite the average validation loss seeming to decrease monotonically, the lr scheduler keeps on reducing the learning rate.
tensor(2.3137, device='cuda:0')
tensor(0.6615, device='cuda:0')

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/trainer_io.py:210: UserWarning: Did not find hyperparameters at model.hparams. Saving checkpoint without hyperparameters
  "Did not find hyperparameters at model.hparams. Saving checkpoint without"

tensor(0.6424, device='cuda:0')
tensor(0.6337, device='cuda:0')
tensor(0.6291, device='cuda:0')
Epoch     3: reducing learning rate of group 0 to 4.0000e-03.
tensor(0.6162, device='cuda:0')
tensor(0.6147, device='cuda:0')
tensor(0.6137, device='cuda:0')
Epoch     6: reducing learning rate of group 0 to 8.0000e-04.
tensor(0.6121, device='cuda:0')
tensor(0.6118, device='cuda:0')
tensor(0.6115, device='cuda:0')
Epoch     9: reducing learning rate of group 0 to 1.6000e-04.
tensor(0.6114, device='cuda:0')
tensor(0.6113, device='cuda:0')
tensor(0.6113, device='cuda:0')
Epoch    12: reducing learning rate of group 0 to 3.2000e-05.

Could anyone kindly advise as to how to correctly implement the scheduler? Thank you.
Edit: I forgot to attach the code for the Trainer portion, but it is also essentially the same as in the example.
mnist_model = MNISTModel()

# most basic trainer, uses good defaults (1 gpu)
trainer = pl.Trainer(gpus=1, show_progress_bar=False)    
trainer.fit(mnist_model)