Skip to content

Commit 4e377f8

Browse files
committed
Merge branch 'develop' of https://github.com/PaddlePaddle/Paddle into enhance_for_tensorrt_infer
2 parents bd64979 + e658762 commit 4e377f8

File tree

4 files changed

+206
-32
lines changed

4 files changed

+206
-32
lines changed

doc/fluid/api/layers.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,3 +1768,11 @@ reverse
17681768
.. autofunction:: paddle.fluid.layers.reverse
17691769
:noindex:
17701770

1771+
.. _api_fluid_layers_rank_loss:
1772+
1773+
rank_loss
1774+
-------
1775+
1776+
.. autofunction:: paddle.fluid.layers.rank_loss
1777+
:noindex:
1778+

python/paddle/fluid/layers/io.py

Lines changed: 104 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -456,52 +456,124 @@ def py_reader(capacity,
456456
name=None,
457457
use_double_buffer=True):
458458
"""
459-
Create a reader and blocking queue for data feeding in Python
459+
Create a Python reader for data feeding in Python
460460
461-
This layer returns a Reader Variable and a BlockingQueue.
462-
The BlockingQueue provides `push()` method to push a `LoDTensorArray`
463-
object into the queue in Python side. In C++ side, the Reader
464-
Variable would invoke `pop()` method of the queue to retrieve the
465-
feeding data. The process of feeding data in Python side and fetching
466-
data in C++ side can run in parallel. The BlockingQueue should be closed
467-
using `close()` method when unused.
461+
This layer returns a Reader Variable.
462+
The Reader provides :code:`decorate_paddle_reader()` and
463+
:code:`decorate_tensor_provider()` to set a Python generator as the data
464+
source in Python side. When :code:`Executor::Run()` is invoked in C++
465+
side, the data from the generator would be read automatically. Unlike
466+
:code:`DataFeeder.feed()`, the data reading process and
467+
:code:`Executor::Run()` process can run in parallel using
468+
:code:`py_reader`. The :code:`start()` method of the Reader should be
469+
called when each pass begins, while the :code:`reset()` method should be
470+
called when the pass ends and :code:`fluid.core.EOFException` raises.
471+
Note that :code:`Program.clone()` method cannot clone :code:`py_reader`.
468472
469473
Args:
470-
use_double_buffer(bool): Whether use double buffer or not.
471-
capacity(int): The maximum capacity of the BlockingQueue.
474+
capacity(int): The buffer capacity maintained by :code:`py_reader`.
472475
shapes(list|tuple): List of tuples which declaring data shapes.
473476
dtypes(list|tuple): List of strs which declaring data type.
474477
lod_levels(list|tuple): List of ints which declaring data lod_level.
475478
name(basestring): The prefix Python queue name and Reader name. None will
476479
be generated automatically.
480+
use_double_buffer(bool): Whether use double buffer or not.
477481
478482
Returns:
479-
tuple(Variable, BlockingQueue):
480-
A Reader Variable from which we can get feeding data.
481-
482-
A BlockingQueue object for data feeding.
483+
Variable: A Reader from which we can get feeding data.
483484
484485
Examples:
485486
486-
.. code-block:: python
487+
1. The basic usage of :code:`py_reader` is as follows:
487488
488-
reader, queue = fluid.layers.py_reader(
489-
capacity=10,
490-
shapes=[[-1,3,224,224], [-1,1]],
491-
dtypes=['float32', 'int64'])
492-
# Via the reader, we can use 'read_file' layer to get data:
493-
image, label = fluid.layers.read_file(reader)
494-
495-
# Via the blocking queue, we can feed data using threads
496-
def feed_data(queue, feed_images, feed_labels):
497-
for feed_image, feed_label in zip(feed_images, feed_labels):
498-
data = core.LoDTensorArray()
499-
data.append(feed_image)
500-
data.append(feed_label)
501-
queue.push(data)
502-
503-
thread = threading.Thread(target=feed_data, args=(queue, feed_images, feed_labels))
504-
thread.start()
489+
>>> import paddle.v2
490+
>>> import paddle.fluid as fluid
491+
>>> import paddle.dataset.mnist as mnist
492+
>>>
493+
>>> reader = fluid.layers.py_reader(capacity=64,
494+
>>> shapes=[(-1,3,224,224), (-1,1)],
495+
>>> dtypes=['float32', 'int64'])
496+
>>> reader.decorate_paddle_reader(
497+
>>> paddle.v2.reader.shuffle(paddle.batch(mnist.train())
498+
>>>
499+
>>> img, label = fluid.layers.read_file(reader)
500+
>>> loss = network(img, label) # some network definition
501+
>>>
502+
>>> fluid.Executor(fluid.CUDAPlace(0)).run(fluid.default_startup_program())
503+
>>>
504+
>>> exe = fluid.ParallelExecutor(use_cuda=True, loss_name=loss.name)
505+
>>> for epoch_id in range(10):
506+
>>> reader.start()
507+
>>> try:
508+
>>> while True:
509+
>>> exe.run(fetch_list=[loss.name])
510+
>>> except fluid.core.EOFException:
511+
>>> reader.reset()
512+
513+
2. When training and testing are both performed, two different
514+
:code:`py_reader` should be created with different names, e.g.:
515+
516+
>>> import paddle.v2
517+
>>> import paddle.fluid as fluid
518+
>>> import paddle.dataset.mnist as mnist
519+
>>>
520+
>>> def network(reader):
521+
>>> img, label = fluid.layers.read_file(reader)
522+
>>> # Here, we omitted the network definition
523+
>>> return loss
524+
>>>
525+
>>> train_reader = fluid.layers.py_reader(capacity=64,
526+
>>> shapes=[(-1,3,224,224), (-1,1)],
527+
>>> dtypes=['float32', 'int64'],
528+
>>> name='train_reader')
529+
>>> train_reader.decorate_paddle_reader(
530+
>>> paddle.v2.reader.shuffle(paddle.batch(mnist.train())
531+
>>>
532+
>>> test_reader = fluid.layers.py_reader(capacity=32,
533+
>>> shapes=[(-1,3,224,224), (-1,1)],
534+
>>> dtypes=['float32', 'int64'],
535+
>>> name='test_reader')
536+
>>> test_reader.decorate_paddle_reader(paddle.batch(mnist.test(), 512))
537+
>>>
538+
>>> # Create train_main_prog and train_startup_prog
539+
>>> train_main_prog = fluid.Program()
540+
>>> train_startup_prog = fluid.Program()
541+
>>> with fluid.program_guard(train_main_prog, train_startup_prog):
542+
>>> # Use fluid.unique_name.guard() to share parameters with test program
543+
>>> with fluid.unique_name.guard():
544+
>>> train_loss = network(train_reader) # some network definition
545+
>>> adam = fluid.optimizer.Adam(learning_rate=0.01)
546+
>>> adam.minimize(loss)
547+
>>>
548+
>>> # Create test_main_prog and test_startup_prog
549+
>>> test_main_prog = fluid.Program()
550+
>>> test_startup_prog = fluid.Program()
551+
>>> with fluid.program_guard(test_main_prog, test_startup_prog):
552+
>>> # Use fluid.unique_name.guard() to share parameters with train program
553+
>>> with fluid.unique_name.guard():
554+
>>> test_loss = network(test_reader)
555+
>>>
556+
>>> fluid.Executor(fluid.CUDAPlace(0)).run(train_startup_prog)
557+
>>> fluid.Executor(fluid.CUDAPlace(0)).run(test_startup_prog)
558+
>>>
559+
>>> train_exe = fluid.ParallelExecutor(use_cuda=True,
560+
>>> loss_name=train_loss.name, main_program=train_main_prog)
561+
>>> test_exe = fluid.ParallelExecutor(use_cuda=True,
562+
>>> loss_name=test_loss.name, main_program=test_main_prog)
563+
>>> for epoch_id in range(10):
564+
>>> train_reader.start()
565+
>>> try:
566+
>>> while True:
567+
>>> train_exe.run(fetch_list=[train_loss.name])
568+
>>> except fluid.core.EOFException:
569+
>>> train_reader.reset()
570+
>>>
571+
>>> test_reader.start()
572+
>>> try:
573+
>>> while True:
574+
>>> test_exe.run(fetch_list=[test_loss.name])
575+
>>> except fluid.core.EOFException:
576+
>>> test_reader.reset()
505577
"""
506578
dtypes = [convert_np_dtype_to_dtype_(dt) for dt in dtypes]
507579
shape_concat = []

