calc_gradient使用问题
Created by: oraoto
我在实现DeepDream,需要计算某个特征图对输入图像的梯度,所以使用了fluid.backward.calc_gradient
,发现两个问题:
- batch_norm无法计算梯度
x = fluid.layers.create_parameter(name="x0", shape=[1, 3, 5, 5], dtype='float32')
x2 = x * 2.0
x3 = fluid.layers.batch_norm(x2)
y = fluid.layers.mean(x3)
g = fluid.backward.calc_gradient(y, x) # 出错
错误信息:
EnforceNotMet Traceback (most recent call last)
<ipython-input-58-ce613e3efa1a> in <module>()
11 y = fluid.layers.mean(x3)
12
---> 13 g = fluid.backward.calc_gradient(y, x)
/home/lyp/projects/paddle/.env/lib/python2.7/site-packages/paddle/fluid/backward.pyc in calc_gradient(targets, inputs, target_gradients, no_grad_set)
729 _rename_grad_(block, fwd_op_num, grad_to_var, target_grad_map)
730
--> 731 _append_backward_vars_(block, fwd_op_num, grad_to_var, grad_info_map)
732 prog.sync_with_cpp()
733
/home/lyp/projects/paddle/.env/lib/python2.7/site-packages/paddle/fluid/backward.pyc in _append_backward_vars_(block, start_op_idx, grad_to_var, grad_info_map)
390 # infer_shape and infer_type
391 op_desc.infer_var_type(block.desc)
--> 392 op_desc.infer_shape(block.desc)
393 # ncclInit dones't need to set data_type
394 if op_desc.type() == 'ncclInit':
EnforceNotMet: at [/paddle/paddle/fluid/operators/batch_norm_op.cc:325]
PaddlePaddle Call Stacks:
0 0x7f26d1ee4376p paddle::platform::EnforceNotMet::EnforceNotMet(std::__exception_ptr::exception_ptr, char const*, int) + 486
1 0x7f26d247efb8p paddle::operators::BatchNormGradOp::InferShape(paddle::framework::InferShapeContext*) const + 2888
2 0x7f26d1f64691p paddle::framework::OpDesc::InferShape(paddle::framework::BlockDesc const&) const + 881
3 0x7f26d1f37915p pybind11::cpp_function::initialize<pybind11::cpp_function::initialize<void, paddle::framework::OpDesc, paddle::framework::BlockDesc const&, pybind11::name, pybind11::is_method, pybind11::sibling>(void (paddle::framework::OpDesc::*)(paddle::framework::BlockDesc const&) const, pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&)::{lambda(paddle::framework::OpDesc const*, paddle::framework::BlockDesc const&)#1}, void, paddle::framework::OpDesc const*, paddle::framework::BlockDesc const&, pybind11::name, pybind11::is_method, pybind11::sibling>(pybind11::cpp_function::initialize<void, paddle::framework::OpDesc, paddle::framework::BlockDesc const&, pybind11::name, pybind11::is_method, pybind11::sibling>(void (paddle::framework::OpDesc::*)(paddle::framework::BlockDesc const&) const, pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&)::{lambda(paddle::framework::OpDesc const*, paddle::framework::BlockDesc const&)#1}&&, void (*)(paddle::framework::OpDesc const*, paddle::framework::BlockDesc const&), pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&)::{lambda(pybind11::detail::function_call&)#3}::_FUN(pybind11::detail::function_call) + 213
4 0x7f26d1ef346cp pybind11::cpp_function::dispatcher(_object*, _object*, _object*) + 2540
5 0x7f271bc071a8p PyEval_EvalFrameEx + 25384
2.fluid.layers.slice
某些情况会无法计算梯度
没有slice时能正常求梯度:
x = fluid.layers.create_parameter(name="x1", shape=[1, 3, 5, 5], dtype='float32')
x2 = x * 2.0
y = fluid.layers.mean(x2)
g = fluid.backward.calc_gradient(y, x)
加了一层slice,无法求梯度(返回None):
x = fluid.layers.create_parameter(name="x2", shape=[1, 3, 5, 5], dtype='float32') # (1, 3, 5, 5)
x2 = x * 2.0
s = fluid.layers.slice(x2, axes=[0, 1], starts=[0, 0], ends=[1, 2]) # (1, 2, 5, 5)
y = fluid.layers.mean(s) # (1, )
g = fluid.backward.calc_gradient(y, x2) # g is None
再加一层Conv2D,g不为None,但是梯度都是0:
x = fluid.layers.create_parameter(name="x3", shape=[1, 3, 5, 5], dtype='float32')
x2 = x * 2.0
conv = fluid.layers.conv2d(x2, num_filters=3, filter_size=3, padding=1, act='relu') # (1, 3, 5, 5)
s = fluid.layers.slice(conv, axes=[0, 1], starts=[0, 0], ends=[1, 2]) # (1, 2, 5, 5)
y = fluid.layers.mean(s)
g = fluid.backward.calc_gradient(y, x)