leezu commented on a change in pull request #17530: Add deferred compute support URL: https://github.com/apache/incubator-mxnet/pull/17530#discussion_r379850186
########## File path: src/imperative/imperative.cc ########## @@ -273,8 +288,126 @@ void Imperative::RecordOp( info.outputs.back().dtype_ = outputs[i]->dtype(); info.outputs.back().storage_type_ = outputs[i]->storage_type(); } - outputs[i]->entry_ = nnvm::NodeEntry{node, i, 0}; + outputs[i]->autograd_entry_ = nnvm::NodeEntry{node, i, 0}; + } +} + +void Imperative::RecordDeferredCompute(nnvm::NodeAttrs &&attrs, + const std::vector<NDArray *> &inputs, + const std::vector<NDArray *> &outputs) { + CHECK(!is_recording()) + << "Autograd recording is not supported during deferred compute mode."; + + for (const NDArray *output : outputs) { + CHECK(DCInfo::IsNone(*output)) + << "Inplace operations (+=, -=, x[:]=, etc) are not supported when " + << "recording in deferred compute mode."; + // However, an inplace operation on a non-deferred compute array inside + // deferred compute scope will work. For example: + // a = mx.nd.arange(10) + // with dc.context(): + // a[:5] = 0 + } + DispatchMode dispatch_mode = DispatchMode::kUndefined; + Context default_ctx = Context::CPU(); + Context ctx = imperative::GetContext(attrs, inputs, outputs, default_ctx); + imperative::SetShapeType(ctx, attrs, inputs, outputs, &dispatch_mode); + + nnvm::ObjectPtr node = nnvm::Node::Create(); + node->inputs.reserve(inputs.size()); + // Get NodeEntries for inputs + for (const NDArray *array : inputs) { + // For non-deferred compute arrays, array->deferredcompute_entry_ will be + // nullptr. We handle this in in GetDeferredComputeSymbol + node->inputs.emplace_back(array->deferredcompute_entry_); + } + node->attrs = std::move(attrs); + // Need to support NameManager in imperative API to better name node->attrs.name + node->attrs.name = "node_" + std::to_string(node_count_++); + DCInfo::Create(node, inputs, outputs); + + for (uint32_t i = 0; i < outputs.size(); ++i) { + outputs[i]->deferredcompute_entry_ = nnvm::NodeEntry{node, i, 0}; + } +} + +nnvm::Symbol Imperative::GetDeferredComputeSymbol( + const std::vector<std::pair<NDArray *, std::string>> &inputs, + const std::vector<NDArray *> &outputs + ) { + Symbol s; + s.outputs.reserve(outputs.size()); + for (NDArray * ndoutput : outputs) { + CHECK(!Imperative::DCInfo::IsNone(*ndoutput)) + << "ValueError: output_arrays for GetDeferredComputeSymbol " + << "must have a deferred compute history associated with them."; + s.outputs.emplace_back(ndoutput->deferredcompute_entry_); } + std::unordered_map<NDArray *, nnvm::ObjectPtr> ndinput_to_variable; + std::unordered_set<const NDArray *> missing_inputs; + auto add_symbol_variables = [&inputs, &ndinput_to_variable, + &missing_inputs](const nnvm::ObjectPtr &node) { + if (node == nullptr) { + // This (nonexistant) "Node" belongs to an array created outside of deferred compute scope. + return; + } + + // Check if node has any non-deferred compute inputs + for (uint32_t i = 0; i < node->inputs.size(); i++) { + nnvm::NodeEntry &node_entry = node->inputs[i]; + if (node_entry.node == nullptr || node_entry.node->is_variable()) { + // Node has non-deferred compute input (nullptr). Find the corresponding + // NDArray and create a variable for it. If GetDeferredComputeSymbol has + // been called before, a variable already exists and only the name needs + // to be updated. + Imperative::DCInfo &dcinfo = Imperative::DCInfo::Get(node); + const NDArray *array = dcinfo.input_handles_.at(i); + + // Make sure this array is part of GetDeferredComputeSymbol inputs + auto is_equal = [array](const std::pair<NDArray *, std::string> &input) { + return array == std::get<0>(input); + }; + + // std::vector<std::pair<NDArray *, std::string>>::iterator input_search = Review comment: That one shouldn't have been a comment. I didn't figure out the correct type at the time of writing and used auto as intermediate solution. Correct type is `std::vector<std::pair<NDArray *, std::string>>::const_iterator` (note the `const`) and is used now. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services