test_seq_pool.py 13.9 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
D
dzhwinter 已提交
2
#
D
dzhwinter 已提交
3 4 5
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
D
dzhwinter 已提交
6
#
D
dzhwinter 已提交
7
#     http://www.apache.org/licenses/LICENSE-2.0
D
dzhwinter 已提交
8
#
D
dzhwinter 已提交
9 10 11 12 13 14
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

15 16
from __future__ import print_function

17 18
import unittest
import numpy as np
19
from op_test import OpTest
T
tensor-tang 已提交
20
from test_reorder_lod_tensor import convert_to_offset
21 22


23
def compute_seqpool_sum(x, offset, out, pad_value=0.0):
24 25 26
    level = len(offset) - 1
    for i in range(len(offset[level]) - 1):
        if offset[level][i] == offset[level][i + 1]:
27 28
            out[i] = pad_value
        else:
29
            sub_x = x[offset[level][i]:offset[level][i + 1], :]
30
            out[i] = sub_x.sum(axis=0)
T
tensor-tang 已提交
31 32


33
def compute_seqpool_avg(x, offset, out, pad_value=0.0):
34 35 36
    level = len(offset) - 1
    for i in range(len(offset[level]) - 1):
        if offset[level][i] == offset[level][i + 1]:
37 38
            out[i] = pad_value
        else:
39
            sub_x = x[offset[level][i]:offset[level][i + 1], :]
40
            out[i] = sub_x.mean(axis=0)
T
tensor-tang 已提交
41

42

43
def compute_seqpool_sqrt(x, offset, out, pad_value=0.0):
44 45 46
    level = len(offset) - 1
    for i in range(len(offset[level]) - 1):
        if offset[level][i] == offset[level][i + 1]:
47 48
            out[i] = pad_value
        else:
49 50
            sub_x = x[offset[level][i]:offset[level][i + 1], :]
            seq_len = offset[level][i + 1] - offset[level][i]
51
            out[i] = sub_x.sum(axis=0) / np.sqrt(seq_len)
T
tensor-tang 已提交
52 53 54


class TestSeqAvgPool(OpTest):
55 56 57
    def set_lod(self):
        return [[11]]

58 59
    def set_data(self):
        self.op_type = 'sequence_pool'
60
        x = np.random.uniform(0.1, 1, [11, 23]).astype('float32')
61
        lod = self.set_lod()
62
        level = len(lod) - 1
63
        self.inputs = {'X': (x, lod)}
T
tensor-tang 已提交
64
        offset = convert_to_offset(lod)
65
        out = np.zeros((len(lod[level]), 23)).astype('float32')
66
        self.outputs = {'Out': out}
67
        return x, offset, out
68

69
    def compute(self, x, offset, out):
70 71
        self.attrs = {"pad_value": 0.0, 'pooltype': "AVERAGE"}
        compute_seqpool_avg(x, offset, out, self.attrs["pad_value"])
72

73
    def setUp(self):
74 75
        x, offset, out = self.set_data()
        self.compute(x, offset, out)
76 77
        if len(offset) > 1:
            self.outputs = {'Out': (out, [self.set_lod()[0]])}
78 79 80 81 82

    def test_check_output(self):
        self.check_output()

    def test_check_grad(self):
83
        # Remove MaxIndex after check_grad is refined.
84 85
        out = self.outputs['Out']
        if isinstance(out, tuple): out = out[0]
86
        self.outputs['MaxIndex'] = \
87
            np.zeros(out.shape).astype('int32')
88 89 90
        self.check_grad(["X"], "Out")


91 92 93 94 95
class TestSeqAvgPoolLen0(TestSeqAvgPool):
    def set_lod(self):
        return [[0, 4, 0, 7, 0]]


96 97 98 99 100
class TestSeqAvgPoolLen0LoDLevel2(TestSeqAvgPool):
    def set_lod(self):
        return [[2, 0, 1, 2], [0, 4, 0, 7, 0]]


D
dzhwinter 已提交
101
class TestSeqSumPool(TestSeqAvgPool):
102
    def compute(self, x, offset, out):
103 104 105 106 107 108 109
        self.attrs = {"pad_value": 0.1, 'pooltype': "SUM"}
        compute_seqpool_sum(x, offset, out, self.attrs["pad_value"])


class TestSeqSumPoolLen0(TestSeqSumPool):
    def set_lod(self):
        return [[0, 4, 0, 7, 0]]
D
dzhwinter 已提交
110 111


