Skip to content

Commit 881c522

Browse files
authored
Merge pull request #8843 from zhouhanqing/Paddle-ReduceProd
Add product reduction for reduce op.
2 parents 5a159f3 + 9d78971 commit 881c522

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

paddle/fluid/operators/reduce_op.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ class ReduceMinOpMaker : public ReduceOpMaker {
173173
}
174174
};
175175

176+
class ReduceProdOpMaker : public ReduceOpMaker {
177+
public:
178+
ReduceProdOpMaker(OpProto *proto, OpAttrChecker *op_checker)
179+
: ReduceOpMaker(proto, op_checker) {
180+
SetComment("ReduceProd", "production");
181+
AddComment(comment_);
182+
}
183+
};
184+
176185
} // namespace operators
177186
} // namespace paddle
178187

@@ -190,6 +199,9 @@ REGISTER_OP(reduce_max, ops::ReduceOp, ops::ReduceMaxOpMaker, reduce_max_grad,
190199
REGISTER_OP(reduce_min, ops::ReduceOp, ops::ReduceMinOpMaker, reduce_min_grad,
191200
ops::ReduceGradOp);
192201

202+
REGISTER_OP(reduce_prod, ops::ReduceOp, ops::ReduceProdOpMaker,
203+
reduce_prod_grad, ops::ReduceGradOp);
204+
193205
#define REGISTER_REDUCE_CPU_KERNEL(reduce_type, functor, grad_functor) \
194206
REGISTER_OP_CPU_KERNEL(reduce_type, \
195207
ops::ReduceKernel<paddle::platform::CPUDeviceContext, \

paddle/fluid/operators/reduce_op.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ struct MaxOrMinGradFunctor {
9393
}
9494
};
9595

96+
struct ProdFunctor {
97+
template <typename DeviceContext, typename X, typename Y, typename Dim>
98+
void operator()(const DeviceContext& place, X& x, Y& y, const Dim& dim) {
99+
y.device(place) = x.prod(dim);
100+
}
101+
};
102+
103+
struct ProdGradFunctor {
104+
template <typename DeviceContext, typename X, typename Y, typename DX,
105+
typename DY, typename Dim>
106+
void operator()(const DeviceContext& place, X& x, Y& y, DX& dx, DY& dy,
107+
const Dim& dim, int size) {
108+
dx.device(place) = dy.broadcast(dim) * y.broadcast(dim) * x.inverse();
109+
}
110+
};
111+
96112
template <typename DeviceContext, typename T, typename Functor>
97113
class ReduceKernel : public framework::OpKernel<T> {
98114
public:
@@ -254,4 +270,5 @@ class ReduceGradKernel : public framework::OpKernel<T> {
254270
__macro(reduce_sum, SumFunctor, SumGradFunctor); \
255271
__macro(reduce_mean, MeanFunctor, MeanGradFunctor); \
256272
__macro(reduce_max, MaxFunctor, MaxOrMinGradFunctor); \
257-
__macro(reduce_min, MinFunctor, MaxOrMinGradFunctor);
273+
__macro(reduce_min, MinFunctor, MaxOrMinGradFunctor); \
274+
__macro(reduce_prod, ProdFunctor, ProdGradFunctor);

python/paddle/fluid/layers/nn.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
'reduce_mean',
5050
'reduce_max',
5151
'reduce_min',
52+
'reduce_prod',
5253
'sequence_first_step',
5354
'sequence_last_step',
5455
'dropout',
@@ -2184,6 +2185,53 @@ def reduce_min(input, dim=None, keep_dim=False, name=None):
21842185
return out
21852186

21862187

2188+
def reduce_prod(input, dim=None, keep_dim=False, name=None):
2189+
"""
2190+
Computes the product of tensor elements over the given dimension.
2191+
2192+
Args:
2193+
input (Variable): The input variable which is a Tensor or LoDTensor.
2194+
dim (int|None): The dimension along which the product is performed. If
2195+
:attr:`None`, multipy all elements of :attr:`input` and return a
2196+
Tensor variable with a single element, otherwise must be in the
2197+
range :math:`[-rank(input), rank(input))`. If :math:`dim < 0`,
2198+
the dimension to reduce is :math:`rank + dim`.
2199+
keep_dim (bool|False): Whether to reserve the reduced dimension in the
2200+
output Tensor. The result tensor will have one fewer dimension
2201+
than the :attr:`input` unless :attr:`keep_dim` is true.
2202+
name(str|None): A name for this layer(optional). If set None, the
2203+
layer will be named automatically.
2204+
2205+
Returns:
2206+
Variable: The reduced Tensor variable.
2207+
2208+
Examples:
2209+
.. code-block:: python
2210+
2211+
# x is a Tensor variable with following elements:
2212+
# [[0.2, 0.3, 0.5, 0.9]
2213+
# [0.1, 0.2, 0.6, 0.7]]
2214+
# Each example is followed by the correspending output tensor.
2215+
fluid.layers.reduce_prod(x) # [0.0002268]
2216+
fluid.layers.reduce_prod(x, dim=0) # [0.02, 0.06, 0.3, 0.63]
2217+
fluid.layers.reduce_prod(x, dim=-1) # [0.027, 0.0084]
2218+
fluid.layers.reduce_prod(x, dim=1,
2219+
keep_dim=True) # [[0.027], [0.0084]]
2220+
"""
2221+
helper = LayerHelper('reduce_prod', **locals())
2222+
out = helper.create_tmp_variable(dtype=helper.input_dtype())
2223+
helper.append_op(
2224+
type='reduce_prod',
2225+
inputs={'X': input},
2226+
outputs={'Out': out},
2227+
attrs={
2228+
'dim': dim if dim != None else 0,
2229+
'keep_dim': keep_dim,
2230+
'reduce_all': True if dim == None else False
2231+
})
2232+
return out
2233+
2234+
21872235
def split(input, num_or_sections, dim=-1, name=None):
21882236
"""
21892237
Split the input tensor into multiple sub-tensors.

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ def test_check_output(self):
7070
self.check_output()
7171

7272

73+
class TestProdOp(OpTest):
74+
def setUp(self):
75+
self.op_type = "reduce_prod"
76+
self.inputs = {'X': np.random.random((5, 6, 10)).astype("float64")}
77+
self.outputs = {'Out': self.inputs['X'].prod(axis=0)}
78+
79+
def test_check_output(self):
80+
self.check_output()
81+
82+
def test_check_grad(self):
83+
self.check_grad(['X'], 'Out')
84+
85+
7386
class TestKeepDimReduce(OpTest):
7487
def setUp(self):
7588
self.op_type = "reduce_sum"

0 commit comments

Comments
 (0)