Skip to content

Commit 2649221

Browse files
authored
Fix/sequence op (#5264)
* "replace enum with string" * "fix layers"
1 parent bcdedec commit 2649221

File tree

4 files changed

+68
-113
lines changed

4 files changed

+68
-113
lines changed

paddle/operators/sequence_pool_op.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,14 @@ class SequencePoolOpMaker : public framework::OpProtoAndCheckerMaker {
3939
AddOutput("Out",
4040
"(Tensor), output of SequencePoolOp, which does not contain LoD "
4141
"infomation.");
42-
AddAttr<int>(
43-
"strategy",
44-
"(int, default AVERAGE) the pooling strategy of SequencePoolOp.")
45-
.SetDefault(AVERAGE)
46-
.InEnum({AVERAGE, SUM, SQRT, MAX, LAST, FIRST});
42+
AddAttr<std::string>(
43+
"pooltype",
44+
"(int, default AVERAGE) the pooling pooltype of SequencePoolOp.")
45+
.SetDefault("AVERAGE");
4746
AddComment(R"DOC(
4847
SequencePoolOp pools features of all time-steps of each instance.
4948
50-
It supports six pooling strategy:
49+
It supports six pooling pooltype:
5150
- AVERAGE: Out[i] = average_{for each instance in i-th sequence}{X[i]}
5251
- SUM: Out[i] = sum_{for each instance in i-th sequence}{X[i]}
5352
- SQRT: Out[i] = sum_{for each instance in i-th sequence}{X[i]}
@@ -63,7 +62,7 @@ class SequencePoolOpMaker : public framework::OpProtoAndCheckerMaker {
6362
and the value of X = [[1, 3], [2, 4, 6], [5, 1]].
6463
6564
Thus, Out is a [3,1,1] Tensor without LoD infomation.
66-
And for different strategy, the value of Out is as follows:
65+
And for different pooltype, the value of Out is as follows:
6766
6867
- AVERAGE: [2, 4, 3], where 2=(1+3)/2, 4=(2+4+6)/3, 3=(5+1)/2
6968
- SUM: [4, 12, 6], where 4=1+3, 12=2+4+6, 6=5+1

paddle/operators/sequence_pool_op.h

Lines changed: 45 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,13 @@ template <typename T, int MajorType = Eigen::RowMajor,
2929
typename IndexType = Eigen::DenseIndex>
3030
using EigenMatrix = framework::EigenMatrix<T, MajorType, IndexType>;
3131

32-
enum SeqPoolType {
33-
AVERAGE = 0,
34-
SUM = 1,
35-
SQRT = 2, // square_root_n
36-
MAX = 3,
37-
LAST = 4,
38-
FIRST = 5
39-
};
40-
4132
template <typename Place, typename T>
4233
class SequencePoolKernel : public framework::OpKernel<T> {
4334
public:
4435
void Compute(const framework::ExecutionContext& context) const override {
4536
auto* in = context.Input<LoDTensor>("X");
4637
auto* out = context.Output<LoDTensor>("Out");
47-
int strategy = context.Attr<int>("strategy");
38+
std::string pooltype = context.Attr<std::string>("pooltype");
4839

4940
auto dims = in->dims();
5041
auto lod = in->lod();
@@ -71,28 +62,21 @@ class SequencePoolKernel : public framework::OpKernel<T> {
7162
auto in_e = EigenMatrix<T>::From(in_t, framework::make_ddim({h, w}));
7263
auto out_e = EigenVector<T>::Flatten(out_t);
7364

74-
switch (strategy) {
75-
case AVERAGE:
76-
out_e.device(place) = in_e.mean(Eigen::array<int, 1>({{0}}));
77-
break;
78-
case SUM:
79-
out_e.device(place) = in_e.sum(Eigen::array<int, 1>({{0}}));
80-
break;
81-
case SQRT:
82-
out_e.device(place) = in_e.sum(Eigen::array<int, 1>({{0}})) /
83-
std::sqrt(static_cast<T>(h));
84-
break;
85-
case MAX:
86-
out_e.device(place) = in_e.maximum(Eigen::array<int, 1>({{0}}));
87-
break;
88-
case LAST:
89-
out_e.device(place) = in_e.chip(h - 1, 0);
90-
break;
91-
case FIRST:
92-
out_e.device(place) = in_e.chip(0, 0);
93-
break;
94-
default:
95-
PADDLE_THROW("unsupported pooling strategy");
65+
if (pooltype == "AVERAGE") {
66+
out_e.device(place) = in_e.mean(Eigen::array<int, 1>({{0}}));
67+
} else if (pooltype == "SUM") {
68+
out_e.device(place) = in_e.sum(Eigen::array<int, 1>({{0}}));
69+
} else if (pooltype == "SQRT") {
70+
out_e.device(place) = in_e.sum(Eigen::array<int, 1>({{0}})) /
71+
std::sqrt(static_cast<T>(h));
72+
} else if (pooltype == "MAX") {
73+
out_e.device(place) = in_e.maximum(Eigen::array<int, 1>({{0}}));
74+
} else if (pooltype == "LAST") {
75+
out_e.device(place) = in_e.chip(h - 1, 0);
76+
} else if (pooltype == "FIRST") {
77+
out_e.device(place) = in_e.chip(0, 0);
78+
} else {
79+
PADDLE_THROW("unsupported pooling pooltype");
9680
}
9781
}
9882
}
@@ -105,15 +89,15 @@ class SequencePoolGradKernel : public framework::OpKernel<T> {
10589
auto* in = context.Input<LoDTensor>("X");
10690
auto* in_g = context.Output<LoDTensor>(framework::GradVarName("X"));
10791
auto* out_g = context.Input<LoDTensor>(framework::GradVarName("Out"));
108-
int strategy = context.Attr<int>("strategy");
92+
std::string pooltype = context.Attr<std::string>("pooltype");
10993

11094
auto dims = in->dims();
11195
auto lod = in->lod()[0];
11296
int64_t w = in->numel() / dims[0];
11397

11498
in_g->mutable_data<T>(context.GetPlace());
115-
if (strategy == LAST || strategy == FIRST) {
116-
// set X@Grad be zero at first when strategy is LAST/FIRST
99+
if (pooltype == "LAST" || pooltype == "FIRST") {
100+
// set X@Grad be zero at first when pooltype is LAST/FIRST
117101
math::SetConstant<Place, T> functor;
118102
functor(context.device_context(), in_g, 0);
119103
}
@@ -127,41 +111,33 @@ class SequencePoolGradKernel : public framework::OpKernel<T> {
127111
auto out_g_e = EigenMatrix<T>::From(out_g_t, {1, w});
128112
Eigen::DSizes<int, 2> bcast(h, 1);
129113

130-
switch (strategy) {
131-
case AVERAGE:
132-
in_g_e.device(place) = (out_g_e / static_cast<T>(h)).broadcast(bcast);
133-
break;
134-
case SUM:
135-
in_g_e.device(place) = (out_g_e).broadcast(bcast);
136-
break;
137-
case SQRT:
138-
in_g_e.device(place) =
139-
(out_g_e / std::sqrt(static_cast<T>(h))).broadcast(bcast);
140-
break;
141-
case MAX: {
142-
auto in_t =
143-
in->Slice(static_cast<int>(lod[i]), static_cast<int>(lod[i + 1]));
144-
Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
145-
in_t_map(in_t.data<T>(), h, w);
146-
int row_id;
147-
Eigen::array<int, 2> extents{{1, 1}};
148-
for (int col_id = 0; col_id < w; col_id++) {
149-
in_t_map.col(col_id).maxCoeff(&row_id);
150-
Eigen::array<int, 2> in_offsets{{row_id, col_id}};
151-
Eigen::array<int, 2> out_offsets{{0, col_id}};
152-
in_g_e.slice(in_offsets, extents).device(place) =
153-
out_g_e.slice(out_offsets, extents);
154-
}
155-
break;
114+
if (pooltype == "AVERAGE") {
115+
in_g_e.device(place) = (out_g_e / static_cast<T>(h)).broadcast(bcast);
116+
} else if (pooltype == "SUM") {
117+
in_g_e.device(place) = (out_g_e).broadcast(bcast);
118+
} else if (pooltype == "SQRT") {
119+
in_g_e.device(place) =
120+
(out_g_e / std::sqrt(static_cast<T>(h))).broadcast(bcast);
121+
} else if (pooltype == "MAX") {
122+
auto in_t =
123+
in->Slice(static_cast<int>(lod[i]), static_cast<int>(lod[i + 1]));
124+
Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
125+
in_t_map(in_t.data<T>(), h, w);
126+
int row_id;
127+
Eigen::array<int, 2> extents{{1, 1}};
128+
for (int col_id = 0; col_id < w; col_id++) {
129+
in_t_map.col(col_id).maxCoeff(&row_id);
130+
Eigen::array<int, 2> in_offsets{{row_id, col_id}};
131+
Eigen::array<int, 2> out_offsets{{0, col_id}};
132+
in_g_e.slice(in_offsets, extents).device(place) =
133+
out_g_e.slice(out_offsets, extents);
156134
}
157-
case LAST:
158-
in_g_e.chip(h - 1, 0).device(place) = out_g_e;
159-
break;
160-
case FIRST:
161-
in_g_e.chip(0, 0).device(place) = out_g_e;
162-
break;
163-
default:
164-
PADDLE_THROW("unsupported pooling strategy");
135+
} else if (pooltype == "LAST") {
136+
in_g_e.chip(h - 1, 0).device(place) = out_g_e;
137+
} else if (pooltype == "FIRST") {
138+
in_g_e.chip(0, 0).device(place) = out_g_e;
139+
} else {
140+
PADDLE_THROW("unsupported pooling pooltype");
165141
}
166142
}
167143
}

python/paddle/v2/framework/layers.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -351,32 +351,21 @@ def conv2d(input,
351351
return helper.append_activation(pre_act)
352352

353353

354-
def sequence_pool(input, pool_type, program=None, init_program=None):
355-
# FIXME(dzh) : want to unify the argument of python layer
356-
# function. So we ignore some unecessary attributes
357-
358-
ENUM_POOL_TYPE = dict({
359-
"AVERAGE": 0,
360-
"SUM": 1,
361-
"SQRT": 2,
362-
"MAX": 3,
363-
"LAST": 4,
364-
"FIRST": 5
365-
})
354+
def sequence_pool(input, pool_type, **kwargs):
355+
ENUM_POOL_TYPE = set(["MAX", "AVG", "SQRT", "LAST", "FIRST"])
366356
if pool_type.upper() not in ENUM_POOL_TYPE:
367357
raise ValueError("Unknown pool_type: '%s'. It can only be %s.",
368-
str(pool_type), " ".join(ENUM_POOL_TYPE.keys()))
358+
str(pool_type), " ".join(ENUM_POOL_TYPE))
369359

370-
helper = LayerHelper('sequence_pool', **locals())
360+
helper = LayerHelper('sequence_pool', **kwargs)
371361
dtype = helper.input_dtype()
372362
pool_out = helper.create_tmp_variable(dtype)
373363

374-
# FIXME(dzh): strategy
375364
helper.append_op(
376365
type="sequence_pool",
377366
inputs={"X": [input]},
378367
outputs={"Out": [pool_out]},
379-
attrs={"strategy": ENUM_POOL_TYPE[pool_type.upper()]})
368+
attrs={"pooltype": pool_type.upper()})
380369

381370
return pool_out
382371

python/paddle/v2/framework/tests/test_seq_pool.py

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@
33
from op_test import OpTest
44

55

6-
class SeqPoolType(OpTest):
7-
AVERAGE = 0
8-
SUM = 1
9-
SQRT = 2
10-
MAX = 3
11-
LAST = 4
12-
FIRST = 5
13-
14-
156
class TestSeqAvgPool(OpTest):
167
def set_data(self):
178
self.op_type = 'sequence_pool'
@@ -25,7 +16,7 @@ def set_data(self):
2516
return x, lod, out
2617

2718
def compute(self, x, lod, out):
28-
self.attrs = {'strategy': SeqPoolType.AVERAGE}
19+
self.attrs = {'pooltype': "AVERAGE"}
2920
for i in range(4):
3021
sub_x = x[lod[0][i]:lod[0][i + 1], :]
3122
out[i] = sub_x.mean(axis=0)
@@ -54,31 +45,31 @@ def set_data(self):
5445
return x, lod, out
5546

5647
def compute(self, x, lod, out):
57-
self.attrs = {'strategy': SeqPoolType.AVERAGE}
48+
self.attrs = {'pooltype': "AVERAGE"}
5849
for i in range(4):
5950
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
6051
out[i] = np.reshape(sub_x.mean(axis=0), (3, 17))
6152

6253

6354
class TestSeqSumPool(TestSeqAvgPool):
6455
def compute(self, x, lod, out):
65-
self.attrs = {'strategy': SeqPoolType.SUM}
56+
self.attrs = {'pooltype': "SUM"}
6657
for i in range(4):
6758
sub_x = x[lod[0][i]:lod[0][i + 1], :]
6859
out[i] = sub_x.sum(axis=0)
6960

7061

7162
class TestSeqSumPool2D(TestSeqAvgPool2D):
7263
def compute(self, x, lod, out):
73-
self.attrs = {'strategy': SeqPoolType.SUM}
64+
self.attrs = {'pooltype': "SUM"}
7465
for i in range(4):
7566
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
7667
out[i] = np.reshape(sub_x.sum(axis=0), (3, 17))
7768

7869

7970
class TestSeqSqrtPool(TestSeqAvgPool):
8071
def compute(self, x, lod, out):
81-
self.attrs = {'strategy': SeqPoolType.SQRT}
72+
self.attrs = {'pooltype': "SQRT"}
8273
for i in range(4):
8374
sub_x = x[lod[0][i]:lod[0][i + 1], :]
8475
len = lod[0][i + 1] - lod[0][i]
@@ -87,7 +78,7 @@ def compute(self, x, lod, out):
8778

8879
class TestSeqSqrtPool2D(TestSeqAvgPool2D):
8980
def compute(self, x, lod, out):
90-
self.attrs = {'strategy': SeqPoolType.SQRT}
81+
self.attrs = {'pooltype': "SQRT"}
9182
for i in range(4):
9283
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
9384
len = lod[0][i + 1] - lod[0][i]
@@ -99,7 +90,7 @@ def test_check_grad(self):
9990

10091
class TestSeqMaxPool(TestSeqAvgPool):
10192
def compute(self, x, lod, out):
102-
self.attrs = {'strategy': SeqPoolType.MAX}
93+
self.attrs = {'pooltype': "MAX"}
10394
for i in range(4):
10495
sub_x = x[lod[0][i]:lod[0][i + 1], :]
10596
out[i] = np.amax(sub_x, axis=0)
@@ -111,7 +102,7 @@ def test_check_grad(self):
111102

112103
class TestSeqMaxPool2D(TestSeqAvgPool2D):
113104
def compute(self, x, lod, out):
114-
self.attrs = {'strategy': SeqPoolType.MAX}
105+
self.attrs = {'pooltype': "MAX"}
115106
for i in range(4):
116107
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
117108
out[i] = np.reshape(np.amax(sub_x, axis=0), (3, 17))
@@ -123,31 +114,31 @@ def test_check_grad(self):
123114

124115
class TestSeqLastPool(TestSeqAvgPool):
125116
def compute(self, x, lod, out):
126-
self.attrs = {'strategy': SeqPoolType.LAST}
117+
self.attrs = {'pooltype': "LAST"}
127118
for i in range(4):
128119
sub_x = x[lod[0][i]:lod[0][i + 1], :]
129120
out[i] = sub_x[-1, :]
130121

131122

132123
class TestSeqLastPool2D(TestSeqAvgPool2D):
133124
def compute(self, x, lod, out):
134-
self.attrs = {'strategy': SeqPoolType.LAST}
125+
self.attrs = {'pooltype': "LAST"}
135126
for i in range(4):
136127
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
137128
out[i] = np.reshape(sub_x[-1, :], (3, 17))
138129

139130

140131
class TestSeqFirstPool(TestSeqAvgPool):
141132
def compute(self, x, lod, out):
142-
self.attrs = {'strategy': SeqPoolType.FIRST}
133+
self.attrs = {'pooltype': "FIRST"}
143134
for i in range(4):
144135
sub_x = x[lod[0][i]:lod[0][i + 1], :]
145136
out[i] = sub_x[0, :]
146137

147138

148139
class TestSeqFirstPool2D(TestSeqAvgPool2D):
149140
def compute(self, x, lod, out):
150-
self.attrs = {'strategy': SeqPoolType.FIRST}
141+
self.attrs = {'pooltype': "FIRST"}
151142
for i in range(4):
152143
sub_x = np.reshape(x[lod[0][i]:lod[0][i + 1], :], (-1, 3 * 17))
153144
out[i] = np.reshape(sub_x[0, :], (3, 17))

0 commit comments

Comments
 (0)