test_dict.py 8.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# 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
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# 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.

import unittest

17 18
import numpy as np

19
import paddle
20
import paddle.fluid as fluid
A
Aurelius84 已提交
21
from paddle.jit import to_static
22
from paddle.jit.dy2static.program_translator import ProgramTranslator
23

24 25 26
PLACE = (
    fluid.CUDAPlace(0) if fluid.is_compiled_with_cuda() else fluid.CPUPlace()
)
27 28 29 30


class SubNetWithDict(fluid.dygraph.Layer):
    def __init__(self, hidden_size=16, output_size=16):
31
        super().__init__()
32

33 34
        init_weight = lambda x: paddle.ParamAttr(
            initializer=paddle.nn.initializer.Constant(x)
35 36
        )

37 38 39
        self.q_fc = paddle.nn.Linear(
            in_features=hidden_size,
            out_features=output_size,
40
            bias_attr=False,
41
            weight_attr=init_weight(0.6),
42
        )
43 44 45
        self.k_fc = paddle.nn.Linear(
            in_features=hidden_size,
            out_features=output_size,
46
            bias_attr=False,
47
            weight_attr=init_weight(0.5),
48
        )
49 50 51
        self.v_fc = paddle.nn.Linear(
            in_features=hidden_size,
            out_features=output_size,
52
            bias_attr=False,
53
            weight_attr=init_weight(0.2),
54
        )
55 56 57 58 59 60 61 62 63 64 65 66

    def forward(self, input, cache=None):
        input = fluid.dygraph.to_variable(input)

        q = self.q_fc(input)
        k = self.k_fc(input)
        v = self.v_fc(input)

        if cache is not None:
            cache_k, cache_v = cache["k"], cache["v"]
            k = 0.1 * cache_k + k
            v = 0.2 * cache_v + v
67
            cache["k"], cache["v"] = k, v
68

K
kangguangli 已提交
69
        weight = paddle.matmul(x=q, y=k, transpose_y=True)
70
        weight = paddle.nn.functional.softmax(weight)
K
kangguangli 已提交
71
        out = paddle.matmul(weight, v)
72 73 74 75 76 77

        return out


class MainNetWithDict(fluid.dygraph.Layer):
    def __init__(self, batch_size=64, hidden_size=16, output_size=16):
78
        super().__init__()
79 80 81 82 83
        self.batch_size = batch_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        self.sub_net = SubNetWithDict(hidden_size, output_size)

A
Aurelius84 已提交
84
    @to_static
85 86 87
    def forward(self, input, max_len=4):
        input = fluid.dygraph.to_variable(input)
        cache = {
88
            "k": fluid.layers.fill_constant(
89 90
                shape=[self.batch_size, self.output_size],
                dtype='float32',
91 92 93
                value=0,
            ),
            "v": fluid.layers.fill_constant(
94 95
                shape=[self.batch_size, self.output_size],
                dtype='float32',
96 97
                value=0,
            ),
98
        }
99
        # TODO(Aurelius84): The following code will be converted into:
100
        # max_len = paddle.static.nn.cond(paddle.shape(input)[0] != max_len,
2
201716010711 已提交
101
        #                       lambda: paddle.shape(input)[0], lambda: max_len)
102 103 104 105
        # But max_len should be wrapped into tensor, which is not supported.

        # Comment out this line of code for now.
        # max_len = input.shape[0] if input.shape[0] != max_len else max_len
106 107 108
        out = input
        for i in range(max_len):
            out = self.sub_net(out, cache)
109
            cache = update_cache(cache)
110 111 112
        return out


113 114
# Test to call function defined outside of class.
def update_cache(cache):
115
    for k, val in cache.items():
116
        cache[k] = paddle.nn.functional.softmax(val)
117 118

    return cache
119 120 121 122 123 124 125 126 127 128 129 130 131


class TestNetWithDict(unittest.TestCase):
    """
    TestCase for the transformation from control flow `if/else`
    dependent on tensor in Dygraph into Static `fluid.layers.cond`.
    """

    def setUp(self):
        self.x = np.random.random([10, 16]).astype('float32')
        self.batch_size = self.x.shape[0]

    def _run_static(self):
132
        return self.train(to_static=True)
133 134

    def _run_dygraph(self):
135 136 137 138 139
        return self.train(to_static=False)

    def train(self, to_static=False):
        prog_trans = ProgramTranslator()
        prog_trans.enable(to_static)
