未验证 提交 d8a2aa5d 编写于 作者: G guofei 提交者: GitHub

Make assign op support LoDTensorArray and modify while_loop API (#22309) (#22525)

This PR makes assign op support LoDTensorArray and enable the loop_vars in
while_loop to support tuple or list.
上级 ad2813b1
...@@ -1234,7 +1234,7 @@ Scope* OperatorWithKernel::PrepareData( ...@@ -1234,7 +1234,7 @@ Scope* OperatorWithKernel::PrepareData(
void OperatorWithKernel::ParseInputDataType( void OperatorWithKernel::ParseInputDataType(
const ExecutionContext& ctx, const std::string& name, const ExecutionContext& ctx, const std::string& name,
proto::VarType::Type* data_type) const { proto::VarType::Type* data_type) const {
proto::VarType::Type dafault_data_type = proto::VarType::Type default_data_type =
static_cast<proto::VarType::Type>(-1); static_cast<proto::VarType::Type>(-1);
const std::vector<Variable*> vars = ctx.MultiInputVar(name); const std::vector<Variable*> vars = ctx.MultiInputVar(name);
for (size_t i = 0; i < vars.size(); ++i) { for (size_t i = 0; i < vars.size(); ++i) {
...@@ -1247,6 +1247,13 @@ void OperatorWithKernel::ParseInputDataType( ...@@ -1247,6 +1247,13 @@ void OperatorWithKernel::ParseInputDataType(
t = &var->Get<LoDTensor>(); t = &var->Get<LoDTensor>();
} else if (var->IsType<SelectedRows>()) { } else if (var->IsType<SelectedRows>()) {
t = &(var->Get<SelectedRows>().value()); t = &(var->Get<SelectedRows>().value());
} else if (var->IsType<LoDTensorArray>()) {
auto t_arr = var->Get<LoDTensorArray>();
for (size_t j = 0; j < t_arr.size(); j++) {
if (t_arr[j].IsInitialized()) {
t = &(t_arr[j]);
}
}
} }
if (t != nullptr) { if (t != nullptr) {
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
...@@ -1257,7 +1264,7 @@ void OperatorWithKernel::ParseInputDataType( ...@@ -1257,7 +1264,7 @@ void OperatorWithKernel::ParseInputDataType(
Type(), name, ctx.InputNames(name).at(i))); Type(), name, ctx.InputNames(name).at(i)));
proto::VarType::Type tmp = t->type(); proto::VarType::Type tmp = t->type();
PADDLE_ENFORCE( PADDLE_ENFORCE(
tmp == *data_type || *data_type == dafault_data_type, tmp == *data_type || *data_type == default_data_type,
platform::errors::InvalidArgument( platform::errors::InvalidArgument(
"The DataType of %s Op's duplicable Variable %s must be " "The DataType of %s Op's duplicable Variable %s must be "
"consistent. The current variable type is (%s), but the " "consistent. The current variable type is (%s), but the "
......
...@@ -1000,15 +1000,12 @@ def while_loop(cond, body, loop_vars, is_test=False, name=None): ...@@ -1000,15 +1000,12 @@ def while_loop(cond, body, loop_vars, is_test=False, name=None):
while_loop_block = While(pre_cond, is_test, name) while_loop_block = While(pre_cond, is_test, name)
with while_loop_block.block(): with while_loop_block.block():
output_vars = body(*loop_vars) output_vars = body(*loop_vars)
map_structure(assign, output_vars, loop_vars)
if len(loop_vars) == 1: if len(loop_vars) == 1:
assign(output_vars, loop_vars[0])
now_cond = cond(output_vars) now_cond = cond(output_vars)
else: else:
for i in range(len(output_vars)):
assign(output_vars[i], loop_vars[i])
now_cond = cond(*output_vars) now_cond = cond(*output_vars)
assign(now_cond, pre_cond) assign(now_cond, pre_cond)
return loop_vars return loop_vars
......
...@@ -62,11 +62,7 @@ class TestApiWhileLoop(unittest.TestCase): ...@@ -62,11 +62,7 @@ class TestApiWhileLoop(unittest.TestCase):
with program_guard(main_program, startup_program): with program_guard(main_program, startup_program):
i = layers.zeros(shape=[1], dtype='int64') i = layers.zeros(shape=[1], dtype='int64')
ten = layers.fill_constant(shape=[1], dtype='int64', value=10) ten = layers.fill_constant(shape=[1], dtype='int64', value=10)
mem = layers.data( mem = fluid.data(name='mem', shape=[10], dtype='float32')
name='mem',
shape=[10],
dtype='float32',
append_batch_size=False)
one = layers.fill_constant(shape=[10], dtype='float32', value=1) one = layers.fill_constant(shape=[10], dtype='float32', value=1)
out = layers.while_loop(cond, body, [i, mem]) out = layers.while_loop(cond, body, [i, mem])
...@@ -111,16 +107,8 @@ class TestApiWhileLoop_Nested(unittest.TestCase): ...@@ -111,16 +107,8 @@ class TestApiWhileLoop_Nested(unittest.TestCase):
with program_guard(main_program, startup_program): with program_guard(main_program, startup_program):
i = layers.zeros(shape=[1], dtype='int64') i = layers.zeros(shape=[1], dtype='int64')
j = layers.zeros(shape=[1], dtype='int64') j = layers.zeros(shape=[1], dtype='int64')
init = layers.data( init = fluid.data(name='init', shape=[3, 3], dtype='float32')
name='init', sums = fluid.data(name='sums', shape=[3, 3], dtype='float32')
shape=[3, 3],
dtype='float32',
append_batch_size=False)
sums = layers.data(
name='sums',
shape=[3, 3],
dtype='float32',
append_batch_size=False)
loop_len1 = layers.fill_constant(shape=[1], dtype='int64', value=2) loop_len1 = layers.fill_constant(shape=[1], dtype='int64', value=2)
loop_len2 = layers.fill_constant(shape=[1], dtype='int64', value=3) loop_len2 = layers.fill_constant(shape=[1], dtype='int64', value=3)
ones = layers.fill_constant(shape=[3, 3], dtype='float32', value=1) ones = layers.fill_constant(shape=[3, 3], dtype='float32', value=1)
...@@ -159,13 +147,11 @@ class TestApiWhileLoop_Backward(unittest.TestCase): ...@@ -159,13 +147,11 @@ class TestApiWhileLoop_Backward(unittest.TestCase):
main_program = Program() main_program = Program()
startup_program = Program() startup_program = Program()
with fluid.program_guard(main_program, startup_program): with fluid.program_guard(main_program, startup_program):
i = layers.data( i = fluid.data(name='i', shape=[1], dtype='float32')
name='i', shape=[1], dtype='float32', append_batch_size=False)
i.stop_gradient = False i.stop_gradient = False
eleven = layers.fill_constant(shape=[1], dtype='float32', value=11) eleven = layers.fill_constant(shape=[1], dtype='float32', value=11)
one = layers.fill_constant(shape=[1], dtype='float32', value=1) one = layers.fill_constant(shape=[1], dtype='float32', value=1)
x = layers.data( x = fluid.data(name='x', shape=[1], dtype='float32')
name='x', shape=[1], dtype='float32', append_batch_size=False)
x.stop_gradient = False x.stop_gradient = False
out = layers.while_loop(cond, body, [i, x]) out = layers.while_loop(cond, body, [i, x])
...@@ -189,63 +175,84 @@ class TestApiWhileLoop_Backward(unittest.TestCase): ...@@ -189,63 +175,84 @@ class TestApiWhileLoop_Backward(unittest.TestCase):
self.assertTrue(np.allclose(np.asarray(res[1]), i_grad)) self.assertTrue(np.allclose(np.asarray(res[1]), i_grad))
class TestApiWhileLoop_NestedWithBackward(unittest.TestCase): class TestApiWhileLoop_NestedWithBackwardAndLoDTensorArray(unittest.TestCase):
def test_nested_net_with_backward(self): def test_nested_net_with_backward_and_lodtensor(self):
def external_cond(i, x, y): def external_cond(i, j, x, mem_array):
return layers.less_than(i, ten) return layers.less_than(i, array_len)
def external_body(i, x, y): def external_body(i, j, x, mem_array):
def internal_cond(i, x, y): def internal_cond(j, x, mem_array):
return layers.less_than(i, five) return layers.less_than(j, array_len2)
def internal_body(i, x, y): def internal_body(j, x, mem_array):
x = layers.elementwise_add(x=i, y=i) inner_data = layers.array_read(array=data_array, i=j)
i = layers.increment(i) inner_prev = layers.array_read(array=mem_array, i=j)
return [i, x, y] inner_sum_0 = layers.elementwise_add(x=inner_data, y=inner_prev)
inner_sum_1 = layers.elementwise_add(x=x, y=inner_sum_0)
temp = layers.while_loop(internal_cond, internal_body, [i, x, y]) j = layers.increment(x=j, in_place=True)
y = layers.elementwise_add(x=temp[1], y=i) layers.array_write(inner_sum_1, i=j, array=mem_array)
i = layers.increment(i) return [j, x, mem_array]
return [i, x, y]
outer_data = layers.array_read(array=data_array, i=i)
outer_prev = layers.array_read(array=mem_array, i=i)
outer_sum_0 = layers.elementwise_add(x=outer_data, y=outer_prev)
outer_sum_1 = layers.elementwise_add(x=x, y=outer_sum_0)
i = layers.increment(x=i, in_place=True)
layers.array_write(outer_sum_1, i=i, array=mem_array)
j, x, mem_array = layers.while_loop(internal_cond, internal_body,
[j, x, mem_array])
return [i, j, x, mem_array]
main_program = Program() main_program = Program()
startup_program = Program() startup_program = Program()
with fluid.program_guard(main_program, startup_program): with fluid.program_guard(main_program, startup_program):
i = layers.data( d0 = fluid.data(name='d0', shape=[10], dtype='float32')
name='i', shape=[1], dtype='float32', append_batch_size=False) d1 = fluid.data(name='d1', shape=[10], dtype='float32')
i.stop_gradient = False d2 = fluid.data(name='d2', shape=[10], dtype='float32')
ten = layers.fill_constant(shape=[1], dtype='float32', value=10) x = fluid.data(name='x', shape=[10], dtype='float32')
five = layers.fill_constant(shape=[1], dtype='float32', value=5)
x = layers.data(
name='x', shape=[1], dtype='float32', append_batch_size=False)
x.stop_gradient = False x.stop_gradient = False
y = layers.data( i = layers.zeros(shape=[1], dtype='int64')
name='y', shape=[1], dtype='float32', append_batch_size=False) i.stop_gradient = True
y.stop_gradient = False init = layers.zeros(shape=[10], dtype='float32')
out = layers.while_loop(external_cond, external_body, [i, x, y]) mem_array = layers.array_write(x=init, i=i)
data_array = layers.array_write(x=d0, i=i)
i = layers.increment(i)
layers.array_write(d1, i, array=data_array)
i = layers.increment(i)
layers.array_write(d2, i, array=data_array)
i = layers.zeros(shape=[1], dtype='int64')
i.stop_gradient = True
array_len = layers.fill_constant(shape=[1], dtype='int64', value=1)
j = layers.fill_constant(shape=[1], dtype='int64', value=1)
j.stop_gradient = True
array_len2 = layers.fill_constant(shape=[1], dtype='int64', value=3)
mean = layers.mean(out[2]) out = layers.while_loop(external_cond, external_body,
[i, j, x, mem_array])
sum_result = layers.array_read(array=mem_array, i=j)
mean = layers.mean(sum_result)
append_backward(mean) append_backward(mean)
place = fluid.CUDAPlace(0) if core.is_compiled_with_cuda( place = fluid.CUDAPlace(0) if core.is_compiled_with_cuda(
) else fluid.CPUPlace() ) else fluid.CPUPlace()
exe = fluid.Executor(place) exe = fluid.Executor(place)
data = np.asarray([17]).astype('float32') d = []
feed_x = np.zeros(1).astype('float32') for i in range(3):
feed_i = np.ones(1).astype('float32') d.append(np.random.random(size=[10]).astype('float32'))
feed_y = np.zeros(1).astype('float32') feed_x = np.ones(10).astype('float32')
i_grad = np.asarray(13).astype('int32') data_sum = d[0] + d[1] + d[2] + 3 * feed_x
x_grad = [0.3] * 10
res = exe.run(main_program, res = exe.run(
feed={'i': feed_i, main_program,
'x': feed_x, feed={'d0': d[0],
'y': feed_y}, 'd1': d[1],
fetch_list=[mean.name, i.grad_name]) 'd2': d[2],
'x': feed_x},
self.assertTrue(np.allclose(np.asarray(res[0]), data)) fetch_list=[sum_result.name, x.grad_name])
self.assertTrue(np.allclose(np.asarray(res[1]), i_grad)) self.assertTrue(np.allclose(res[0], data_sum))
self.assertTrue(np.allclose(res[1], x_grad))
class TestApiWhileLoopWithSwitchCase(unittest.TestCase): class TestApiWhileLoopWithSwitchCase(unittest.TestCase):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册