From a4c06083afd1ae491f7d55ea883ad90c329b4aac Mon Sep 17 00:00:00 2001 From: baiyf Date: Mon, 23 Jul 2018 21:00:27 +0800 Subject: [PATCH] Expose rank_loss op Python API (#12132) * expose rank_loss python api --- doc/fluid/api/layers.rst | 8 +++ python/paddle/fluid/layers/nn.py | 72 +++++++++++++++++++ .../fluid/tests/unittests/test_layers.py | 22 ++++++ 3 files changed, 102 insertions(+) diff --git a/doc/fluid/api/layers.rst b/doc/fluid/api/layers.rst index d443c49657b..ecbd8191ccf 100644 --- a/doc/fluid/api/layers.rst +++ b/doc/fluid/api/layers.rst @@ -1768,3 +1768,11 @@ reverse .. autofunction:: paddle.fluid.layers.reverse :noindex: +.. _api_fluid_layers_rank_loss: + +rank_loss +------- + +.. autofunction:: paddle.fluid.layers.rank_loss + :noindex: + diff --git a/python/paddle/fluid/layers/nn.py b/python/paddle/fluid/layers/nn.py index 4df806216aa..5d7f1eadd93 100644 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -110,6 +110,7 @@ __all__ = [ 'relu', 'log', 'crop', + 'rank_loss', ] @@ -5282,3 +5283,74 @@ def crop(x, shape=None, offsets=None, name=None): outputs={'Out': out}, attrs=None if len(attrs) == 0 else attrs) return out + + +def rank_loss(label, left, right, name=None): + """ + **Rank loss layer for RankNet** + + RankNet(http://icml.cc/2015/wp-content/uploads/2015/06/icml_ranking.pdf) + is a pairwise ranking model with a training sample consisting of a pair + of documents, A and B. Label P indicates whether A is ranked higher than B + or not: + + P = {0, 1} or {0, 0.5, 1}, where 0.5 means that there is no information + about the rank of the input pair. + + Rank loss layer takes three inputs: left (o_i), right (o_j) and + label (P_{i,j}). The inputs respectively represent RankNet's output scores + for documents A and B and the value of label P. The following equation + computes rank loss C_{i,j} from the inputs: + + $$ + C_{i,j} = -\tilde{P_{ij}} * o_{i,j} + \log(1 + e^{o_{i,j}}) \\ + o_{i,j} = o_i - o_j \\ + \tilde{P_{i,j}} = \left \{0, 0.5, 1 \right \} \ or \ \left \{0, 1 \right \} + $$ + + Rank loss layer takes batch inputs with size batch_size (batch_size >= 1). + + Args: + label (Variable): Indicats whether A ranked higher than B or not. + left (Variable): RankNet's output score for doc A. + right (Variable): RankNet's output score for doc B. + name(str|None): A name for this layer(optional). If set None, the layer + will be named automatically. + + Returns: + list: The value of rank loss. + + Raises: + ValueError: Any of label, left, and right is not a variable. + + Examples: + + .. code-block:: python + + label = fluid.layers.data(name="label", shape=[4, 1], dtype="float32") + left = fluid.layers.data(name="left", shape=[4, 1], dtype="float32") + right = fluid.layers.data(name="right", shape=[4, 1], dtype="float32") + out = fluid.layers.rank_loss(label, left, right) + + + """ + helper = LayerHelper('rank_loss', **locals()) + + if not (isinstance(label, Variable)): + raise ValueError("The label should be a Variable") + + if not (isinstance(left, Variable)): + raise ValueError("The left should be a Variable") + + if not (isinstance(right, Variable)): + raise ValueError("The right should be a Variable") + + out = helper.create_tmp_variable("float32") + + helper.append_op( + type='rank_loss', + inputs={"Label": label, + "Left": left, + "Right": right}, + outputs={'Out': out}) + return out diff --git a/python/paddle/fluid/tests/unittests/test_layers.py b/python/paddle/fluid/tests/unittests/test_layers.py index 6b1f206ea2f..ab2ab24f354 100644 --- a/python/paddle/fluid/tests/unittests/test_layers.py +++ b/python/paddle/fluid/tests/unittests/test_layers.py @@ -443,6 +443,28 @@ class TestBook(unittest.TestCase): self.assertIsNotNone(ids) print(str(program)) + def test_rank_loss(self): + program = Program() + with program_guard(program): + label = layers.data( + name='label', + append_batch_size=False, + shape=[16, 1], + dtype="float32") + left = layers.data( + name='left', + append_batch_size=False, + shape=[16, 1], + dtype="float32") + right = layers.data( + name='right', + append_batch_size=False, + shape=[16, 1], + dtype="float32") + out = layers.rank_loss(label, left, right, name="rank_loss") + self.assertIsNotNone(out) + print(str(program)) + if __name__ == '__main__': unittest.main() -- GitLab