Repository: pykeen/pykeen
Issue: Add TripleRE Model
GitHub labels: 💃 Model

💎 New Component

### Publication Link

https://vixra.org/pdf/2112.0095v1.pdf

### Reference Implementation

_No response_

### Additional Implementations

_No response_

### Relevance

In our company, we are facing CPU memory limitations, and is not suitable for using Node Piece. I wonder why there is no implementation of TripleRE Model but only TripleRE Module and Interaction.

### Additional Context

It seems easy to add ```triple_re.py```  file in [unimodal](https://github.com/pykeen/pykeen/tree/master/src/pykeen/models/unimodal)
```python
# -*- coding: utf-8 -*-

"""Implementation of TripleRE."""

from typing import Any, ClassVar, Mapping, Optional

import torch
import numpy as np
from torch.nn import functional
from torch.nn.init import uniform_

from ..nbase import ERModel
from ...constants import DEFAULT_EMBEDDING_HPO_EMBEDDING_DIM_RANGE
from ...nn.modules import TripleREInteraction
from ...typing import Hint, Initializer, Normalizer

__all__ = [
    "TripleRE",
]


class TripleRE(ERModel):

    def __init__(
        self,
        embedding_dim: int = 200,
        p: int = 1,
        u: float = 0.125,
        power_norm: bool = False,
        entity_initializer: Hint[Initializer] = uniform_,
        entity_initializer_kwargs: Optional[Mapping[str, Any]] = None,
        entity_normalizer: Hint[Normalizer] = functional.normalize,
        entity_normalizer_kwargs: Optional[Mapping[str, Any]] = None,
        relation_initializer: Hint[Initializer] = uniform_,
        relation_initializer_kwargs: Optional[Mapping[str, Any]] = None,
        **kwargs,
    ) -> None:
        r"""Initialize TripleRE via the :class:`pykeen.nn.modules.TripleREInteraction` interaction.

        :param embedding_dim: The entity embedding dimension $d$.
        :param p: The $l_p$ norm.
        :param u: The param for TripleRE V2
        :param power_norm: Should the power norm be used?
        :param entity_initializer: Entity initializer function. Defaults to :func:`torch.nn.init.uniform_`
        :param entity_initializer_kwargs: Keyword arguments to be used when calling the entity initializer
        :param entity_normalizer: Entity normalizer function. Defaults to :func:`torch.nn.functional.normalize`
        :param entity_normalizer_kwargs: Keyword arguments to be used when calling the entity normalizer
        :param relation_initializer: Relation initializer function. Defaults to :func:`torch.nn.init.uniform_`
        :param relation_initializer_kwargs: Keyword arguments to be used when calling the relation initializer
        :param kwargs: Remaining keyword arguments passed through to :class:`pykeen.models.ERModel`.
        """
        entity_normalizer_kwargs = _resolve_kwargs(
            kwargs=entity_normalizer_kwargs,
            default_kwargs=self.default_entity_normalizer_kwargs,
        )

        entity_initializer_kwargs = self._update_embedding_init_with_default(
            entity_initializer_kwargs,
            embedding_dim=embedding_dim,
        )
        relation_initializer_kwargs = self._update_embedding_init_with_default(
            relation_initializer_kwargs,
            embedding_dim=3 * embedding_dim,
        )
        super().__init__(
            interaction=TripleREInteraction,
            interaction_kwargs=dict(p=p, power_norm=power_norm,u=u),
            entity_representations_kwargs=dict(
                shape=embedding_dim,
                initializer=entity_initializer,
                initializer_kwargs=entity_initializer_kwargs,
                normalizer=entity_normalizer,
                normalizer_kwargs=entity_normalizer_kwargs,
            ),
            relation_representations_kwargs=[
                dict(
                    shape=embedding_dim,
                    initializer=relation_initializer,
                    initializer_kwargs=relation_initializer_kwargs,
                ),
                dict(
                    shape=embedding_dim,
                    initializer=relation_initializer,
                    initializer_kwargs=relation_initializer_kwargs,
                ),
                dict(
                    shape=embedding_dim,
                    initializer=relation_initializer,
                    initializer_kwargs=relation_initializer_kwargs,
                ),
            ],
            **kwargs,
        )

    @staticmethod
    def _update_embedding_init_with_default(
        init_kwargs: Optional[Mapping[str, Any]],
        embedding_dim: int,
    ) -> Mapping[str, float]:
        """Update kwargs by dimension-based default init range."""
        init_kwargs = dict(init_kwargs or {})
        embedding_range = 14 / embedding_dim
        init_kwargs.setdefault("a", -embedding_range)
        init_kwargs.setdefault("b", embedding_range)
        return init_kwargs


def _resolve_kwargs(kwargs: Optional[Mapping[str, Any]], default_kwargs: Mapping[str, Any]) -> Mapping[str, Any]:
    kwargs = dict(kwargs or {})
    for k, v in default_kwargs.items():
        kwargs.setdefault(k, v)
    return kwargs
```

cf. https://github.com/pykeen/pykeen/pull/715

Sorry, It must be model, not module

Hi @jasper881108, can you give more context about the company where you work and how you're using PyKEEN?

I'm working at Cathay Financial Holdings, we are trying to use CFKG ( Collaborate Filtering through Knowledge Graph ) to recommend fund. We have used Tensorflow to build an TransE prototype and it works well on fund recommendation. We hope that pykeen can boost our current performance