112 113 114 115 116
class TestSeqSumPoolLen0LoDLevel2(TestSeqSumPool):
    def set_lod(self):
        return [[2, 0, 1, 2], [0, 4, 0, 7, 0]]


D
dzhwinter 已提交
117
class TestSeqMaxPool(TestSeqAvgPool):
118 119 120
    def set_lod(self):
        return [[13]]

D
dzhwinter 已提交
121 122 123
    def set_data(self):
        self.op_type = 'sequence_pool'
        x = np.random.uniform(0.1, 1, [13, 23]).astype('float32')
124
        lod = self.set_lod()
125
        level = len(lod) - 1
T
tensor-tang 已提交
126
        offset = convert_to_offset(lod)
127 128
        for i in range(len(offset[level]) - 1):
            l = offset[level][i + 1] - offset[level][i]
129
            if l > 0:
130
                x[offset[level][i] + np.random.randint(l), :] += 2.0
D
dzhwinter 已提交
131 132 133

        self.inputs = {'X': (x, lod)}

134
        out = np.zeros((len(lod[level]), 23)).astype('float32')
D
dzhwinter 已提交
135
        self.outputs = {'Out': out}
136
        return x, offset, out
D
dzhwinter 已提交
137

138
    def compute(self, x, offset, out):
139
        self.attrs = {"pad_value": 0.5, 'pooltype': "MAX"}
140 141 142
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
143 144
                out[i] = self.attrs["pad_value"]
            else:
145
                sub_x = x[offset[level][i]:offset[level][i + 1], :]
146 147 148 149 150 151
                out[i] = np.amax(sub_x, axis=0)


class TestSeqMaxPoolLen0(TestSeqMaxPool):
    def set_lod(self):
        return [[0, 1, 1, 5, 6, 0]]
D
dzhwinter 已提交
152 153


154 155 156 157 158
class TestSeqMaxPoolLen0LoDLevel2(TestSeqMaxPool):
    def set_lod(self):
        return [[2, 0, 3, 1], [0, 1, 1, 5, 6, 0]]


D
dzhwinter 已提交
159
class TestSeqSqrtPool(TestSeqAvgPool):
160
    def compute(self, x, offset, out):
161 162 163 164 165 166 167
        self.attrs = {"pad_value": 0.0, 'pooltype': "SQRT"}
        compute_seqpool_sqrt(x, offset, out, self.attrs["pad_value"])


class TestSeqSqrtPoolLen0(TestSeqSqrtPool):
    def set_lod(self):
        return [[0, 7, 0, 2, 2, 0]]
D
dzhwinter 已提交
168 169


170 171 172 173 174
class TestSeqSqrtPoolLen0LoDLevel2(TestSeqSqrtPool):
    def set_lod(self):
        return [[1, 2, 0, 3], [0, 7, 0, 2, 2, 0]]


D
dzhwinter 已提交
175
class TestSeqLastPool(TestSeqAvgPool):
176
    def compute(self, x, offset, out):
177
        self.attrs = {"pad_value": 0.0, 'pooltype': "LAST"}
178 179 180
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
181 182
                out[i] = self.attrs["pad_value"]
            else:
183
                sub_x = x[offset[level][i]:offset[level][i + 1], :]
184 185 186 187 188 189
                out[i] = sub_x[-1, :]


class TestSeqLastPoolLen0(TestSeqLastPool):
    def set_lod(self):
        return [[0, 3, 4, 0, 4, 0]]
D
dzhwinter 已提交
190 191


192 193 194 195 196
class TestSeqLastPoolLen0LoDLevel2(TestSeqLastPool):
    def set_lod(self):
        return [[1, 0, 2, 3], [0, 3, 4, 0, 4, 0]]


D
dzhwinter 已提交
197
class TestSeqFirstPool(TestSeqAvgPool):
198
    def compute(self, x, offset, out):
199
        self.attrs = {"pad_value": 0.3, 'pooltype': "FIRST"}
200 201 202
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
203 204
                out[i] = self.attrs["pad_value"]
            else:
205
                sub_x = x[offset[level][i]:offset[level][i + 1], :]
206 207 208 209 210 211
                out[i] = sub_x[0, :]


class TestSeqFirstPoolLen0(TestSeqFirstPool):
    def set_lod(self):
        return [[0, 2, 0, 3, 6, 0]]
D
dzhwinter 已提交
212 213


214 215 216 217 218
class TestSeqFirstPoolLen0LoDLevel2(TestSeqFirstPool):
    def set_lod(self):
        return [[1, 0, 2, 3], [0, 2, 0, 3, 6, 0]]


