Repository: pykeen/pykeen
Issue: RGCN HPO Issue
Root cause: Validation Gap

### Describe the bug

When using the hyperparameter optimization pipeline and the RGCN model I run into errors where I get an error regarding the ERMLP interaction class. I have successfully ran my pipeline by removing this class and just using DistMult and ComplEx but is there a better fix for this. Even when I define my embedding dimensions in my model_kwargs or my model_kwargs_ranges this error still persists. 

```python-traceback
TypeError: ERMLPInteraction.__init__() missing 1 required positional argument: 'embedding_dim'
```

<summary>Traceback</summary>
<details>

```python-traceback
TypeError                                 Traceback (most recent call last)
Cell In[164], line 1
----> 1 pipeline_results = hpo_pipeline(
      2   study_name="RGCN_hpo",
      3   device='cpu', # I am on a mac so currently only runs on cpu, but have tried with cuda in colab as well
      4   n_trials=1,
      5   dataset='nations',
      6   model='RGCN',
      7 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/hpo/hpo.py:876, in hpo_pipeline(dataset, dataset_kwargs, training, testing, validation, evaluation_entity_whitelist, evaluation_relation_whitelist, model, model_kwargs, model_kwargs_ranges, loss, loss_kwargs, loss_kwargs_ranges, regularizer, regularizer_kwargs, regularizer_kwargs_ranges, optimizer, optimizer_kwargs, optimizer_kwargs_ranges, lr_scheduler, lr_scheduler_kwargs, lr_scheduler_kwargs_ranges, training_loop, training_loop_kwargs, negative_sampler, negative_sampler_kwargs, negative_sampler_kwargs_ranges, epochs, training_kwargs, training_kwargs_ranges, stopper, stopper_kwargs, evaluator, evaluator_kwargs, evaluation_kwargs, metric, filter_validation_when_testing, result_tracker, result_tracker_kwargs, device, storage, sampler, sampler_kwargs, pruner, pruner_kwargs, study_name, direction, load_if_exists, n_trials, timeout, gc_after_trial, n_jobs, save_model_directory)
    820 objective = Objective(
    821     # 1. Dataset
    822     dataset=dataset,
   (...)    872     device=device,
    873 )
    875 # Invoke optimization of the objective function.
--> 876 study.optimize(
    877     cast(Callable[[Trial], float], objective),
    878     n_trials=n_trials,
    879     timeout=timeout,
    880     gc_after_trial=gc_after_trial,
    881     n_jobs=n_jobs or 1,
    882     catch=(MemoryError, RuntimeError),
    883 )
    885 return HpoPipelineResult(
    886     study=study,
    887     objective=objective,
    888 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/study.py:490, in Study.optimize(self, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)
    388 def optimize(
    389     self,
    390     func: ObjectiveFuncType,
   (...)    397     show_progress_bar: bool = False,
    398 ) -> None:
    399     """Optimize an objective function.
    400 
    401     Optimization is done by choosing a suitable set of hyperparameter values from a given
   (...)    488             If nested invocation of this method occurs.
    489     """
--> 490     _optimize(
    491         study=self,
    492         func=func,
    493         n_trials=n_trials,
    494         timeout=timeout,
    495         n_jobs=n_jobs,
    496         catch=tuple(catch) if isinstance(catch, Iterable) else (catch,),
    497         callbacks=callbacks,
    498         gc_after_trial=gc_after_trial,
    499         show_progress_bar=show_progress_bar,
    500     )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:67, in _optimize(study, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)
     65 try:
     66     if n_jobs == 1:
---> 67         _optimize_sequential(
     68             study,
     69             func,
     70             n_trials,
     71             timeout,
     72             catch,
     73             callbacks,
     74             gc_after_trial,
     75             reseed_sampler_rng=False,
     76             time_start=None,
     77             progress_bar=progress_bar,
     78         )
     79     else:
     80         if n_jobs == -1:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:164, in _optimize_sequential(study, func, n_trials, timeout, catch, callbacks, gc_after_trial, reseed_sampler_rng, time_start, progress_bar)
    161         break
    163 try:
--> 164     frozen_trial_id = _run_trial(study, func, catch)
    165 finally:
    166     # The following line mitigates memory problems that can be occurred in some
    167     # environments (e.g., services that use computing containers such as GitHub Actions).
    168     # Please refer to the following PR for further details:
    169     # https://github.com/optuna/optuna/pull/325.
    170     if gc_after_trial:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:262, in _run_trial(study, func, catch)
    255         assert False, "Should not reach."
    257 if (
    258     updated_state == TrialState.FAIL
    259     and func_err is not None
    260     and not isinstance(func_err, catch)
    261 ):
--> 262     raise func_err
    263 return trial._trial_id

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:205, in _run_trial(study, func, catch)
    203 with get_heartbeat_thread(trial._trial_id, study._storage):
    204     try:
--> 205         value_or_values = func(trial)
    206     except exceptions.TrialPruned as e:
    207         # TODO(mamu): Handle multi-objective cases.
    208         state = TrialState.PRUNED

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/hpo/hpo.py:267, in Objective.__call__(self, trial)
    264     self._update_stopper_callbacks(_stopper_kwargs, trial, metric=self.metric, result_tracker=result_tracker)
    266 try:
--> 267     result = pipeline(
    268         # 1. Dataset
    269         dataset=self.dataset,
    270         dataset_kwargs=self.dataset_kwargs,
    271         training=self.training,
    272         testing=self.testing,
    273         validation=self.validation,
    274         evaluation_entity_whitelist=self.evaluation_entity_whitelist,
    275         evaluation_relation_whitelist=self.evaluation_relation_whitelist,
    276         # 2. Model
    277         model=self.model,
    278         model_kwargs=_model_kwargs,
    279         # 3. Loss
    280         loss=self.loss,
    281         loss_kwargs=_loss_kwargs,
    282         # 4. Regularizer
    283         regularizer=self.regularizer,
    284         regularizer_kwargs=_regularizer_kwargs,
    285         # 5. Optimizer
    286         optimizer=self.optimizer,
    287         optimizer_kwargs=_optimizer_kwargs,
    288         clear_optimizer=True,
    289         # 5.1 Learning Rate Scheduler
    290         lr_scheduler=self.lr_scheduler,
    291         lr_scheduler_kwargs=_lr_scheduler_kwargs,
    292         # 6. Training Loop
    293         training_loop=self.training_loop,
    294         negative_sampler=self.negative_sampler,
    295         negative_sampler_kwargs=_negative_sampler_kwargs,
    296         # 7. Training
    297         training_loop_kwargs=self.training_loop_kwargs,
    298         training_kwargs=_training_kwargs,
    299         stopper=self.stopper,
    300         stopper_kwargs=_stopper_kwargs,
    301         # 8. Evaluation
    302         evaluator=self.evaluator,
    303         evaluator_kwargs=self.evaluator_kwargs,
    304         evaluation_kwargs=self.evaluation_kwargs,
    305         filter_validation_when_testing=self.filter_validation_when_testing,
    306         # 9. Tracker
    307         result_tracker=result_tracker,
    308         result_tracker_kwargs=None,
    309         # Misc.
    310         use_testing_data=False,  # use validation set during HPO!
    311         device=self.device,
    312     )
    313 except (MemoryError, RuntimeError) as e:
    314     # close run in result tracker
    315     result_tracker.end_run(success=False)

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:1503, 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)
   1490 _result_tracker.start_run(run_name=title)
   1492 training, testing, validation = _handle_dataset(
   1493     _result_tracker=_result_tracker,
   1494     dataset=dataset,
   (...)   1500     evaluation_relation_whitelist=evaluation_relation_whitelist,
   1501 )
-> 1503 model_instance = _handle_model(
   1504     device=device,
   1505     _result_tracker=_result_tracker,
   1506     _random_seed=_random_seed,
   1507     training=training,
   1508     model=model,
   1509     model_kwargs=model_kwargs,
   1510     interaction=interaction,
   1511     interaction_kwargs=interaction_kwargs,
   1512     dimensions=dimensions,
   1513     loss=loss,
   1514     loss_kwargs=loss_kwargs,
   1515     regularizer=regularizer,
   1516     regularizer_kwargs=regularizer_kwargs,
   1517 )
   1519 training_loop_instance = _handle_training_loop(
   1520     _result_tracker=_result_tracker,
   1521     model_instance=model_instance,
   (...)   1530     negative_sampler_kwargs=negative_sampler_kwargs,
   1531 )
   1533 evaluator_instance, evaluation_kwargs = _handle_evaluator(
   1534     _result_tracker=_result_tracker,
   1535     evaluator=evaluator,
   1536     evaluator_kwargs=evaluator_kwargs,
   1537     evaluation_kwargs=evaluation_kwargs,
   1538 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:970, in _handle_model(device, _result_tracker, _random_seed, training, model, model_kwargs, interaction, interaction_kwargs, dimensions, loss, loss_kwargs, regularizer, regularizer_kwargs)
    966     model_instance = cast(Model, model)
    967     # TODO should training be reset?
    968     # TODO should kwargs for loss and regularizer be checked and raised for?
    969 else:
--> 970     model_instance, model_kwargs = _build_model_helper(
    971         model=model,
    972         model_kwargs=model_kwargs,
    973         loss=loss,
    974         loss_kwargs=loss_kwargs,
    975         regularizer=regularizer,
    976         regularizer_kwargs=regularizer_kwargs,
    977         _device=_device,
    978         _random_seed=_random_seed,
    979         training_triples_factory=training,
    980     )
    982 model_instance = model_instance.to(_device)
    984 # Log model parameters

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:837, in _build_model_helper(model, model_kwargs, loss, loss_kwargs, _device, _random_seed, regularizer, regularizer_kwargs, training_triples_factory)
    833     for param_name, param_default in _get_model_defaults(model).items():
    834         model_kwargs.setdefault(param_name, param_default)
    836 return (
--> 837     model_resolver.make(
    838         model,
    839         triples_factory=training_triples_factory,
    840         **model_kwargs,
    841     ),
    842     model_kwargs,
    843 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:243, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    241         if any(text in e.args[0] for text in MISSING_ARGS):
    242             raise UnexpectedKeywordError(cls) from None
--> 243         raise e
    245 # An instance was passed, and it will go through without modification.
    246 return query

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:237, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    235 cls: type[X] = self.lookup(query)
    236 try:
--> 237     return cls(**(pos_kwargs or {}), **kwargs)
    238 except TypeError as e:
    239     if "required keyword-only argument" in e.args[0]:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/models/unimodal/rgcn.py:158, in RGCN.__init__(self, triples_factory, embedding_dim, num_layers, base_entity_initializer, base_entity_initializer_kwargs, relation_representations, relation_initializer, relation_initializer_kwargs, interaction, interaction_kwargs, use_bias, activation, activation_kwargs, edge_dropout, self_loop_dropout, edge_weighting, decomposition, decomposition_kwargs, regularizer, regularizer_kwargs, **kwargs)
     78 def __init__(
     79     self,
     80     *,
   (...)    102     **kwargs,
    103 ):
    104     """
    105     Initialize the model.
    106 
   (...)    156         additional keyword-based parameters passed to :meth:`ERModel.__init__`
    157     """
--> 158     super().__init__(
    159         entity_representations=RGCNRepresentation,
    160         entity_representations_kwargs=dict(
    161             triples_factory=triples_factory,
    162             entity_representations_kwargs=dict(
    163                 shape=embedding_dim,
    164                 initializer=base_entity_initializer,
    165                 initializer_kwargs=base_entity_initializer_kwargs,
    166             ),
    167             num_layers=num_layers,
    168             use_bias=use_bias,
    169             activation=activation,
    170             activation_kwargs=activation_kwargs,
    171             edge_dropout=edge_dropout,
    172             self_loop_dropout=self_loop_dropout,
    173             edge_weighting=edge_weighting,
    174             decomposition=decomposition,
    175             decomposition_kwargs=decomposition_kwargs,
    176             # cf. https://github.com/MichSchli/RelationPrediction/blob/c77b094fe5c17685ed138dae9ae49b304e0d8d89/code/decoders/bilinear_diag.py#L64-L67  # noqa: E501
    177             regularizer=regularizer,
    178             regularizer_kwargs=regularizer_kwargs,
    179         ),
    180         relation_representations=relation_representations,
    181         relation_representations_kwargs=dict(
    182             shape=embedding_dim,
    183             initializer=relation_initializer,
    184             initializer_kwargs=relation_initializer_kwargs,
    185             # cf. https://github.com/MichSchli/RelationPrediction/blob/c77b094fe5c17685ed138dae9ae49b304e0d8d89/code/decoders/bilinear_diag.py#L64-L67  # noqa: E501
    186             regularizer=regularizer,
    187             regularizer_kwargs=regularizer_kwargs,
    188         ),
    189         triples_factory=triples_factory,
    190         interaction=interaction,
    191         interaction_kwargs=interaction_kwargs,
    192         **kwargs,
    193     )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/models/nbase.py:349, in ERModel.__init__(self, triples_factory, interaction, interaction_kwargs, entity_representations, entity_representations_kwargs, relation_representations, relation_representations_kwargs, skip_checks, **kwargs)
    344 # TODO: support "broadcasting" representation regularizers?
    345 # e.g. re-use the same regularizer for everything; or
    346 # pass a dictionary with keys "entity"/"relation";
    347 # values are either a regularizer hint (=the same regularizer for all repr); or a sequence of appropriate length
    348 super().__init__(triples_factory=triples_factory, **kwargs)
--> 349 self.interaction = interaction_resolver.make(interaction, pos_kwargs=interaction_kwargs)
    350 self.entity_representations = self._build_representations(
    351     triples_factory=triples_factory,
    352     representations=entity_representations,
   (...)    355     skip_checks=skip_checks,
    356 )
    357 self.relation_representations = self._build_representations(
    358     triples_factory=triples_factory,
    359     representations=relation_representations,
   (...)    362     skip_checks=skip_checks,
    363 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:243, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    241         if any(text in e.args[0] for text in MISSING_ARGS):
    242             raise UnexpectedKeywordError(cls) from None
--> 243         raise e
    245 # An instance was passed, and it will go through without modification.
    246 return query

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:237, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    235 cls: type[X] = self.lookup(query)
    236 try:
--> 237     return cls(**(pos_kwargs or {}), **kwargs)
    238 except TypeError as e:
    239     if "required keyword-only argument" in e.args[0]:

TypeError: ERMLPInteraction.__init__() missing 1 required positional argument: 'embedding_dim'
```
</details>


