--- title: BPR keywords: fastai sidebar: home_sidebar summary: "Bayesian Personalized Ranking (BPR)" description: "Bayesian Personalized Ranking (BPR)" nb_path: "nbs/models/tf/bpr.ipynb" ---
{% raw %}
{% endraw %} {% raw %}
{% endraw %} {% raw %}

## `class` `BPR`[source]

> `BPR`(*`args`, **`kwargs`) :: `Model`

`Model` groups layers into an object with training and inference features.

Args: inputs: The input(s) of the model: a `keras.Input` object or list of `keras.Input` objects. outputs: The output(s) of the model. See Functional API example below. name: String, the name of the model.

There are two ways to instantiate a `Model`:

1 - With the "Functional API", where you start from `Input`, you chain layer calls to specify the model's forward pass, and finally you create your model from inputs and outputs:

    import tensorflow as tf

    inputs = tf.keras.Input(shape=(3,))
    x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs)
    outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x)
    model = tf.keras.Model(inputs=inputs, outputs=outputs)

Note: Only dicts, lists, and tuples of input tensors are supported. Nested inputs are not supported (e.g. lists of list or dicts of dict).

A new Functional API model can also be created by using the intermediate tensors. This enables you to quickly extract sub-components of the model.

Example:

    inputs = keras.Input(shape=(None, None, 3))
    processed = keras.layers.RandomCrop(width=32, height=32)(inputs)
    conv = keras.layers.Conv2D(filters=2, kernel_size=3)(processed)
    pooling = keras.layers.GlobalAveragePooling2D()(conv)
    feature = keras.layers.Dense(10)(pooling)

    full_model = keras.Model(inputs, feature)
    backbone = keras.Model(processed, conv)
    activations = keras.Model(conv, feature)

Note that the `backbone` and `activations` models are not created with `keras.Input` objects, but with the tensors that are originated from `keras.Inputs` objects. Under the hood, the layers and weights will be shared across these models, so that user can train the `full_model`, and use `backbone` or `activations` to do feature extraction. The inputs and outputs of the model can be nested structures of tensors as well, and the created models are standard Functional API models that support all the existing APIs.

2 - By subclassing the `Model` class: in that case, you should define your layers in `__init__()` and you should implement the model's forward pass in `call()`.

    import tensorflow as tf

    class MyModel(tf.keras.Model):

      def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)

      def call(self, inputs):
        x = self.dense1(inputs)
        return self.dense2(x)

    model = MyModel()

If you subclass `Model`, you can optionally have a `training` argument (boolean) in `call()`, which you can use to specify a different behavior in training and inference:

    import tensorflow as tf

    class MyModel(tf.keras.Model):

      def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)
        self.dropout = tf.keras.layers.Dropout(0.5)

      def call(self, inputs, training=False):
        x = self.dense1(inputs)
        if training:
          x = self.dropout(x, training=training)
        return self.dense2(x)

    model = MyModel()

Once the model is created, you can config the model with losses and metrics with `model.compile()`, train the model with `model.fit()`, or use the model to do prediction with `model.predict()`.

{% endraw %} {% raw %}
{% endraw %} {% raw %}

    feature_columns = [{'embed_dim': 4, 'feat': 'user_id', 'feat_num': 5},
                       {'embed_dim': 4, 'feat': 'item_id', 'feat_num': 5}]

    model = BPR(feature_columns)

{% endraw %} {% raw %}

    model.summary()

    Model: "model"
    __________________________________________________________________________________________________
     Layer (type)                   Output Shape         Param #     Connected to
    ==================================================================================================
     input_1 (InputLayer)           [(None, 1)]          0           []

     input_2 (InputLayer)           [(None, 1)]          0           []

     input_3 (InputLayer)           [(None, 1)]          0           []

     embedding (Embedding)          (None, 1, 4)         20          ['input_1[0][0]']

     embedding_1 (Embedding)        (None, 1, 4)         20          ['input_2[0][0]',
                                                                      'input_3[0][0]']

     tf.math.multiply (TFOpLambda)  (None, 1, 4)         0           ['embedding[0][0]',
                                                                      'embedding_1[0][0]']

     tf.math.multiply_1 (TFOpLambda  (None, 1, 4)        0           ['embedding[0][0]',
     )                                                                'embedding_1[1][0]']

     tf.math.reduce_sum (TFOpLambda  (None, 1)           0           ['tf.math.multiply[0][0]']
     )

     tf.math.reduce_sum_1 (TFOpLamb  (None, 1)           0           ['tf.math.multiply_1[0][0]']
     da)

     tf.concat (TFOpLambda)         (None, 2)            0           ['tf.math.reduce_sum[0][0]',
                                                                      'tf.math.reduce_sum_1[0][0]']

    ==================================================================================================
    Total params: 40
    Trainable params: 40
    Non-trainable params: 0
    __________________________________________________________________________________________________

{% endraw %}