219
class TestSeqAvgPool2D(TestSeqAvgPool):
220 221 222
    def set_lod(self):
        return [[4, 1, 3, 5]]

223 224
    def set_data(self):
        self.op_type = 'sequence_pool'
225
        x = np.random.uniform(0.1, 1, [13, 3, 17]).astype('float32')
226
        lod = self.set_lod()
227
        level = len(lod) - 1
228
        self.inputs = {'X': (x, lod)}
T
tensor-tang 已提交
229
        offset = convert_to_offset(lod)
230

231
        out = np.zeros((len(lod[level]), 3, 17)).astype('float32')
232
        self.outputs = {'Out': out}
233
        return x, offset, out
234

235
    def compute(self, x, offset, out):
236
        self.attrs = {"pad_value": 0.0, 'pooltype': "AVERAGE"}
237 238 239
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
240 241
                out[i] = self.attrs["pad_value"] * np.ones((3, 17))
            else:
242
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
243 244 245 246 247 248 249
                                   (-1, 3 * 17))
                out[i] = np.reshape(sub_x.mean(axis=0), (3, 17))


class TestSeqAvgPool2DLen0(TestSeqAvgPool2D):
    def set_lod(self):
        return [[0, 5, 0, 8, 0]]
250 251


252 253 254 255 256
class TestSeqAvgPool2DLen0LoDLevel2(TestSeqAvgPool2D):
    def set_lod(self):
        return [[1, 0, 4], [0, 5, 0, 8, 0]]


257
class TestSeqSumPool2D(TestSeqAvgPool2D):
258
    def compute(self, x, offset, out):
259
        self.attrs = {"pad_value": 0.2, 'pooltype': "SUM"}
260 261 262
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
263 264
                out[i] = self.attrs["pad_value"] * np.ones((3, 17))
            else:
265
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
266 267 268 269 270 271 272
                                   (-1, 3 * 17))
                out[i] = np.reshape(sub_x.sum(axis=0), (3, 17))


class TestSeqSumPool2DLen0(TestSeqSumPool2D):
    def set_lod(self):
        return [[0, 8, 0, 5, 0]]
273 274


275 276 277 278 279
class TestSeqSumPool2DLen0LoDLevel2(TestSeqSumPool2D):
    def set_lod(self):
        return [[1, 0, 4], [0, 8, 0, 5, 0]]


L
Luo Tao 已提交
280
class TestSeqSqrtPool2D(TestSeqAvgPool2D):
281
    def compute(self, x, offset, out):
282
        self.attrs = {"pad_value": 0.0, 'pooltype': "SQRT"}
283 284 285
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
286 287
                out[i] = self.attrs["pad_value"] * np.ones((3, 17))
            else:
288
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
289
                                   (-1, 3 * 17))
290
                seq_len = offset[level][i + 1] - offset[level][i]
291 292
                out[i] = np.reshape(
                    sub_x.sum(axis=0) / np.sqrt(seq_len), (3, 17))
L
Luo Tao 已提交
293 294

    def test_check_grad(self):
295
        # Remove MaxIndex after check_grad is refined.
296 297 298
        out = self.outputs['Out']
        if isinstance(out, tuple):
            out = out[0]
299
        self.outputs['MaxIndex'] = \
300
            np.zeros(out.shape).astype('int32')
L
Luo Tao 已提交
301 302 303
        self.check_grad(["X"], "Out", max_relative_error=0.06)


304 305 306 307 308
class TestSeqSqrtPool2DLen0(TestSeqSqrtPool2D):
    def set_lod(self):
        return [[0, 8, 0, 5, 0]]


309 310 311 312 313
class TestSeqSqrtPool2DLen0LoDLevel2(TestSeqSqrtPool2D):
    def set_lod(self):
        return [[1, 0, 2, 2], [0, 8, 0, 5, 0]]


L
Luo Tao 已提交
314
class TestSeqMaxPool2D(TestSeqAvgPool2D):
315 316 317
    def set_lod(self):
        return [[4, 1, 3, 5]]

318 319 320
    def set_data(self):
        self.op_type = 'sequence_pool'
        x = np.random.uniform(0.1, 1, [13, 3, 11]).astype('float32')
321
        self.lod = self.set_lod()
322
        level = len(self.lod) - 1
323 324
        self.inputs = {'X': (x, self.lod)}
        offset = convert_to_offset(self.lod)