### How to reproduce
```python
from pykeen.hpo import hpo_pipeline

pipeline_results = hpo_pipeline(
    study_name="RGCN_hpo",
    device='cpu', # I am on a mac so currently only runs on cpu, but have tried with cuda in colab as well 
    n_trials=1, 
    dataset='nations',
    model='RGCN',
)
```


### Environment

| Key             | Value                    |
|-----------------|--------------------------|
| OS              | posix                    |
| Platform        | Darwin                   |
| Release         | 24.6.0                   |
| Time            | Tue Dec  2 10:13:54 2025 |
| Python          | 3.12.11                  |
| PyKEEN          | 1.11.1                   |
| PyKEEN Hash     | a7cb19dc                 |
| PyKEEN Branch   | feat/link_prediction     |
| PyTorch         | 2.9.1                    |
| CUDA Available? | false                    |
| CUDA Version    | N/A                      |
| cuDNN Version   | N/A                      |

### Additional information

_No response_

### Issue Template Checks

- [x] This is not a feature request (use a different issue template if it is)
- [x] This is not a question (use the [discussions](https://github.com/pykeen/pykeen/discussions/new) forum instead)
- [x] I've read the text explaining why including environment information is important and understand if I omit this information that my issue will be dismissed

@s160677 please go a few steps further - include the entire python code you ran (i.e., if I put this in my repl, will it run?) and the full stack trace

python3.12

!pip install pykeen

```python
from pykeen.datasets import nations
from pykeen.hpo import hpo_pipeline
from pykeen.models import RGCN
from pykeen.nn.modules import ERMLPInteraction

pipeline_results = hpo_pipeline(
  study_name="RGCN_hpo",
  device='cpu', # I am on a mac so currently only runs on cpu, but have tried with cuda in colab as well
  n_trials=1,
  dataset='nations',
  model='RGCN',
)
```

Please let me know if you need more information


---------------------------------------------------------------------------

```python-traceback
TypeError                                 Traceback (most recent call last)
Cell In[164], line 1
----> 1 pipeline_results = hpo_pipeline(
      2   study_name="RGCN_hpo",
      3   device='cpu', # I am on a mac so currently only runs on cpu, but have tried with cuda in colab as well
      4   n_trials=1,
      5   dataset='nations',
      6   model='RGCN',
      7 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/hpo/hpo.py:876, in hpo_pipeline(dataset, dataset_kwargs, training, testing, validation, evaluation_entity_whitelist, evaluation_relation_whitelist, model, model_kwargs, model_kwargs_ranges, loss, loss_kwargs, loss_kwargs_ranges, regularizer, regularizer_kwargs, regularizer_kwargs_ranges, optimizer, optimizer_kwargs, optimizer_kwargs_ranges, lr_scheduler, lr_scheduler_kwargs, lr_scheduler_kwargs_ranges, training_loop, training_loop_kwargs, negative_sampler, negative_sampler_kwargs, negative_sampler_kwargs_ranges, epochs, training_kwargs, training_kwargs_ranges, stopper, stopper_kwargs, evaluator, evaluator_kwargs, evaluation_kwargs, metric, filter_validation_when_testing, result_tracker, result_tracker_kwargs, device, storage, sampler, sampler_kwargs, pruner, pruner_kwargs, study_name, direction, load_if_exists, n_trials, timeout, gc_after_trial, n_jobs, save_model_directory)
    820 objective = Objective(
    821     # 1. Dataset
    822     dataset=dataset,
   (...)    872     device=device,
    873 )
    875 # Invoke optimization of the objective function.
--> 876 study.optimize(
    877     cast(Callable[[Trial], float], objective),
    878     n_trials=n_trials,
    879     timeout=timeout,
    880     gc_after_trial=gc_after_trial,
    881     n_jobs=n_jobs or 1,
    882     catch=(MemoryError, RuntimeError),
    883 )
    885 return HpoPipelineResult(
    886     study=study,
    887     objective=objective,
    888 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/study.py:490, in Study.optimize(self, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)
    388 def optimize(
    389     self,
    390     func: ObjectiveFuncType,
   (...)    397     show_progress_bar: bool = False,
    398 ) -> None:
    399     """Optimize an objective function.
    400 
    401     Optimization is done by choosing a suitable set of hyperparameter values from a given
   (...)    488             If nested invocation of this method occurs.
    489     """
--> 490     _optimize(
    491         study=self,
    492         func=func,
    493         n_trials=n_trials,
    494         timeout=timeout,
    495         n_jobs=n_jobs,
    496         catch=tuple(catch) if isinstance(catch, Iterable) else (catch,),
    497         callbacks=callbacks,
    498         gc_after_trial=gc_after_trial,
    499         show_progress_bar=show_progress_bar,
    500     )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:67, in _optimize(study, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)
     65 try:
     66     if n_jobs == 1:
---> 67         _optimize_sequential(
     68             study,
     69             func,
     70             n_trials,
     71             timeout,
     72             catch,
     73             callbacks,
     74             gc_after_trial,
     75             reseed_sampler_rng=False,
     76             time_start=None,
     77             progress_bar=progress_bar,
     78         )
     79     else:
     80         if n_jobs == -1:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:164, in _optimize_sequential(study, func, n_trials, timeout, catch, callbacks, gc_after_trial, reseed_sampler_rng, time_start, progress_bar)
    161         break
    163 try:
--> 164     frozen_trial_id = _run_trial(study, func, catch)
    165 finally:
    166     # The following line mitigates memory problems that can be occurred in some
    167     # environments (e.g., services that use computing containers such as GitHub Actions).
    168     # Please refer to the following PR for further details:
    169     # https://github.com/optuna/optuna/pull/325.
    170     if gc_after_trial:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:262, in _run_trial(study, func, catch)
    255         assert False, "Should not reach."
    257 if (
    258     updated_state == TrialState.FAIL
    259     and func_err is not None
    260     and not isinstance(func_err, catch)
    261 ):
--> 262     raise func_err
    263 return trial._trial_id

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/optuna/study/_optimize.py:205, in _run_trial(study, func, catch)
    203 with get_heartbeat_thread(trial._trial_id, study._storage):
    204     try:
--> 205         value_or_values = func(trial)
    206     except exceptions.TrialPruned as e:
    207         # TODO(mamu): Handle multi-objective cases.
    208         state = TrialState.PRUNED

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/hpo/hpo.py:267, in Objective.__call__(self, trial)
    264     self._update_stopper_callbacks(_stopper_kwargs, trial, metric=self.metric, result_tracker=result_tracker)
    266 try:
--> 267     result = pipeline(
    268         # 1. Dataset
    269         dataset=self.dataset,
    270         dataset_kwargs=self.dataset_kwargs,
    271         training=self.training,
    272         testing=self.testing,
    273         validation=self.validation,
    274         evaluation_entity_whitelist=self.evaluation_entity_whitelist,
    275         evaluation_relation_whitelist=self.evaluation_relation_whitelist,
    276         # 2. Model
    277         model=self.model,
    278         model_kwargs=_model_kwargs,
    279         # 3. Loss
    280         loss=self.loss,
    281         loss_kwargs=_loss_kwargs,
    282         # 4. Regularizer
    283         regularizer=self.regularizer,
    284         regularizer_kwargs=_regularizer_kwargs,
    285         # 5. Optimizer
    286         optimizer=self.optimizer,
    287         optimizer_kwargs=_optimizer_kwargs,
    288         clear_optimizer=True,
    289         # 5.1 Learning Rate Scheduler
    290         lr_scheduler=self.lr_scheduler,
    291         lr_scheduler_kwargs=_lr_scheduler_kwargs,
    292         # 6. Training Loop
    293         training_loop=self.training_loop,
    294         negative_sampler=self.negative_sampler,
    295         negative_sampler_kwargs=_negative_sampler_kwargs,
    296         # 7. Training
    297         training_loop_kwargs=self.training_loop_kwargs,
    298         training_kwargs=_training_kwargs,
    299         stopper=self.stopper,
    300         stopper_kwargs=_stopper_kwargs,
    301         # 8. Evaluation
    302         evaluator=self.evaluator,
    303         evaluator_kwargs=self.evaluator_kwargs,
    304         evaluation_kwargs=self.evaluation_kwargs,
    305         filter_validation_when_testing=self.filter_validation_when_testing,
    306         # 9. Tracker
    307         result_tracker=result_tracker,
    308         result_tracker_kwargs=None,
    309         # Misc.
    310         use_testing_data=False,  # use validation set during HPO!
    311         device=self.device,
    312     )
    313 except (MemoryError, RuntimeError) as e:
    314     # close run in result tracker
    315     result_tracker.end_run(success=False)

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:1503, 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)
   1490 _result_tracker.start_run(run_name=title)
   1492 training, testing, validation = _handle_dataset(
   1493     _result_tracker=_result_tracker,
   1494     dataset=dataset,
   (...)   1500     evaluation_relation_whitelist=evaluation_relation_whitelist,
   1501 )
-> 1503 model_instance = _handle_model(
   1504     device=device,
   1505     _result_tracker=_result_tracker,
   1506     _random_seed=_random_seed,
   1507     training=training,
   1508     model=model,
   1509     model_kwargs=model_kwargs,
   1510     interaction=interaction,
   1511     interaction_kwargs=interaction_kwargs,
   1512     dimensions=dimensions,
   1513     loss=loss,
   1514     loss_kwargs=loss_kwargs,
   1515     regularizer=regularizer,
   1516     regularizer_kwargs=regularizer_kwargs,
   1517 )
   1519 training_loop_instance = _handle_training_loop(
   1520     _result_tracker=_result_tracker,
   1521     model_instance=model_instance,
   (...)   1530     negative_sampler_kwargs=negative_sampler_kwargs,
   1531 )
   1533 evaluator_instance, evaluation_kwargs = _handle_evaluator(
   1534     _result_tracker=_result_tracker,
   1535     evaluator=evaluator,
   1536     evaluator_kwargs=evaluator_kwargs,
   1537     evaluation_kwargs=evaluation_kwargs,
   1538 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:970, in _handle_model(device, _result_tracker, _random_seed, training, model, model_kwargs, interaction, interaction_kwargs, dimensions, loss, loss_kwargs, regularizer, regularizer_kwargs)
    966     model_instance = cast(Model, model)
    967     # TODO should training be reset?
    968     # TODO should kwargs for loss and regularizer be checked and raised for?
    969 else:
--> 970     model_instance, model_kwargs = _build_model_helper(
    971         model=model,
    972         model_kwargs=model_kwargs,
    973         loss=loss,
    974         loss_kwargs=loss_kwargs,
    975         regularizer=regularizer,
    976         regularizer_kwargs=regularizer_kwargs,
    977         _device=_device,
    978         _random_seed=_random_seed,
    979         training_triples_factory=training,
    980     )
    982 model_instance = model_instance.to(_device)
    984 # Log model parameters

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/pipeline/api.py:837, in _build_model_helper(model, model_kwargs, loss, loss_kwargs, _device, _random_seed, regularizer, regularizer_kwargs, training_triples_factory)
    833     for param_name, param_default in _get_model_defaults(model).items():
    834         model_kwargs.setdefault(param_name, param_default)
    836 return (
--> 837     model_resolver.make(
    838         model,
    839         triples_factory=training_triples_factory,
    840         **model_kwargs,
    841     ),
    842     model_kwargs,
    843 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:243, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    241         if any(text in e.args[0] for text in MISSING_ARGS):
    242             raise UnexpectedKeywordError(cls) from None
--> 243         raise e
    245 # An instance was passed, and it will go through without modification.
    246 return query

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:237, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    235 cls: type[X] = self.lookup(query)
    236 try:
--> 237     return cls(**(pos_kwargs or {}), **kwargs)
    238 except TypeError as e:
    239     if "required keyword-only argument" in e.args[0]:

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/models/unimodal/rgcn.py:158, in RGCN.__init__(self, triples_factory, embedding_dim, num_layers, base_entity_initializer, base_entity_initializer_kwargs, relation_representations, relation_initializer, relation_initializer_kwargs, interaction, interaction_kwargs, use_bias, activation, activation_kwargs, edge_dropout, self_loop_dropout, edge_weighting, decomposition, decomposition_kwargs, regularizer, regularizer_kwargs, **kwargs)
     78 def __init__(
     79     self,
     80     *,
   (...)    102     **kwargs,
    103 ):
    104     """
    105     Initialize the model.
    106 
   (...)    156         additional keyword-based parameters passed to :meth:`ERModel.__init__`
    157     """
--> 158     super().__init__(
    159         entity_representations=RGCNRepresentation,
    160         entity_representations_kwargs=dict(
    161             triples_factory=triples_factory,
    162             entity_representations_kwargs=dict(
    163                 shape=embedding_dim,
    164                 initializer=base_entity_initializer,
    165                 initializer_kwargs=base_entity_initializer_kwargs,
    166             ),
    167             num_layers=num_layers,
    168             use_bias=use_bias,
    169             activation=activation,
    170             activation_kwargs=activation_kwargs,
    171             edge_dropout=edge_dropout,
    172             self_loop_dropout=self_loop_dropout,
    173             edge_weighting=edge_weighting,
    174             decomposition=decomposition,
    175             decomposition_kwargs=decomposition_kwargs,
    176             # cf. https://github.com/MichSchli/RelationPrediction/blob/c77b094fe5c17685ed138dae9ae49b304e0d8d89/code/decoders/bilinear_diag.py#L64-L67  # noqa: E501
    177             regularizer=regularizer,
    178             regularizer_kwargs=regularizer_kwargs,
    179         ),
    180         relation_representations=relation_representations,
    181         relation_representations_kwargs=dict(
    182             shape=embedding_dim,
    183             initializer=relation_initializer,
    184             initializer_kwargs=relation_initializer_kwargs,
    185             # cf. https://github.com/MichSchli/RelationPrediction/blob/c77b094fe5c17685ed138dae9ae49b304e0d8d89/code/decoders/bilinear_diag.py#L64-L67  # noqa: E501
    186             regularizer=regularizer,
    187             regularizer_kwargs=regularizer_kwargs,
    188         ),
    189         triples_factory=triples_factory,
    190         interaction=interaction,
    191         interaction_kwargs=interaction_kwargs,
    192         **kwargs,
    193     )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/pykeen/models/nbase.py:349, in ERModel.__init__(self, triples_factory, interaction, interaction_kwargs, entity_representations, entity_representations_kwargs, relation_representations, relation_representations_kwargs, skip_checks, **kwargs)
    344 # TODO: support "broadcasting" representation regularizers?
    345 # e.g. re-use the same regularizer for everything; or
    346 # pass a dictionary with keys "entity"/"relation";
    347 # values are either a regularizer hint (=the same regularizer for all repr); or a sequence of appropriate length
    348 super().__init__(triples_factory=triples_factory, **kwargs)
--> 349 self.interaction = interaction_resolver.make(interaction, pos_kwargs=interaction_kwargs)
    350 self.entity_representations = self._build_representations(
    351     triples_factory=triples_factory,
    352     representations=entity_representations,
   (...)    355     skip_checks=skip_checks,
    356 )
    357 self.relation_representations = self._build_representations(
    358     triples_factory=triples_factory,
    359     representations=relation_representations,
   (...)    362     skip_checks=skip_checks,
    363 )

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:243, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    241         if any(text in e.args[0] for text in MISSING_ARGS):
    242             raise UnexpectedKeywordError(cls) from None
--> 243         raise e
    245 # An instance was passed, and it will go through without modification.
    246 return query

File ~/Documents/Documents - Sean’s MacBook Pro/ML6/Bitbucket/venv3/lib/python3.12/site-packages/class_resolver/api.py:237, in ClassResolver.make(self, query, pos_kwargs, **kwargs)
    235 cls: type[X] = self.lookup(query)
    236 try:
--> 237     return cls(**(pos_kwargs or {}), **kwargs)
    238 except TypeError as e:
    239     if "required keyword-only argument" in e.args[0]:

TypeError: ERMLPInteraction.__init__() missing 1 required positional argument: 'embedding_dim'
```

Hey.

The issue is that `ERMLPInteraction` has internal parameters whose size depends on the embedding dimension. Thus, the interaction's `embedding_dim` must coincide with the entity representations' dimension.

The short-term fix is to exclude `ERMLP` from the interaction range (like you already discovered). It would make sense to also ensure that the default HPO range does not run into any issues 🙂 

To enable passing ERMLP interaction, we have to check inside the RGCN's `__init__` if access to the embedding dimension is necessary. If so, the `embedding_dim` keyword argument has to be inserted into the `interaction_kwargs`. That does not really sound like a clean solution though, as we would need to maintain for each interaction whether this is forwarded.

Depending on how much effort you want to invest on your side, you could also fallback to directly using optuna and calling into `pipeline` yourself. Their interface is relatively straight-forward: [documentation](https://optuna.readthedocs.io/en/stable/tutorial/10_key_features/001_first.html). This would also give you much more control over how to explore the hyper-parameter space. Here is a very basic example:

```python
import optuna

from pykeen.pipeline import pipeline


def objective(trial: optuna.Trial) -> float:
    embedding_dim = trial.suggest_int(name="embedding_dim", low=32, high=256, step=32)
    interaction = trial.suggest_categorical(name="interaction", choices=["distmult", "ermlp"])
    interaction_kwargs = {"embedding_dim": embedding_dim} if interaction == "ermlp" else None
    result = pipeline(
        dataset="nations",
        model="RGCN",
        model_kwargs={
            "interaction": interaction,
            "interaction_kwargs": interaction_kwargs,
            "embedding_dim": embedding_dim,
        },
    )
    return result.get_metric(key="mrr")


study = optuna.create_study()
study.optimize(objective, n_trials=3)
study.best_trial  # contains the best validation mrr + params
```