Repository: pykeen/pykeen
Issue: AttributeError: 'NoneType' object has no attribute 'mapped_triples' with  stopper = 'early'
Root cause: Validation Gap

### Describe the bug

I am using Pykeen with my own data , it works well but when using stopper = 'early' it gave an error 

> AttributeError: 'NoneType' object has no attribute 'mapped_triples'  

```python-traceback
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_39/2914315150.py in <module>
     15         stopper='early',
     16         stopper_kwargs=dict(frequency=5, patience=2, relative_delta=0.002),
---> 17         device='gpu')
     18 result_name = 'results' +'_'+ name
     19 results.save_to_directory(result_name)

/opt/conda/lib/python3.7/site-packages/pykeen/pipeline/api.py in pipeline(dataset, dataset_kwargs, training, testing, validation, evaluation_entity_whitelist, evaluation_relation_whitelist, model, model_kwargs, interaction, interaction_kwargs, dimensions, loss, loss_kwargs, regularizer, regularizer_kwargs, optimizer, optimizer_kwargs, clear_optimizer, lr_scheduler, lr_scheduler_kwargs, training_loop, training_loop_kwargs, negative_sampler, negative_sampler_kwargs, epochs, training_kwargs, stopper, stopper_kwargs, evaluator, evaluator_kwargs, evaluation_kwargs, result_tracker, result_tracker_kwargs, metadata, device, random_seed, use_testing_data, evaluation_fallback, filter_validation_when_testing, use_tqdm)
   1239         stopper=stopper_instance,
   1240         clear_optimizer=clear_optimizer,
-> 1241         **training_kwargs,
   1242     )
   1243     assert losses is not None  # losses is only none if it's doing search mode

/opt/conda/lib/python3.7/site-packages/pykeen/training/training_loop.py in train(self, triples_factory, num_epochs, batch_size, slice_size, label_smoothing, sampler, continue_training, only_size_probing, use_tqdm, use_tqdm_batch, tqdm_kwargs, stopper, sub_batch_size, num_workers, clear_optimizer, checkpoint_directory, checkpoint_name, checkpoint_frequency, checkpoint_on_failure, drop_last, callbacks, callback_kwargs, gradient_clipping_max_norm, gradient_clipping_norm_type, gradient_clipping_max_abs_value, pin_memory)
    367                 gradient_clipping_max_abs_value=gradient_clipping_max_abs_value,
    368                 triples_factory=triples_factory,
--> 369                 pin_memory=pin_memory,
    370             )
    371 

/opt/conda/lib/python3.7/site-packages/pykeen/training/training_loop.py in _train(self, triples_factory, num_epochs, batch_size, slice_size, label_smoothing, sampler, continue_training, only_size_probing, use_tqdm, use_tqdm_batch, tqdm_kwargs, stopper, sub_batch_size, num_workers, save_checkpoints, checkpoint_path, checkpoint_frequency, checkpoint_on_failure_file_path, best_epoch_model_file_path, last_best_epoch, drop_last, callbacks, callback_kwargs, gradient_clipping_max_norm, gradient_clipping_norm_type, gradient_clipping_max_abs_value, pin_memory)
    695 
    696             # Includes a call to result_tracker.log_metrics
--> 697             callback.post_epoch(epoch=epoch, epoch_loss=epoch_loss)
    698 
    699             # If a checkpoint file is given, we check whether it is time to save a checkpoint

/opt/conda/lib/python3.7/site-packages/pykeen/training/callbacks.py in post_epoch(self, epoch, epoch_loss, **kwargs)
    365     def post_epoch(self, epoch: int, epoch_loss: float, **kwargs: Any) -> None:  # noqa: D102
    366         for callback in self.callbacks:
--> 367             callback.post_epoch(epoch=epoch, epoch_loss=epoch_loss, **kwargs)
    368 
    369     def post_train(self, losses: List[float], **kwargs: Any) -> None:  # noqa: D102

/opt/conda/lib/python3.7/site-packages/pykeen/training/callbacks.py in post_epoch(self, epoch, epoch_loss, **kwargs)
    294         if self.stopper.should_evaluate(epoch):
    295             # TODO how to pass inductive mode
--> 296             if self.stopper.should_stop(epoch):
    297                 self.training_loop._should_stop = True
    298             # Since the model is also used within the stopper, its graph and cache have to be cleared

/opt/conda/lib/python3.7/site-packages/pykeen/stoppers/early_stopping.py in should_stop(self, epoch, mode)
    206             model=self.model,
    207             additional_filter_triples=self.training_triples_factory.mapped_triples,
--> 208             mapped_triples=self.evaluation_triples_factory.mapped_triples,
    209             use_tqdm=False,
    210             batch_size=self.evaluation_batch_size,

AttributeError: 'NoneType' object has no attribute 'mapped_triples](url)
```


### How to reproduce

My code : 
```python
tf = TriplesFactory.from_labeled_triples(dataset.values)
training, testing = tf.split(random_state=1234)
results = pipeline(
        training=training,
        testing=testing,
        model='BoxE',
        training_kwargs=dict(num_epochs=50),
        random_seed=1235, 
        stopper='early',
        device='gpu')
```

### Environment

> <html>
> <body>
> <!--StartFragment-->
> 
> Key | Value
> -- | --
> OS | posix
> Platform | Linux
> Release | 5.10.90+
> Time | Thu Mar 17 10:23:03 2022
> Python | 3.7.12
> PyKEEN | 1.7.1-dev
> PyKEEN Hash | UNHASHED
> PyKEEN Branch |  
> PyTorch | 1.11.0+cu102
> CUDA Available? | true
> CUDA Version | 10.2
> cuDNN Version | 7605
> 
> <!--EndFragment-->
> </body>
> </html>

### Additional information

_No response_

You can't use early stopping in the pipeline without providing the `validation` keyword argument. The bug here is that it doesn't show a more helpful - but this is desired functionality

Thanks for reply 


You can change the split line to be something like this:
`training, testing, validation = tf.split([0.8, 0.1, 0.1], random_state=1234)`