Confusing interaction between training dataloaders and datasets in Trainer
Trainer documentation suggests to override `get_train_dataloader` for custom behaviour. 

However, the `train` method does not respect this.

It directly goes back to `train_dataset`
```
train_dataset_is_sized = has_length(self.train_dataset)
```
And then it gets `num_examples` from `train_dataloader`, rather than the length it just checked.
```
# this accesses train_dataloader.dataset, which could very well not exist
num_examples = (
    self.num_examples(train_dataloader) if train_dataset_is_sized else total_train_batch_size * args.max_steps
)
```

I suggest changing it to something like
```
try:
  num_examples = self.num_examples(train_dataloader)
  # other code for train_dataset_is_sized being true before
except NameError: # no length
  # other code for train_dataset_is_sized being false before
  num_examples = total_train_batch_size * args.max_steps
```

This way one can override `num_examples` to handle more exotic dataloaders, even in the absence of a train_dataset property.

Happy to create a PR, just wanted to check if there is a good reason for the current setup.


I'm not sure this is the only thing that would require some changes, but I'm happy to review a PR.<|||||>This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the [contributing guidelines](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md) are likely to be ignored.