Repository: Lightning-AI/pytorch-lightning

Issue:
training_step log requires that tbptt_reduce_fx is also set
## 🐛 Bug

`training_step` `log` requires that `tbptt_reduce_fx` is also set.

#### Code sample

```python
def training_step(self, batch, batch_idx):
    ...
    self.log("train_loss", loss, on_step=False, on_epoch=True, sync_dist=True)
    self.log(
        "foo",
        torch.tensor(self.current_epoch),
        on_step=False,
        on_epoch=True,
        reduce_fx=max,
        #tbptt_reduce_fx=max, ERROR when commented
    )
    return loss

def validation_step(self, batch, batch_idx):
    # No issues here
    self.log(
        "bar",
        torch.tensor(self.global_step),
        on_step=False,
        on_epoch=True,
        reduce_fx=max,
    )
```

Error:
```
time_outputs = [{'tr_loss': tensor(6.2107), 'foo': tensor(0), 'minimize': tensor(6.2107)}]

    @classmethod
    def reduce_across_time(cls, time_outputs):
        # auto-reduce across time for tbptt
        meta = time_outputs[0]['meta']
    
        # in 1.0 the results have 'extra'. Once we deprecate 0.10.0 we may not need this
        if 'extra' in time_outputs[0]:
            [x.pop('extra', None) for x in time_outputs]
    
        result = cls()
        result = recursive_gather(time_outputs, result)
        recursive_stack(result)
    
        for k, value in result.items():
            if k in ['meta', 'extra']:
                continue
    
            # pick the reduce fx
            if k in ['checkpoint_on', 'early_stop_on', 'minimize']:
                tbptt_reduce_fx = torch.mean
            else:
                tbptt_reduce_fx = meta[k]['tbptt_reduce_fx']
>           result[k] = tbptt_reduce_fx(value)
E           RuntimeError: Can only calculate the mean of floating types. Got Long instead.

../../venv/lib/python3.8/site-packages/pytorch_lightning/core/step_result.py:423: RuntimeError
```

### Expected behavior

That `tbptt_reduce_fx` is not required

### Environment

Master @ commit 8be002c


Discussion:
good catch. yeah, that's a bug.

want to submit a PR?

Resolving patch:
diff --git a/pytorch_lightning/core/step_result.py b/pytorch_lightning/core/step_result.py
--- a/pytorch_lightning/core/step_result.py
+++ b/pytorch_lightning/core/step_result.py
@@ -420,7 +420,7 @@ def reduce_across_time(cls, time_outputs):
                 tbptt_reduce_fx = torch.mean
             else:
                 tbptt_reduce_fx = meta[k]['tbptt_reduce_fx']
-            result[k] = tbptt_reduce_fx(value)
+            result[k] = tbptt_reduce_fx(value.float())
 
         result['meta'] = meta
         return result


Test patch:
diff --git a/tests/trainer/logging/test_train_loop_logging_1_0.py b/tests/trainer/logging/test_train_loop_logging_1_0.py
--- a/tests/trainer/logging/test_train_loop_logging_1_0.py
+++ b/tests/trainer/logging/test_train_loop_logging_1_0.py
@@ -1,13 +1,14 @@
 """
 Tests to ensure that the training loop works with a dict (1.0)
 """
-from pytorch_lightning import Trainer
-from tests.base.deterministic_model import DeterministicModel
 from tests.base.boring_model import BoringModel
 import os
 import torch
 import pytest
 
+from pytorch_lightning import Trainer
+from tests.base.deterministic_model import DeterministicModel
+
 
 def test__training_step__log(tmpdir):
     """
@@ -242,3 +243,35 @@ def training_epoch_end(self, outputs):
 
     # assert the loggers received the expected number
     assert len(trainer.dev_debugger.logged_metrics) == ((batches / log_interval) * max_epochs) + max_epochs
+
+
+@pytest.mark.parametrize(['batches', 'fx', 'result'], [(1, min, 0), (2, max, 1), (11, max, 10)])
+def test__training_step__log_max_reduce_fx(tmpdir, batches, fx, result):
+    """
+    Tests that log works correctly with different tensor types
+    """
+    class TestModel(BoringModel):
+        def training_step(self, batch, batch_idx):
+            acc = self.step(batch[0])
+            self.log('foo', torch.tensor(batch_idx).long(), on_step=False, on_epoch=True, reduce_fx=fx)
+            return acc
+
+        def validation_step(self, batch, batch_idx):
+            output = self.layer(batch)
+            loss = self.loss(batch, output)
+            self.log('bar', torch.tensor(batch_idx).float(), on_step=False, on_epoch=True, reduce_fx=fx)
+            return {"x": loss}
+
+    model = TestModel()
+    trainer = Trainer(
+        default_root_dir=tmpdir,
+        limit_train_batches=batches,
+        limit_val_batches=batches,
+        max_epochs=2,
+        weights_summary=None,
+    )
+    trainer.fit(model)
+
+    # make sure types are correct
+    assert trainer.logged_metrics['foo'] == result
+    assert trainer.logged_metrics['bar'] == result