Skip to content

Commit e7acf32

Browse files
authored
Merge pull request #7525 from guoshengCS/add-python-glu
Add python wrapper for GLU.
2 parents 0237b7e + ef12971 commit e7acf32

File tree

6 files changed

+118
-10
lines changed

6 files changed

+118
-10
lines changed

doc/api/v2/fluid/layers.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,12 @@ reduce_min
358358
.. autofunction:: paddle.v2.fluid.layers.reduce_min
359359
:noindex:
360360

361+
362+
split
363+
-----
364+
.. autofunction:: paddle.v2.fluid.layers.split
365+
:noindex:
366+
361367
logsigmoid
362368
----------
363369
.. autofunction:: paddle.v2.fluid.layers.logsigmoid

doc/api/v2/fluid/nets.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ sequence_conv_pool
2020
:noindex:
2121

2222

23+
glu
24+
---
25+
.. autofunction:: paddle.v2.fluid.nets.glu
26+
:noindex:
27+

paddle/operators/split_op.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ class SplitOp : public framework::OperatorWithKernel {
6060
}
6161
}
6262
ctx->SetOutputsDim("Out", outs_dims);
63+
if (axis != 0) {
64+
// Only pass LoD when not spliting along the first dim.
65+
for (size_t i = 0; i < outs_number; ++i) {
66+
ctx->ShareLoD("X", "Out", 0, i);
67+
}
68+
}
6369
}
6470
};
6571

python/paddle/v2/fluid/layers/nn.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
'sequence_first_step',
3737
'sequence_last_step',
3838
'dropout',
39+
'split',
3940
]
4041

4142

@@ -1525,3 +1526,61 @@ def reduce_min(input, dim=None, keep_dim=False):
15251526
'reduce_all': True if dim == None else False
15261527
})
15271528
return out
1529+
1530+
1531+
def split(input, num_or_sections, dim=-1):
1532+
"""
1533+
Splits the tensor into multiple sub-tensors.
1534+
1535+
Args:
1536+
input (Variable): The input variable which is a Tensor or LoDTensor.
1537+
num_or_sections (int|list): If :attr:`num_or_sections` is an integer,
1538+
then the integer indicates the number of equal sized sub-tensors
1539+
that the tensor will be divided into. If :attr:`num_or_sections`
1540+
is a list of integers, the length of list indicates the number of
1541+
sub-tensors and the integers indicate the sizes of sub-tensors'
1542+
:attr:`dim` dimension orderly.
1543+
dim (int): The dimension along which to split. If :math:`dim < 0`, the
1544+
dimension to split along is :math:`rank(input) + dim`.
1545+
1546+
Returns:
1547+
List: The list of segmented tensor variables.
1548+
1549+
Examples:
1550+
.. code-block:: python
1551+
1552+
# x is a Tensor variable with shape [3, 9, 5]:
1553+
x0, x1, x2 = fluid.layers.split(x, num_or_sections=3, dim=1)
1554+
x0.shape # [3, 3, 5]
1555+
x1.shape # [3, 3, 5]
1556+
x2.shape # [3, 3, 5]
1557+
x0, x1, x2 = fluid.layers.split(x, num_or_sections=[2, 3, 4], dim=1)
1558+
x0.shape # [3, 2, 5]
1559+
x1.shape # [3, 3, 5]
1560+
x2.shape # [3, 4, 5]
1561+
"""
1562+
helper = LayerHelper('split', **locals())
1563+
input_shape = input.shape
1564+
dim = (len(input_shape) + dim) if dim < 0 else dim
1565+
if isinstance(num_or_sections, int):
1566+
assert num_or_sections > 1, 'num_or_sections must be more than 1.'
1567+
num = num_or_sections
1568+
else:
1569+
assert len(num_or_sections) < input_shape[
1570+
dim], 'len(num_or_sections) must not be more than input.shape[dim].'
1571+
num = len(num_or_sections)
1572+
outs = [
1573+
helper.create_tmp_variable(dtype=helper.input_dtype())
1574+
for i in range(num)
1575+
]
1576+
helper.append_op(
1577+
type='split',
1578+
inputs={'X': input},
1579+
outputs={'Out': outs},
1580+
attrs={
1581+
'num': num_or_sections if isinstance(num_or_sections, int) else 0,
1582+
'sections': num_or_sections
1583+
if isinstance(num_or_sections, list) else [],
1584+
'axis': dim
1585+
})
1586+
return outs

