diff options
author | Georgios Pinitas <georgios.pinitas@arm.com> | 2017-12-22 15:27:52 +0000 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-11-02 16:49:16 +0000 |
commit | d8734b55d89f05901ba9a75349761a9c955d9243 (patch) | |
tree | e23d53a0fb73251f7416993e4d3a7241e533e79e /src/graph2/GraphBuilder.cpp | |
parent | 7390e05561a5c49306ebbf2eb2dcb1848546f201 (diff) | |
download | ComputeLibrary-d8734b55d89f05901ba9a75349761a9c955d9243.tar.gz |
COMPMID-793 : Add graph intermediate representation
Change-Id: Ic1685de4e19e0ac79669ef2da64e1dc96c7ea0bf
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/115248
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Diffstat (limited to 'src/graph2/GraphBuilder.cpp')
-rw-r--r-- | src/graph2/GraphBuilder.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/graph2/GraphBuilder.cpp b/src/graph2/GraphBuilder.cpp new file mode 100644 index 0000000000..aaf70c4e61 --- /dev/null +++ b/src/graph2/GraphBuilder.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/graph2/GraphBuilder.h" + +#include "arm_compute/graph2/Graph.h" +#include "arm_compute/graph2/Utils.h" +#include "arm_compute/graph2/algorithms/BFS.h" +#include "arm_compute/graph2/nodes/Nodes.h" + +#define CHECK_NODEIDX_PAIR(pair, g) \ + ARM_COMPUTE_ERROR_ON(((pair).node_id >= (g).nodes().size()) || ((g).node((pair).node_id) == nullptr) || ((pair).index >= (g).node((pair).node_id)->num_outputs())); + +namespace arm_compute +{ +namespace graph2 +{ +namespace +{ +Status set_node_params(Graph &g, NodeID nid, NodeParams ¶ms) +{ + INode *node = g.node(nid); + ARM_COMPUTE_RETURN_ERROR_ON(!node); + + node->set_common_node_parameters(params); + + return Status{}; +} +Status set_accessor_on_node(Graph &g, NodeID nid, bool is_output, size_t idx, ITensorAccessorUPtr accessor) +{ + INode *node = g.node(nid); + ARM_COMPUTE_RETURN_ERROR_ON(!node); + + Tensor *tensor = is_output ? node->output(idx) : node->input(idx); + ARM_COMPUTE_RETURN_ERROR_ON(!tensor); + + tensor->set_accessor(std::move(accessor)); + + return Status{}; +} + +NodeID add_const_node_with_name(Graph &g, NodeParams params, const std::string &name, TensorDescriptor desc, ITensorAccessorUPtr accessor) +{ + params.name = params.name.empty() ? "" : params.name + name; + auto nid = GraphBuilder::add_const_node(g, params, desc, std::move(accessor)); + set_node_params(g, nid, params); + return nid; +} +} // namespace + +NodeID GraphBuilder::add_const_node(Graph &g, NodeParams params, TensorDescriptor desc, ITensorAccessorUPtr accessor) +{ + auto nid = g.add_node<ConstNode>(desc); + set_node_params(g, nid, params); + set_accessor_on_node(g, nid, true, 0, std::move(accessor)); + return nid; +} + +NodeID GraphBuilder::add_input_node(Graph &g, NodeParams params, TensorDescriptor desc, ITensorAccessorUPtr accessor) +{ + auto nid = g.add_node<InputNode>(desc); + set_node_params(g, nid, params); + set_accessor_on_node(g, nid, true, 0, std::move(accessor)); + return nid; +} + +NodeID GraphBuilder::add_output_node(Graph &g, NodeParams params, NodeIdxPair input, ITensorAccessorUPtr accessor) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<OutputNode>(); + g.add_connection(input.node_id, input.index, nid, 0); + set_node_params(g, nid, params); + set_accessor_on_node(g, nid, false, 0, std::move(accessor)); + + return nid; +} + +NodeID GraphBuilder::add_activation_node(Graph &g, NodeParams params, NodeIdxPair input, ActivationLayerInfo act_info) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<ActivationLayerNode>(act_info); + g.add_connection(input.node_id, input.index, nid, 0); + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_batch_normalization_node(Graph &g, NodeParams params, NodeIdxPair input, float epsilon, + ITensorAccessorUPtr mean_accessor, ITensorAccessorUPtr var_accessor, + ITensorAccessorUPtr beta_accessor, ITensorAccessorUPtr gamma_accessor) +{ + CHECK_NODEIDX_PAIR(input, g); + + bool has_beta = (beta_accessor != nullptr); + bool has_gamma = (gamma_accessor != nullptr); + + // Get input tensor descriptor + const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]); + + // Calculate Common Descriptor + TensorDescriptor common_desc = input_tensor_desc; + common_desc.shape = TensorShape(common_desc.shape.z()); + + // Create mean and nodes + auto mean_nid = add_const_node_with_name(g, params, "Mean", common_desc, std::move(mean_accessor)); + auto var_nid = add_const_node_with_name(g, params, "Variance", common_desc, std::move(var_accessor)); + + // Create beta node + NodeID beta_nid = EmptyNodeID; + if(has_beta) + { + beta_nid = add_const_node_with_name(g, params, "Beta", common_desc, std::move(beta_accessor)); + } + + // Create gamma node + NodeID gamma_nid = EmptyNodeID; + if(has_gamma) + { + gamma_nid = add_const_node_with_name(g, params, "Gamma", common_desc, std::move(gamma_accessor)); + } + + // Create batch normalization node and add connections + NodeID batch_norm_nid = g.add_node<BatchNormalizationLayerNode>(epsilon); + g.add_connection(input.node_id, input.index, batch_norm_nid, 0); + g.add_connection(mean_nid, 0, batch_norm_nid, 1); + g.add_connection(var_nid, 0, batch_norm_nid, 2); + if(has_beta) + { + g.add_connection(beta_nid, 0, batch_norm_nid, 3); + } + if(has_gamma) + { + g.add_connection(gamma_nid, 0, batch_norm_nid, 4); + } + set_node_params(g, batch_norm_nid, params); + + return batch_norm_nid; +} + +NodeID GraphBuilder::add_convolution_node(Graph &g, NodeParams params, NodeIdxPair input, + Size2D kernel_spatial_extend, unsigned int depth, PadStrideInfo conv_info, + ConvolutionMethod method, + ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor) +{ + CHECK_NODEIDX_PAIR(input, g); + ARM_COMPUTE_ERROR_ON(depth == 0); + ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0)); + + bool has_bias = (bias_accessor != nullptr); + + // Get input tensor descriptor + const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]); + + // Create weights node + TensorDescriptor w_desc = input_tensor_desc; + w_desc.shape = TensorShape(kernel_spatial_extend.width, kernel_spatial_extend.height, w_desc.shape.z(), depth); + NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor)); + + // Create bias nodes + NodeID b_nid = EmptyNodeID; + if(has_bias) + { + TensorDescriptor b_desc = input_tensor_desc; + b_desc.shape = TensorShape(depth); + b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor)); + } + + // Create convolution node and connect + NodeID conv_nid = g.add_node<ConvolutionLayerNode>(conv_info, method); + g.add_connection(input.node_id, input.index, conv_nid, 0); + g.add_connection(w_nid, 0, conv_nid, 1); + if(has_bias) + { + g.add_connection(b_nid, 0, conv_nid, 2); + } + set_node_params(g, conv_nid, params); + + return conv_nid; +} + +NodeID GraphBuilder::add_depth_concatenate_node(Graph &g, NodeParams params, std::vector<NodeIdxPair> inputs) +{ + ARM_COMPUTE_ERROR_ON(inputs.size() == 0); + + NodeID nid = g.add_node<DepthConcatenateLayerNode>(inputs.size()); + + unsigned int i = 0; + for(const auto &input : inputs) + { + CHECK_NODEIDX_PAIR(input, g); + g.add_connection(input.node_id, input.index, nid, i++); + } + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_depthwise_convolution_node(Graph &g, NodeParams params, NodeIdxPair input, Size2D kernel_spatial_extend, PadStrideInfo conv_info, + DepthwiseConvolutionMethod method, + ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor) +{ + CHECK_NODEIDX_PAIR(input, g); + ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0)); + + bool has_bias = (bias_accessor != nullptr); + + // Get input tensor descriptor + const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]); + + // Create weights node + TensorDescriptor w_desc = input_tensor_desc; + w_desc.shape = TensorShape(kernel_spatial_extend.width, kernel_spatial_extend.height, w_desc.shape.z()); + NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor)); + + // Create bias nodes + NodeID b_nid = EmptyNodeID; + if(has_bias) + { + TensorDescriptor b_desc = input_tensor_desc; + b_desc.shape = TensorShape(b_desc.shape.z()); + b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor)); + } + + // Create convolution node and connect + NodeID conv_nid = g.add_node<DepthwiseConvolutionLayerNode>(conv_info, method); + g.add_connection(input.node_id, input.index, conv_nid, 0); + g.add_connection(w_nid, 0, conv_nid, 1); + if(has_bias) + { + g.add_connection(b_nid, 0, conv_nid, 2); + } + set_node_params(g, conv_nid, params); + + return conv_nid; +} + +NodeID GraphBuilder::add_elementwise_node(Graph &g, NodeParams params, NodeIdxPair input0, NodeIdxPair input1, EltwiseOperation operation) +{ + CHECK_NODEIDX_PAIR(input0, g); + CHECK_NODEIDX_PAIR(input1, g); + + NodeID nid = g.add_node<EltwiseLayerNode>(operation); + + g.add_connection(input0.node_id, input0.index, nid, 0); + g.add_connection(input1.node_id, input1.index, nid, 1); + + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_flatten_node(Graph &g, NodeParams params, NodeIdxPair input) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<FlattenLayerNode>(); + g.add_connection(input.node_id, input.index, nid, 0); + + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_fully_connected_layer(Graph &g, NodeParams params, NodeIdxPair input, unsigned int num_outputs, + ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor) +{ + CHECK_NODEIDX_PAIR(input, g); + ARM_COMPUTE_ERROR_ON(num_outputs == 0); + + bool has_bias = (bias_accessor != nullptr); + + // Get input tensor descriptor + const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]); + + // Create weights node + TensorDescriptor w_desc = input_tensor_desc; + w_desc.shape = FullyConnectedLayerNode::compute_weights_shape(input_tensor_desc.shape, num_outputs); + NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor)); + + // Create bias nodes + NodeID b_nid = EmptyNodeID; + if(has_bias) + { + TensorDescriptor b_desc = input_tensor_desc; + b_desc.shape = TensorShape(num_outputs); + b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor)); + } + + // Create convolution node and connect + NodeID fc_nid = g.add_node<FullyConnectedLayerNode>(num_outputs); + g.add_connection(input.node_id, input.index, fc_nid, 0); + g.add_connection(w_nid, 0, fc_nid, 1); + if(has_bias) + { + g.add_connection(b_nid, 0, fc_nid, 2); + } + + set_node_params(g, fc_nid, params); + + return fc_nid; +} + +NodeID GraphBuilder::add_normalization_node(Graph &g, NodeParams params, NodeIdxPair input, NormalizationLayerInfo norm_info) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<NormalizationLayerNode>(norm_info); + g.add_connection(input.node_id, input.index, nid, 0); + + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_pooling_node(Graph &g, NodeParams params, NodeIdxPair input, PoolingLayerInfo pool_info) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<PoolingLayerNode>(pool_info); + g.add_connection(input.node_id, input.index, nid, 0); + + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_reshape_node(Graph &g, NodeParams params, NodeIdxPair input, TensorShape shape) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<ReshapeLayerNode>(shape); + g.add_connection(input.node_id, input.index, nid, 0); + + set_node_params(g, nid, params); + + return nid; +} + +NodeID GraphBuilder::add_softmax_node(Graph &g, NodeParams params, NodeIdxPair input, float beta) +{ + CHECK_NODEIDX_PAIR(input, g); + + NodeID nid = g.add_node<SoftmaxLayerNode>(beta); + g.add_connection(input.node_id, input.index, nid, 0); + + set_node_params(g, nid, params); + + return nid; +} +} // namespace graph2 +} // namespace arm_compute
\ No newline at end of file |