140 141 142 143 144 145 146 147 148
        with fluid.dygraph.guard(PLACE):
            net = MainNetWithDict(batch_size=self.batch_size)
            ret = net(self.x)
            return ret.numpy()

    def test_ast_to_func(self):
        self.assertTrue((self._run_dygraph() == self._run_static()).all())


149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
# Tests for dict pop
@paddle.jit.to_static
def test_dic_pop(x):
    x = paddle.to_tensor(x)
    dict_a = {"red": 0, "green": 1, "blue": 2}

    m = dict_a.pop("red")
    n = dict_a.pop("black", 3)

    out = x + m + n
    return out


@paddle.jit.to_static
def test_dic_pop_2(x):
    x = paddle.to_tensor(x)
    dict_a = {"red": x, "green": x + 1, "blue": x + 3}

    m = dict_a.pop("red")
    n = dict_a.pop("black", 3)

    out = x + m + n
    return out


class TestDictPop(unittest.TestCase):
    def setUp(self):
        self.input = np.random.random((3)).astype('int32')
177 178 179 180 181
        self.place = (
            paddle.CUDAPlace(0)
            if paddle.is_compiled_with_cuda()
            else paddle.CPUPlace()
        )
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        self._set_test_func()

    def _set_test_func(self):
        self.dygraph_func = test_dic_pop

    def _run_static(self):
        return self._run(to_static=True)

    def _run_dygraph(self):
        return self._run(to_static=False)

    def _run(self, to_static):
        prog_trans = ProgramTranslator()
        prog_trans.enable(to_static)

        result = self.dygraph_func(self.input)

        return result.numpy()

    def test_transformed_result(self):
        dygraph_res = self._run_dygraph()
        static_res = self._run_static()
204 205 206 207 208
        np.testing.assert_allclose(
            dygraph_res,
            static_res,
            rtol=1e-05,
            err_msg='dygraph result is {}\nstatic result is {}'.format(
209 210 211
                dygraph_res, static_res
            ),
        )
212 213 214 215 216 217 218


class TestDictPop2(TestDictPop):
    def _set_test_func(self):
        self.dygraph_func = test_dic_pop_2


219 220
class NetWithDictPop(paddle.nn.Layer):
    def __init__(self):
221
        super().__init__()
222 223 224 225 226

    @to_static
    def forward(self, x, **kwargs):
        x = paddle.to_tensor(x)
        y = kwargs.pop('y', None)
L
liym27 已提交
227
        if y:
228 229 230 231 232 233 234
            y = paddle.to_tensor(x)
            x += y

        x.mean()
        return x


Z
zhangchunle 已提交
235
class TestDictPop3(TestNetWithDict):
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    def setUp(self):
        self.x = np.array([2, 2]).astype('float32')

    def train(self, to_static=False):
        prog_trans = ProgramTranslator()
        prog_trans.enable(to_static)
        with fluid.dygraph.guard(PLACE):
            net = NetWithDictPop()
            ret = net(z=0, x=self.x, y=True)
            return ret.numpy()

    def test_ast_to_func(self):
        dygraph_result = self._run_dygraph()
        static_result = self._run_static()

251 252 253 254 255 256
        self.assertTrue(
            (dygraph_result == static_result).all(),
            msg="dygraph result: {}\nstatic result: {}".format(
                dygraph_result, static_result
            ),
        )
257 258


259 260 261 262 263 264 265 266 267 268
class TestDictCmpInFor(unittest.TestCase):
    def test_with_for(self):
        def func():
            pos = [1, 3]
            neg = [-1, -3]
            dict_val = {'minus': 0}
            # test `zip` with `for`
            for (x, y) in zip(pos, neg):
                val = x - y
                dict_val.update(
269 270
                    {k: val + dict_val[k] for k, v in dict_val.items()}
                )
271 272 273 274 275 276 277 278 279 280 281 282 283 284

            return dict_val

        self.assertEqual(paddle.jit.to_static(func)()['minus'], 8)

    def test_with_for_enumerate(self):
        def func():
            pos = [1, 3]
            neg = [-1, -3]
            dict_val = {'minus': 0}
            # test `zip` with `for`
            for i, (x, y) in enumerate(zip(pos, neg)):
                val = x - y
                dict_val.update(
285 286
                    {k: val + dict_val[k] for k, v in dict_val.items()}
                )
287 288 289 290 291 292

            return dict_val

        self.assertEqual(paddle.jit.to_static(func)()['minus'], 8)


293 294
if __name__ == '__main__':
    unittest.main()