// // Copyright © 2017 Arm Ltd. All rights reserved. // See LICENSE file in the project root for full license information. // #include "Network.hpp" #include "Graph.hpp" #include "Layer.hpp" #include "backends/CpuTensorHandle.hpp" #include "backends/WorkloadFactory.hpp" #include "Optimizer.hpp" #include #include #include #include #include #include #include #include #include #include namespace armnn { armnn::INetwork* INetwork::CreateRaw() { return new Network(); } armnn::INetworkPtr INetwork::Create() { return INetworkPtr(CreateRaw(), &INetwork::Destroy); } void INetwork::Destroy(INetwork* network) { delete boost::polymorphic_downcast(network); } Status Network::PrintGraph() { m_Graph->Print(); return Status::Success; } void IOptimizedNetwork::Destroy(IOptimizedNetwork* network) { delete boost::polymorphic_downcast(network); } Status OptimizedNetwork::PrintGraph() { m_Graph->Print(); return Status::Success; } Status OptimizedNetwork::SerializeToDot(std::ostream& stream) const { return m_Graph->SerializeToDot(stream); } IOptimizedNetworkPtr Optimize(const INetwork& inNetwork, const DeviceSpec& deviceSpec) { const Network& network = *boost::polymorphic_downcast(&inNetwork); std::unique_ptr graph = std::make_unique(network.GetGraph()); OptimizedNetwork* optNet = new OptimizedNetwork(std::move(graph)); Optimizer::Optimize(optNet->GetGraph()); // Infer the tensor infos for all output slots. Throws an exception on failure. optNet->GetGraph().InferTensorInfos(); // Assign a compute device for all nodes for (auto&& layer : optNet->GetGraph()) { DataType dataType = layer->GetDataType(); // Default to the user-requested compute device from the Runtime layer->SetComputeDevice(deviceSpec.DefaultComputeDevice); // If the layer is unsupported by this device, fall back to reference std::string reasonIfUnsupported; if (!IWorkloadFactory::IsLayerSupported(*layer, dataType, reasonIfUnsupported)) { BOOST_LOG_TRIVIAL(warning) << "Layer of type " << GetLayerTypeAsCString(layer->GetType()) << " is not supported on requested backend " << layer->GetComputeDevice() << " (reason: " << reasonIfUnsupported << "), falling back to CpuRef backend."; layer->SetComputeDevice(Compute::CpuRef); } BOOST_ASSERT_MSG(IWorkloadFactory::IsLayerSupported(*layer, dataType, reasonIfUnsupported), "Layer has no valid compute device"); } optNet->GetGraph().AddCopyLayers(); return {optNet, &IOptimizedNetwork::Destroy}; } Network::Network() : m_Graph(std::make_unique()) { } Network::~Network() { } IConnectableLayer* Network::AddInputLayer(LayerBindingId id, const char* name) { return m_Graph->AddLayer(id, name); } IConnectableLayer* Network::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor, const ConstTensor& weights, const ConstTensor* biases, const char* name) { if (fullyConnectedDescriptor.m_BiasEnabled && (biases == nullptr)) { throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be NULL"); } const auto layer = m_Graph->AddLayer(fullyConnectedDescriptor, name); layer->m_Weight = std::make_unique(weights); if (fullyConnectedDescriptor.m_BiasEnabled) { layer->m_Bias = std::make_unique(*biases); } return layer; } IConnectableLayer* Network::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const ConstTensor& weights, const char* name) { return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, nullptr, name); } IConnectableLayer* Network::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const ConstTensor& weights, const ConstTensor& biases, const char* name) { return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, &biases, name); } IConnectableLayer* Network::AddConvolution2dLayerImpl(const Convolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const ConstTensor* biases, const char* name) { if (convolution2dDescriptor.m_BiasEnabled && (biases == nullptr)) { throw InvalidArgumentException("AddConvolution2dLayer: biases cannot be NULL"); } const auto layer = m_Graph->AddLayer(convolution2dDescriptor, name); layer->m_Weight = std::make_unique(weights); if (convolution2dDescriptor.m_BiasEnabled) { layer->m_Bias = std::make_unique(*biases); } return layer; } IConnectableLayer* Network::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const char* name) { return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, nullptr, name); } IConnectableLayer* Network::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const ConstTensor& biases, const char* name) { return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, &biases, name); } IConnectableLayer* Network::AddDepthwiseConvolution2dLayerImpl( const DepthwiseConvolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const ConstTensor* biases, const char* name) { if (convolution2dDescriptor.m_BiasEnabled && (biases == nullptr)) { throw InvalidArgumentException("AddDepthwiseConvolution2dLayer: biases cannot be NULL"); } const auto layer = m_Graph->AddLayer(convolution2dDescriptor, name); layer->m_Weight = std::make_unique(weights); if (convolution2dDescriptor.m_BiasEnabled) { layer->m_Bias = std::make_unique(*biases); } return layer; } IConnectableLayer* Network::AddDepthwiseConvolution2dLayer( const DepthwiseConvolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const char* name) { return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, nullptr, name); } IConnectableLayer* Network::AddDepthwiseConvolution2dLayer( const DepthwiseConvolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const ConstTensor& biases, const char* name) { return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, &biases, name); } IConnectableLayer* Network::AddPermuteLayer(const PermuteDescriptor& permuteDescriptor, const char* name) { return m_Graph->AddLayer(permuteDescriptor, name); } IConnectableLayer* Network::AddPooling2dLayer(const Pooling2dDescriptor& pooling2dDescriptor, const char* name) { return m_Graph->AddLayer(pooling2dDescriptor, name); } IConnectableLayer* Network::AddActivationLayer(const ActivationDescriptor& activationDescriptor, const char* name) { return m_Graph->AddLayer(activationDescriptor, name); } IConnectableLayer* Network::AddNormalizationLayer(const NormalizationDescriptor& normalizationDescriptor, const char* name) { return m_Graph->AddLayer(normalizationDescriptor, name); } IConnectableLayer* Network::AddSoftmaxLayer(const SoftmaxDescriptor& softmaxDescriptor, const char* name) { return m_Graph->AddLayer(softmaxDescriptor, name); } IConnectableLayer* Network::AddSplitterLayer(const ViewsDescriptor& splitterDescriptor, const char* name) { return m_Graph->AddLayer(splitterDescriptor, name); } IConnectableLayer* Network::AddMergerLayer(const OriginsDescriptor& mergerDescriptor, const char* name) { return m_Graph->AddLayer(mergerDescriptor, name); } IConnectableLayer* Network::AddAdditionLayer(const char* name) { return m_Graph->AddLayer(name); } IConnectableLayer* Network::AddMultiplicationLayer(const char* name) { return m_Graph->AddLayer(name); } IConnectableLayer* Network::AddOutputLayer(LayerBindingId id, const char* name) { return m_Graph->AddLayer(id, name); } IConnectableLayer* Network::AddBatchNormalizationLayer(const BatchNormalizationDescriptor& desc, const ConstTensor& mean, const ConstTensor& variance, const ConstTensor& beta, const ConstTensor& gamma, const char* name) { const auto layer = m_Graph->AddLayer(desc, name); layer->m_Mean = std::make_unique(mean); layer->m_Variance = std::make_unique(variance); layer->m_Beta = std::make_unique(beta); layer->m_Gamma = std::make_unique(gamma); return layer; } IConnectableLayer* Network::AddResizeBilinearLayer(const ResizeBilinearDescriptor& resizeDescriptor, const char* name) { return m_Graph->AddLayer(resizeDescriptor,name); } IConnectableLayer* Network::AddL2NormalizationLayer(const char* name) { return m_Graph->AddLayer(name); } IConnectableLayer* Network::AddConstantLayer(const ConstTensor& input, const char* name) { return m_Graph->AddLayer(std::make_shared(input), name); } IConnectableLayer* Network::AddReshapeLayer(const ReshapeDescriptor& reshapeDescriptor, const char* name) { return m_Graph->AddLayer(reshapeDescriptor, name); } IConnectableLayer* Network::AddFloorLayer(const char* name) { return m_Graph->AddLayer(name); } OptimizedNetwork::OptimizedNetwork(std::unique_ptr graph) : m_Graph(std::move(graph)) { } OptimizedNetwork::~OptimizedNetwork() { } } // namespace armnn