python/paddle/fluid/layers/nn.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
'relu',
111111
'log',
112112
'crop',
113+
'rank_loss',
113114
]
114115

115116

@@ -5282,3 +5283,74 @@ def crop(x, shape=None, offsets=None, name=None):
52825283
outputs={'Out': out},
52835284
attrs=None if len(attrs) == 0 else attrs)
52845285
return out
5286+
5287+
5288+
def rank_loss(label, left, right, name=None):
5289+
"""
5290+
**Rank loss layer for RankNet**
5291+
5292+
RankNet(http://icml.cc/2015/wp-content/uploads/2015/06/icml_ranking.pdf)
5293+
is a pairwise ranking model with a training sample consisting of a pair
5294+
of documents, A and B. Label P indicates whether A is ranked higher than B
5295+
or not:
5296+
5297+
P = {0, 1} or {0, 0.5, 1}, where 0.5 means that there is no information
5298+
about the rank of the input pair.
5299+
5300+
Rank loss layer takes three inputs: left (o_i), right (o_j) and
5301+
label (P_{i,j}). The inputs respectively represent RankNet's output scores
5302+
for documents A and B and the value of label P. The following equation
5303+
computes rank loss C_{i,j} from the inputs:
5304+
5305+
$$
5306+
C_{i,j} = -\tilde{P_{ij}} * o_{i,j} + \log(1 + e^{o_{i,j}}) \\
5307+
o_{i,j} = o_i - o_j \\
5308+
\tilde{P_{i,j}} = \left \{0, 0.5, 1 \right \} \ or \ \left \{0, 1 \right \}
5309+
$$
5310+
5311+
Rank loss layer takes batch inputs with size batch_size (batch_size >= 1).
5312+
5313+
Args:
5314+
label (Variable): Indicats whether A ranked higher than B or not.
5315+
left (Variable): RankNet's output score for doc A.
5316+
right (Variable): RankNet's output score for doc B.
5317+
name(str|None): A name for this layer(optional). If set None, the layer
5318+
will be named automatically.
5319+
5320+
Returns:
5321+
list: The value of rank loss.
5322+
5323+
Raises:
5324+
ValueError: Any of label, left, and right is not a variable.
5325+
5326+
Examples:
5327+
5328+
.. code-block:: python
5329+
5330+
label = fluid.layers.data(name="label", shape=[4, 1], dtype="float32")
5331+
left = fluid.layers.data(name="left", shape=[4, 1], dtype="float32")
5332+
right = fluid.layers.data(name="right", shape=[4, 1], dtype="float32")
5333+
out = fluid.layers.rank_loss(label, left, right)
5334+
5335+
5336+
"""
5337+
helper = LayerHelper('rank_loss', **locals())
5338+
5339+
if not (isinstance(label, Variable)):
5340+
raise ValueError("The label should be a Variable")
5341+
5342+
if not (isinstance(left, Variable)):
5343+
raise ValueError("The left should be a Variable")
5344+
5345+
if not (isinstance(right, Variable)):
5346+
raise ValueError("The right should be a Variable")
5347+
5348+
out = helper.create_tmp_variable("float32")
5349+
5350+
helper.append_op(
5351+
type='rank_loss',
5352+
inputs={"Label": label,
5353+
"Left": left,
5354+
"Right": right},
5355+
outputs={'Out': out})
5356+
return out

python/paddle/fluid/tests/unittests/test_layers.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,28 @@ def test_argsort(self):
443443
self.assertIsNotNone(ids)
444444
print(str(program))
445445

446+
def test_rank_loss(self):
447+
program = Program()
448+
with program_guard(program):
449+
label = layers.data(
450+
name='label',
451+
append_batch_size=False,
452+
shape=[16, 1],
453+
dtype="float32")
454+
left = layers.data(
455+
name='left',
456+
append_batch_size=False,
457+
shape=[16, 1],
458+
dtype="float32")
459+
right = layers.data(
460+
name='right',
461+
append_batch_size=False,
462+
shape=[16, 1],
463+
dtype="float32")
464+
out = layers.rank_loss(label, left, right, name="rank_loss")
465+
self.assertIsNotNone(out)
466+
print(str(program))
467+
446468

447469
if __name__ == '__main__':
448470
unittest.main()

0 commit comments

Comments
 (0)