move exec.reshape to backend#10882
Conversation
| API_END(); | ||
| } | ||
|
|
||
| int MXExecutorReshapeEX(SymbolHandle symbol_handle, |
There was a problem hiding this comment.
nit: MXExecutorReshapeEX -> MXExecutorReshapeEx
piiswrong
left a comment
There was a problem hiding this comment.
Is there existing test covering reshape?
| *! \brief Return a new executor with the same symbol and shared memory, | ||
| * but different input/output shapes. | ||
| */ | ||
| MXNET_DLL int MXExecutorReshapeEx(SymbolHandle symbol_handle, |
There was a problem hiding this comment.
why Ex? is there a MXExecutorReshape already?
reminisce
left a comment
There was a problem hiding this comment.
Please write unit tests for this. It should cover expected behaviors of sizing down and sizing up.
| for (uint32_t nid : idx.input_nodes()) { | ||
| std::string name = idx[nid].source->attrs.name; | ||
| const TShape& new_shape = shape_vec[idx.entry_id(nid, 0)]; | ||
| if (idx.mutable_input_nodes().count(nid) == 0) { |
There was a problem hiding this comment.
Can you consolidate the implementation for args and aux? There is a big chunk of duplicate code.
| if (idx.mutable_input_nodes().count(nid) == 0) { | ||
| NDArray* arr = static_cast<NDArray*>(*arg); | ||
| NDArray* darr = static_cast<NDArray*>(*grad); | ||
| if (new_shape == arr->shape()) { |
There was a problem hiding this comment.
Please simplify this. There is no need to have a do nothing block.
| << "is more efficient than the reverse." | ||
| << "If you really want to up size, set allow_up_sizing=True " | ||
| << "to enable allocation of new arrays."; | ||
| NDArray* empty_arr = new NDArray(new_shape, arr->ctx(), false, arr->dtype()); |
There was a problem hiding this comment.
This looks like a memory leak. Please use arr.ReshapeAndAlloc(new_shape).
| << "is more efficient than the reverse." | ||
| << "If you really want to up size, set allow_up_sizing=True " | ||
| << "to enable allocation of new arrays."; | ||
| NDArray* empty_arr = new NDArray(new_shape, arr->ctx(), false, arr->dtype()); |
There was a problem hiding this comment.
Same here. ReshapeAndAlloc.
|
Thanks for your comments. |
| provided_arg_shape_data.extend(v) | ||
| provided_arg_shape_idx.append(len(provided_arg_shape_data)) | ||
|
|
||
| args_handle, args = self._symbol._get_ndarray_inputs( |
There was a problem hiding this comment.
I think you can get all the arg/aux/grad arrays from the executor in backend? Is it necessary to prepare them here and pass to the backend again?
|
Could you please review again? I realized that |
| auto it = arg_grad_map_.find(name); | ||
| if (partial_shaping || provided_arg_shapes.count(name) || new_shape == arr.shape()) { | ||
| if (new_shape.Size() > arr.shape().Size()) { | ||
| CHECK(allow_up_sizing) << name << up_sizing_msg.str(); |
There was a problem hiding this comment.
Need better error message
| size_t grad_top = 0; | ||
|
|
||
| std::ostringstream up_sizing_msg, unspecified_msg; | ||
| up_sizing_msg << ": Arg of new shape which is larger than original." |
There was a problem hiding this comment.
<< is expensive. Normal execution doesn't need to construct these long strings.
reminisce
left a comment
There was a problem hiding this comment.
It looks like the existing unit tests have not covered checking whether the reshaped executor and the original executor share NDArrays depending on the new shape sizes. Could you add test cases covering that check? For checking whether two NDArrays are the same in Python, you can use function same_array
| symbol.outputs = g.outputs; | ||
| const nnvm::IndexedGraph& idx = g.indexed_graph(); | ||
| nnvm::ShapeVector arg_shapes(idx.input_nodes().size(), TShape()); | ||
| for (size_t i = 0; i < num_forward_inputs_; ++i) { |
There was a problem hiding this comment.
Call in_args->reserve(num_args) first outside loop? Same for aux_states and arg_grads.
| if (partial_shaping || provided_arg_shapes.count(name) || new_shape == arr.shape()) { | ||
| if (new_shape.Size() > arr.shape().Size()) { | ||
| CHECK(allow_up_sizing) << name << up_sizing_msg.str(); | ||
| in_args->push_back(NDArray(new_shape, arr.ctx(), false, arr.dtype())); |
There was a problem hiding this comment.
Use in_args->emplace_back(new_shape, arr.ctx(), false, arr.dtype()) to avoid constructing temporary copy of NDArray. Same for all the other push_back(ndarray).
| arg_grads->push_back(darr.Reshape(new_shape)); | ||
| grad_req_types.push_back(grad_store_.at(grad_top++).first); | ||
| } else { | ||
| arg_grads->push_back(NDArray()); |
There was a problem hiding this comment.
Use arg_grads->emplace_back().
| *aux_states = &(ret->ret_handles[nd_idx]); | ||
| nd_idx = ret->ret_handles.size(); | ||
| } | ||
| API_END(); |
There was a problem hiding this comment.
delete out here if an exception is thrown?
| TShape(provided_arg_shape_data+provided_arg_shape_idx[i], | ||
| provided_arg_shape_data+provided_arg_shape_idx[i+1])); | ||
| CHECK(p.second) << "Duplicate shapes are provided for argument " | ||
| << provided_arg_shape_names[i] << " in simple_bind"; |
There was a problem hiding this comment.
Is it always simple_bind?
|
unittest for checking
is added in |
|
ping @reminisce @piiswrong |
|
ping @piiswrong |
|
LGTM. Any concerns? @reminisce @eric-haibin-lin |
* move exec.reshape to backend * fix lint * fix lint * fix Symbol._get_ndarray_inputs * update * update * move Reshape as a member function of Executor * address comments
* move exec.reshape to backend * fix lint * fix lint * fix Symbol._get_ndarray_inputs * update * update * move Reshape as a member function of Executor * address comments
* move exec.reshape to backend * fix lint * fix lint * fix Symbol._get_ndarray_inputs * update * update * move Reshape as a member function of Executor * address comments
Description
move exec.reshape to backend
cc @reminisce @eric-haibin-lin @piiswrong
Checklist
Essentials
Please feel free to remove inapplicable items for your PR.
Changes
Comments