325 326
        for i in range(len(offset[level]) - 1):
            l = offset[level][i + 1] - offset[level][i]
327 328
            if l == 0:
                continue
329
            x[offset[level][i] + np.random.randint(l), :] += 1.0
330

331
        out = np.zeros((len(self.lod[level]), 3, 11)).astype('float32')
332
        self.outputs = {'Out': out}
333
        return x, offset, out
334

335
    def compute(self, x, offset, out):
336
        self.attrs = {"pad_value": 0.0, 'pooltype': "MAX"}
337 338 339
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
340 341
                out[i] = self.attrs["pad_value"] * np.ones((3, 11))
                continue
342
            sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
343
                               (-1, 3 * 11))
344
            out[i] = np.reshape(np.amax(sub_x, axis=0), (3, 11))
L
Luo Tao 已提交
345 346


347 348 349 350 351
class TestSeqMaxPool2DLen0(TestSeqMaxPool2D):
    def set_lod(self):
        return [[0, 3, 0, 10, 0]]


352 353 354 355 356
class TestSeqMaxPool2DLen0LoDLevel2(TestSeqMaxPool2D):
    def set_lod(self):
        return [[1, 0, 2, 2], [0, 3, 0, 10, 0]]


J
Jacek Czaja 已提交
357 358
class TestSeqMaxPool2DInference(TestSeqMaxPool2D):
    def compute(self, x, offset, out):
359
        self.attrs = {"pad_value": 1.0, 'pooltype': "MAX", 'is_test': True}
360 361 362
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
363 364
                out[i] = self.attrs["pad_value"] * np.ones((3, 11))
            else:
365
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
366 367
                                   (-1, 3 * 11))
                out[i] = np.reshape(np.amax(sub_x, axis=0), (3, 11))
J
Jacek Czaja 已提交
368 369 370 371 372 373 374

    def test_check_grad(self):
        """Grad computation does not apply to Sequence MAX 
            Pool executed when is_test is true """
        return


375 376 377 378 379
class TestSeqMaxPool2DInferenceLen0(TestSeqMaxPool2DInference):
    def set_lod(self):
        return [[0, 3, 0, 10, 0]]


380 381 382 383 384
class TestSeqMaxPool2DInferenceLen0LoDLevel2(TestSeqMaxPool2DInference):
    def set_lod(self):
        return [[1, 0, 2, 2], [0, 3, 0, 10, 0]]


L
Luo Tao 已提交
385
class TestSeqLastPool2D(TestSeqAvgPool2D):
386
    def compute(self, x, offset, out):
387
        self.attrs = {"pad_value": 0.0, 'pooltype': "LAST"}
388 389 390
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
391 392
                out[i] = self.attrs["pad_value"] * np.ones((3, 17))
            else:
393
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
394 395 396 397 398 399 400
                                   (-1, 3 * 17))
                out[i] = np.reshape(sub_x[-1, :], (3, 17))


class TestSeqLastPool2DLen0(TestSeqLastPool2D):
    def set_lod(self):
        return [[0, 3, 0, 1, 9, 0]]
L
Luo Tao 已提交
401 402


403 404 405 406 407
class TestSeqLastPool2DLen0LoDLevel2(TestSeqLastPool2D):
    def set_lod(self):
        return [[1, 0, 2, 3], [0, 3, 0, 1, 9, 0]]


L
Luo Tao 已提交
408
class TestSeqFirstPool2D(TestSeqAvgPool2D):
409
    def compute(self, x, offset, out):
410
        self.attrs = {"pad_value": 0.0, 'pooltype': "FIRST"}
411 412 413
        level = len(offset) - 1
        for i in range(len(offset[level]) - 1):
            if offset[level][i] == offset[level][i + 1]:
414 415
                out[i] = self.attrs["pad_value"] * np.ones((3, 17))
            else:
416
                sub_x = np.reshape(x[offset[level][i]:offset[level][i + 1], :],
417 418 419 420 421 422 423
                                   (-1, 3 * 17))
                out[i] = np.reshape(sub_x[0, :], (3, 17))


class TestSeqFirstPool2DLen0(TestSeqFirstPool2D):
    def set_lod(self):
        return [[0, 3, 0, 3, 7, 0]]
L
Luo Tao 已提交
424 425


426 427 428 429 430
class TestSeqFirstPool2DLen0LoDLevel2(TestSeqFirstPool2D):
    def set_lod(self):
        return [[1, 0, 2, 3], [0, 3, 0, 3, 7, 0]]


431 432
if __name__ == '__main__':
    unittest.main()