python/paddle/v2/fluid/nets.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
__all__ = [
44
"simple_img_conv_pool",
55
"sequence_conv_pool",
6+
"glu",
67
]
78

89

@@ -101,3 +102,36 @@ def sequence_conv_pool(input,
101102

102103
pool_out = layers.sequence_pool(input=conv_out, pool_type=pool_type)
103104
return pool_out
105+
106+
107+
def glu(input, dim=-1):
108+
"""
109+
The gated linear unit composed by split and elementwise multiplication.
110+
Specifically, Split the input into two equal sized parts :math:`a` and
111+
:math:`b` along the given dimension and then compute as following:
112+
113+
.. math::
114+
115+
{GLU}(a, b)= a \otimes \sigma(b)
116+
117+
Refer to `Language Modeling with Gated Convolutional Networks
118+
<https://arxiv.org/pdf/1612.08083.pdf>`_.
119+
120+
Args:
121+
input (Variable): The input variable which is a Tensor or LoDTensor.
122+
dim (int): The dimension along which to split. If :math:`dim < 0`, the
123+
dimension to split along is :math:`rank(input) + dim`.
124+
125+
Returns:
126+
Variable: The Tensor variable with half the size of input.
127+
128+
Examples:
129+
.. code-block:: python
130+
131+
# x is a Tensor variable with shape [3, 6, 9]
132+
fluid.nets.glu(input=x, dim=1) # shape of output: [3, 3, 9]
133+
"""
134+
135+
a, b = layers.split(input, num_or_sections=2, dim=dim)
136+
out = layers.elementwise_mul(x=a, y=b)
137+
return out

python/paddle/v2/fluid/tests/test_reorder_lod_tensor.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
class TestReorderLoDTensor(unittest.TestCase):
88
num_seq = 5
9-
# [name, dim, lod_level] pair indicating data info of source and target
10-
data_desc = (['input', 9, 0], ['ref', 5, 1])
9+
# [name, shape, lod_level] pair indicating data info of source and target
10+
data_desc = (['input', [9], 0], ['ref', [5], 1])
1111

1212
@classmethod
1313
def setUpClass(cls):
@@ -16,10 +16,10 @@ def setUpClass(cls):
1616
@classmethod
1717
def set_program(cls):
1818
dat = fluid.layers.data(
19-
name=cls.data_desc[0][0], shape=[cls.data_desc[0][1]])
19+
name=cls.data_desc[0][0], shape=cls.data_desc[0][1])
2020
dat.stop_gradient = False
2121
rank_dat = fluid.layers.data(
22-
name=cls.data_desc[1][0], shape=[cls.data_desc[1][1]])
22+
name=cls.data_desc[1][0], shape=cls.data_desc[1][1])
2323
table = fluid.layers.lod_rank_table(rank_dat)
2424
new_dat = fluid.layers.reorder_lod_tensor_by_rank(
2525
x=dat, rank_table=table)
@@ -49,7 +49,7 @@ def set_data(self):
4949
self.data = {}
5050
for desc in self.data_desc:
5151
data_name = desc[0]
52-
data_dim = desc[1]
52+
data_shape = desc[1]
5353
data_lod_level = desc[2]
5454
data_lod = []
5555
for i in range(data_lod_level):
@@ -59,9 +59,9 @@ def set_data(self):
5959
size=self.num_seq if i == 0 else lod_level_i[-1])
6060
lod_level_i = [0] + numpy.cumsum(lod_level_i).tolist()
6161
data_lod.append(lod_level_i)
62-
data_value = numpy.random.random(size=[
63-
data_lod[-1][-1] if data_lod else self.num_seq, data_dim
64-
]).astype('float32')
62+
data_value = numpy.random.random(
63+
size=[data_lod[-1][-1] if data_lod else self.num_seq
64+
] + data_shape).astype('float32')
6565
self.data[data_name] = (data_value, data_lod)
6666

6767
def set_inputs(self, place):
@@ -163,8 +163,6 @@ def test_reorder_tensor(self):
163163
numpy.allclose(
164164
numpy.array(actual_grad), expect_grad, atol=0.001))
165165
self.assertEqual(expect_grad_lod, actual_grad.lod())
166-
global outputs_from_tensor_implicit_lod
167-
outputs_from_tensor_implicit_lod = self.actual_outputs
168166

169167
# compare outputs between LodTensors with explicit and implicit lod
170168
# use the same data but set the input lod explicitly

0 commit comments

Comments
 (0)