|
|
|
@ -66,6 +66,128 @@ class MLP(fluid.imperative.Layer):
|
|
|
|
|
return x
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SimpleRNNCell(fluid.imperative.Layer):
|
|
|
|
|
def __init__(self, step_input_size, hidden_size, output_size, param_attr):
|
|
|
|
|
super(SimpleRNNCell, self).__init__()
|
|
|
|
|
self.step_input_size = step_input_size
|
|
|
|
|
self.hidden_size = hidden_size
|
|
|
|
|
self.output_size = output_size
|
|
|
|
|
self._dype = core.VarDesc.VarType.FP32
|
|
|
|
|
from paddle.fluid.layer_helper import LayerHelper
|
|
|
|
|
self._helper = LayerHelper(
|
|
|
|
|
'SimpleRNNCell', act="tanh", param_attr=param_attr)
|
|
|
|
|
|
|
|
|
|
def _build_once(self, inputs, pre_hidden):
|
|
|
|
|
i2h_param_shape = [self.step_input_size, self.hidden_size]
|
|
|
|
|
h2h_param_shape = [self.hidden_size, self.hidden_size]
|
|
|
|
|
h2o_param_shape = [self.output_size, self.hidden_size]
|
|
|
|
|
self._i2h_w = self._helper.create_parameter(
|
|
|
|
|
attr=self._helper.param_attr,
|
|
|
|
|
shape=i2h_param_shape,
|
|
|
|
|
dtype=self._dtype,
|
|
|
|
|
is_bias=False)
|
|
|
|
|
self._h2h_w = self._helper.create_parameter(
|
|
|
|
|
attr=self._helper.param_attr,
|
|
|
|
|
shape=h2h_param_shape,
|
|
|
|
|
dtype=self._dtype,
|
|
|
|
|
is_bias=False)
|
|
|
|
|
self._h2o_w = self._helper.create_parameter(
|
|
|
|
|
attr=self._helper.param_attr,
|
|
|
|
|
shape=h2o_param_shape,
|
|
|
|
|
dtype=self._dtype,
|
|
|
|
|
is_bias=False)
|
|
|
|
|
|
|
|
|
|
def forward(self, input, pre_hidden):
|
|
|
|
|
|
|
|
|
|
tmp_i2h = self._helper.create_variable_for_type_inference(self._dtype)
|
|
|
|
|
tmp_h2h = self._helper.create_variable_for_type_inference(self._dtype)
|
|
|
|
|
hidden = self._helper.create_variable_for_type_inference(self._dype)
|
|
|
|
|
out = self._helper.create_variable_for_type_inference(self._dype)
|
|
|
|
|
softmax_out = self._helper.create_variable_for_type_inference(
|
|
|
|
|
self._dtype)
|
|
|
|
|
reduce_out = self._helper.create_variable_for_type_inference(
|
|
|
|
|
self._dtype)
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type="mul",
|
|
|
|
|
inputs={"X": input,
|
|
|
|
|
"Y": self._i2h_w},
|
|
|
|
|
outputs={"Out": tmp_i2h},
|
|
|
|
|
attrs={"x_num_col_dims": 1,
|
|
|
|
|
"y_num_col_dims": 1})
|
|
|
|
|
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type="mul",
|
|
|
|
|
inputs={"X": pre_hidden,
|
|
|
|
|
"Y": self._h2h_w},
|
|
|
|
|
outputs={"Out": tmp_h2h},
|
|
|
|
|
attrs={"x_num_col_dims": 1,
|
|
|
|
|
"y_num_col_dims": 1})
|
|
|
|
|
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type="elementwise_add",
|
|
|
|
|
inputs={'X': tmp_h2h,
|
|
|
|
|
'Y': tmp_i2h},
|
|
|
|
|
outputs={'Out': hidden},
|
|
|
|
|
attrs={'axis': -1,
|
|
|
|
|
'use_mkldnn': False})
|
|
|
|
|
hidden = self._helper.append_activation(hidden)
|
|
|
|
|
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type="mul",
|
|
|
|
|
inputs={"X": hidden,
|
|
|
|
|
"Y": self._h2o_w},
|
|
|
|
|
outputs={"Out": out},
|
|
|
|
|
attrs={"x_num_col_dims": 1,
|
|
|
|
|
"y_num_col_dims": 1})
|
|
|
|
|
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type="softmax",
|
|
|
|
|
inputs={"X": out},
|
|
|
|
|
outputs={"Out": softmax_out},
|
|
|
|
|
attrs={"use_cudnn": False})
|
|
|
|
|
|
|
|
|
|
self._helper.append_op(
|
|
|
|
|
type='reduce_sum',
|
|
|
|
|
inputs={'X': softmax_out},
|
|
|
|
|
outputs={'Out': reduce_out},
|
|
|
|
|
attrs={'dim': None,
|
|
|
|
|
'keep_dim': False,
|
|
|
|
|
'reduce_all': True})
|
|
|
|
|
|
|
|
|
|
return reduce_out, hidden
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SimpleRNN(fluid.imperative.Layer):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
super(SimpleRNN, self).__init__()
|
|
|
|
|
self.seq_len = 4
|
|
|
|
|
self._cell = SimpleRNNCell(
|
|
|
|
|
3,
|
|
|
|
|
3,
|
|
|
|
|
3,
|
|
|
|
|
fluid.ParamAttr(initializer=fluid.initializer.Constant(value=0.1)))
|
|
|
|
|
|
|
|
|
|
def forward(self, inputs):
|
|
|
|
|
outs = list()
|
|
|
|
|
pre_hiddens = list()
|
|
|
|
|
|
|
|
|
|
init_hidden = fluid.layers.tensor.create_parameter(
|
|
|
|
|
attr=fluid.ParamAttr(
|
|
|
|
|
initializer=fluid.initializer.Constant(value=0.1)),
|
|
|
|
|
shape=[1, 3],
|
|
|
|
|
dtype='float32',
|
|
|
|
|
is_bias=False)
|
|
|
|
|
pre_hidden = init_hidden
|
|
|
|
|
for i in range(self.seq_len):
|
|
|
|
|
input = fluid.layers.slice(
|
|
|
|
|
inputs, axes=[1], starts=[i], ends=[i + 1])
|
|
|
|
|
input = fluid.layers.reshape(input, shape=[1, 3])
|
|
|
|
|
out_softmax, pre_hidden = self._cell(input, pre_hidden)
|
|
|
|
|
outs.append(out_softmax)
|
|
|
|
|
|
|
|
|
|
return outs, pre_hiddens
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestImperative(unittest.TestCase):
|
|
|
|
|
def test_sum_op(self):
|
|
|
|
|
x = np.ones([2, 2], np.float32)
|
|
|
|
@ -211,6 +333,41 @@ class TestImperative(unittest.TestCase):
|
|
|
|
|
self.assertTrue(np.allclose(dy_out, static_out))
|
|
|
|
|
self.assertTrue(np.allclose(dy_grad, static_grad))
|
|
|
|
|
|
|
|
|
|
def test_rnn(self):
|
|
|
|
|
np_inp = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0],
|
|
|
|
|
[10.0, 11.0, 12.0]])
|
|
|
|
|
np_inp = np_inp.reshape((1, 4, 3))
|
|
|
|
|
np_inp = np_inp.astype(np.float32)
|
|
|
|
|
with fluid.imperative.guard():
|
|
|
|
|
var_inp = fluid.imperative.base.to_variable(np_inp)
|
|
|
|
|
var_inp = fluid.layers.reshape(var_inp, shape=[1, 4, 3])
|
|
|
|
|
simple_rnn = SimpleRNN()
|
|
|
|
|
outs, pre_hiddens = simple_rnn.forward(var_inp)
|
|
|
|
|
dy_out = outs[3]._numpy()
|
|
|
|
|
outs[3]._backward()
|
|
|
|
|
dy_grad_h2o = simple_rnn._cell._h2o_w._gradient()
|
|
|
|
|
dy_grad_h2h = simple_rnn._cell._h2h_w._gradient()
|
|
|
|
|
dy_grad_i2h = simple_rnn._cell._i2h_w._gradient()
|
|
|
|
|
|
|
|
|
|
with new_program_scope():
|
|
|
|
|
inp = fluid.layers.data(
|
|
|
|
|
name="inp", shape=[1, 4, 3], append_batch_size=False)
|
|
|
|
|
simple_rnn = SimpleRNN()
|
|
|
|
|
outs, pre_hiddens = simple_rnn(inp)
|
|
|
|
|
param_grads = fluid.backward.append_backward(outs[3])
|
|
|
|
|
exe = fluid.Executor(fluid.CPUPlace())
|
|
|
|
|
exe.run(fluid.default_startup_program())
|
|
|
|
|
static_out, static_grad_h2o, static_grad_h2h, static_grad_i2h = exe.run(
|
|
|
|
|
feed={inp.name: np_inp},
|
|
|
|
|
fetch_list=[
|
|
|
|
|
outs[3].name, param_grads[0][1].name,
|
|
|
|
|
param_grads[1][1].name, param_grads[2][1].name
|
|
|
|
|
])
|
|
|
|
|
self.assertTrue(np.allclose(dy_out, static_out))
|
|
|
|
|
self.assertTrue(np.allclose(dy_grad_h2o, static_grad_h2o))
|
|
|
|
|
self.assertTrue(np.allclose(dy_grad_h2h, static_grad_h2h))
|
|
|
|
|
self.assertTrue(np.allclose(dy_grad_i2h, static_grad_i2h))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
unittest.main()
|
|
|
|
|