test_dict.py 8.0 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
from paddle import fluid
A
Aurelius84 已提交
21
from paddle.jit import to_static
22

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


28
class SubNetWithDict(paddle.nn.Layer):
29
    def __init__(self, hidden_size=16, output_size=16):
30
        super().__init__()
31

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

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

    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
66
            cache["k"], cache["v"] = k, v
67

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

        return out


75
class MainNetWithDict(paddle.nn.Layer):
76
    def __init__(self, batch_size=64, hidden_size=16, output_size=16):
77
        super().__init__()
78 79 80 81 82
        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 已提交
83
    @to_static
84 85 86
    def forward(self, input, max_len=4):
        input = fluid.dygraph.to_variable(input)
        cache = {
87
            "k": paddle.tensor.fill_constant(
88 89
                shape=[self.batch_size, self.output_size],
                dtype='float32',
90 91
                value=0,
            ),
92
            "v": paddle.tensor.fill_constant(
93 94
                shape=[self.batch_size, self.output_size],
                dtype='float32',
95 96
                value=0,
            ),
97
        }
98
        # TODO(Aurelius84): The following code will be converted into:
99
        # max_len = paddle.static.nn.cond(paddle.shape(input)[0] != max_len,
2
201716010711 已提交
100
        #                       lambda: paddle.shape(input)[0], lambda: max_len)
101 102 103 104
        # 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
105 106 107
        out = input
        for i in range(max_len):
            out = self.sub_net(out, cache)
108
            cache = update_cache(cache)
109 110 111
        return out


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

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


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):
131
        return self.train(to_static=True)
132 133

    def _run_dygraph(self):
134 135 136
        return self.train(to_static=False)

    def train(self, to_static=False):
R
Ryan 已提交
137
        paddle.jit.enable_to_static(to_static)
138 139 140 141 142 143 144 145 146
        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())


147 148 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
# 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):
174
        self.input = np.random.random(3).astype('int32')
175 176 177 178 179
        self.place = (
            paddle.CUDAPlace(0)
            if paddle.is_compiled_with_cuda()
            else paddle.CPUPlace()
        )
180 181 182 183 184 185 186 187 188 189 190 191
        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):
R
Ryan 已提交
192
        paddle.jit.enable_to_static(to_static)
193 194 195 196 197 198 199 200

        result = self.dygraph_func(self.input)

        return result.numpy()

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


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


216 217
class NetWithDictPop(paddle.nn.Layer):
    def __init__(self):
218
        super().__init__()
219 220 221 222 223

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

        x.mean()
        return x


Z
zhangchunle 已提交
232
class TestDictPop3(TestNetWithDict):
233 234 235 236
    def setUp(self):
        self.x = np.array([2, 2]).astype('float32')

    def train(self, to_static=False):
R
Ryan 已提交
237
        paddle.jit.enable_to_static(to_static)
238 239 240 241 242 243 244 245 246
        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()

247 248 249 250 251 252
        self.assertTrue(
            (dygraph_result == static_result).all(),
            msg="dygraph result: {}\nstatic result: {}".format(
                dygraph_result, static_result
            ),
        )
253 254


255 256 257 258 259 260 261 262 263 264
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(
265 266
                    {k: val + dict_val[k] for k, v in dict_val.items()}
                )
267 268 269 270 271 272 273 274 275 276 277 278 279 280

            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(
281 282
                    {k: val + dict_val[k] for k, v in dict_val.items()}
                )
283 284 285 286 287 288

            return dict_val

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


289 290
if __name__ == '__main__':
    unittest.main()