diff options
Diffstat (limited to 'runtime/neurun/core/src/util')
-rw-r--r-- | runtime/neurun/core/src/util/ConfigSource.cc | 116 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/EnvConfigSource.cc | 40 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/EventCollectorGlobal.cc | 86 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/GeneralConfigSource.cc | 45 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/Padding.cc | 119 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/ShapeInference.cc | 200 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/Utils.cc | 68 | ||||
-rw-r--r-- | runtime/neurun/core/src/util/logging.cc | 7 |
8 files changed, 681 insertions, 0 deletions
diff --git a/runtime/neurun/core/src/util/ConfigSource.cc b/runtime/neurun/core/src/util/ConfigSource.cc new file mode 100644 index 000000000..7d57ec178 --- /dev/null +++ b/runtime/neurun/core/src/util/ConfigSource.cc @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/ConfigSource.h" +#include "util/GeneralConfigSource.h" +#include "util/EnvConfigSource.h" + +#include <array> +#include <algorithm> +#include <cassert> + +#include "cpp14/memory.h" + +namespace neurun +{ +namespace util +{ + +static std::unique_ptr<IConfigSource> _source; + +void config_source(std::unique_ptr<IConfigSource> &&source) { _source = std::move(source); } + +static IConfigSource *config_source() +{ + if (!_source) + { +#ifdef ENVVAR_FOR_DEFAULT_CONFIG + // Default ConfigSource is EnvConfigSource + _source = nnfw::cpp14::make_unique<EnvConfigSource>(); +#else + _source = nnfw::cpp14::make_unique<GeneralConfigSource>(); +#endif // ENVVAR_FOR_DEFAULT_CONFIG + } + return _source.get(); +} + +static std::string getConfigOrDefault(const std::string &key) +{ + static std::unordered_map<std::string, std::string> defaults; + if (defaults.empty()) + { +#define CONFIG(Name, Type, Default) \ + { \ + auto name = std::string{#Name}; \ + defaults.emplace(name, std::string{Default}); \ + } + +#include "util/Config.lst" + +#undef CONFIG + } + + // Treat empty string and absence of the value to be the same + auto ret = config_source()->get(key); + if (ret.empty()) + { + auto itr = defaults.find(key); + if (itr != defaults.end()) + { + // Return the default value if exists + ret = itr->second; + } + } + + return ret; +} + +bool getConfigBool(const std::string &key) +{ + auto raw = getConfigOrDefault(key); + static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"}; + auto false_found = std::find(false_list.begin(), false_list.end(), raw); + + return (false_found == false_list.end()); +} + +int getConfigInt(const std::string &key) +{ + auto raw = getConfigOrDefault(key); + return std::stoi(raw); +} + +std::string getConfigString(const std::string &key) { return getConfigOrDefault(key); } + +} // namespace util +} // namespace neurun + +namespace neurun +{ +namespace util +{ +namespace config +{ + +#define CONFIG(Name, Type, Default) const char *Name = #Name; + +#include "util/Config.lst" + +#undef CONFIG + +} // namespace config +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/EnvConfigSource.cc b/runtime/neurun/core/src/util/EnvConfigSource.cc new file mode 100644 index 000000000..52a6bf2a4 --- /dev/null +++ b/runtime/neurun/core/src/util/EnvConfigSource.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/EnvConfigSource.h" + +#include <cstdlib> + +namespace neurun +{ +namespace util +{ + +std::string EnvConfigSource::get(const std::string &key) const +{ + const char *value = std::getenv(key.c_str()); + if (value != nullptr) + { + return value; + } + else + { + return GeneralConfigSource::get(key); + } +} + +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/EventCollectorGlobal.cc b/runtime/neurun/core/src/util/EventCollectorGlobal.cc new file mode 100644 index 000000000..6c3594f5f --- /dev/null +++ b/runtime/neurun/core/src/util/EventCollectorGlobal.cc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/EventCollectorGlobal.h" + +#include <cassert> +#include <fstream> + +#include "util/ConfigSource.h" + +namespace neurun +{ +namespace util +{ + +EventCollectorGlobal::EventCollectorGlobal() : _recorder{}, _collector{&_recorder} +{ + // DO NOTHING +} + +EventCollectorGlobal::~EventCollectorGlobal() +{ + auto path = util::getConfigString(util::config::TRACE_FILEPATH); + if (!path.empty()) + { + // TODO Need better way for saved file path than just appending ".global" to the trace file path + std::ofstream ofs{path + ".global"}; + _recorder.writeToFile(ofs); + } +} + +EventCollectorGlobal &EventCollectorGlobal::get() +{ + static EventCollectorGlobal instance; + return instance; +} + +EventDurationBlock::EventDurationBlock(const std::string &tag) : _tag{tag} +{ + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag}); +} +EventDurationBlock::~EventDurationBlock() +{ + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag}); +} + +EventDurationManual::EventDurationManual(const std::string &tag) : _tag{tag}, _pair{true} {} + +EventDurationManual::~EventDurationManual() +{ + // Check if it has called begin-end pair + assert(_pair); +} + +void EventDurationManual::begin() +{ + _pair = false; + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag}); +} + +void EventDurationManual::end() +{ + assert(!_pair); + _pair = true; + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag}); +} + +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/GeneralConfigSource.cc b/runtime/neurun/core/src/util/GeneralConfigSource.cc new file mode 100644 index 000000000..084e4c109 --- /dev/null +++ b/runtime/neurun/core/src/util/GeneralConfigSource.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/GeneralConfigSource.h" +#include "util/logging.h" + +namespace neurun +{ +namespace util +{ + +std::string GeneralConfigSource::get(const std::string &key) const +{ + auto itr = _map.find(key); + if (itr == _map.end()) + { + return ""; + } + else + { + return itr->second; + } +} + +void GeneralConfigSource::set(const std::string &key, const std::string &val) +{ + VERBOSE(GeneralConfigSource) << key << " : " << val << std::endl; + _map[key] = val; +} + +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/Padding.cc b/runtime/neurun/core/src/util/Padding.cc new file mode 100644 index 000000000..2e2202b58 --- /dev/null +++ b/runtime/neurun/core/src/util/Padding.cc @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Padding.h" +#include "util/Utils.h" + +#include <algorithm> +#include <stdexcept> + +namespace neurun +{ +namespace util +{ + +ir::ExplicitPadding validPadding(void) +{ + // + // ANEURALNETWORKS_PADDING_VALID + // + // VALID padding. No padding. + // + // When the input size is not evenly divisible by the filter size, + // the input at the end that could not fill the whole filter tile + // will simply be ignored. + // + ir::ExplicitPadding padding; + + padding.top = 0; + padding.bottom = 0; + padding.left = 0; + padding.right = 0; + + return padding; +} + +ir::ExplicitPadding samePaddingUsingIFM(const ir::FeatureShape &ifm_shape, const ir::Stride &stride, + uint32_t kw, uint32_t kh) +{ + ir::ExplicitPadding padding; + + // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec) + // + // SAME padding. Padding on both ends are the "same": + // + // padding_to_beginning = total_padding / 2 + // padding_to_end = (total_padding + 1)/2. + // + const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical; + const int32_t horizontal_expected_output = + (ifm_shape.W + stride.horizontal - 1) / stride.horizontal; + + const int32_t vertical_needed_input = (vertical_expected_output - 1) * stride.vertical + kh; + const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H); + + const int32_t horizontal_needed_input = (horizontal_expected_output - 1) * stride.horizontal + kw; + const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W); + + padding.top = vertical_total_padding / 2; + padding.bottom = (vertical_total_padding + 1) / 2; + padding.left = horizontal_total_padding / 2; + padding.right = (horizontal_total_padding + 1) / 2; + + return padding; +} + +ir::ExplicitPadding samePadding(const ir::FeatureShape &ifm_shape, + const ir::FeatureShape &ofm_shape, const ir::Stride &stride, + uint32_t kw, uint32_t kh) +{ + const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical; + const int32_t horizontal_expected_output = + (ifm_shape.W + stride.horizontal - 1) / stride.horizontal; + assert(vertical_expected_output == ofm_shape.H); + assert(horizontal_expected_output == ofm_shape.W); + + UNUSED_RELEASE(ofm_shape); + UNUSED_RELEASE(vertical_expected_output); + UNUSED_RELEASE(horizontal_expected_output); + + return samePaddingUsingIFM(ifm_shape, stride, kw, kh); +} + +ir::ExplicitPadding calculatePadding(const ir::Padding &padding, const ir::FeatureShape &ifm_shape, + const ir::FeatureShape &ofm_shape, const ir::Stride &stride, + uint32_t kw, uint32_t kh) +{ + if (padding.type == ir::PaddingType::EXPLICIT) + { + return padding.param; + } + else if (padding.type == ir::PaddingType::SAME) + { + return samePadding(ifm_shape, ofm_shape, stride, kw, kh); + } + else if (padding.type == ir::PaddingType::VALID) + { + return validPadding(); + } + else + { + throw std::runtime_error{"Cannot handle padding type"}; + } +} + +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/ShapeInference.cc b/runtime/neurun/core/src/util/ShapeInference.cc new file mode 100644 index 000000000..6fa29e7d8 --- /dev/null +++ b/runtime/neurun/core/src/util/ShapeInference.cc @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Utils.h" +#include "ir/InternalType.h" +#include "ir/Shape.h" +#include "ir/operation/AvgPool2D.h" +#include "ir/operation/MaxPool2D.h" +#include "util/ShapeInference.h" + +namespace neurun +{ +namespace shape_inference +{ + +// +// Helper functions +// + +namespace +{ + +template <typename T, typename U> +typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value, + typename std::common_type<T, U>::type>::type +ceil_div(T dividend, U divisor) +{ + assert(dividend > 0 && divisor > 0 && "this implementations is for positive numbers only"); + return (dividend + divisor - 1) / divisor; +} + +// Calculate the result of broadcast of two shapes +ir::Shape broadcastShapes(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape) +{ + ir::Shape out_shape; + auto max_rank = std::max(lhs_shape.rank(), rhs_shape.rank()); + + for (int idx = 0; idx < max_rank; ++idx) + { + // Go over operands dimensions from right to left + int lhs_idx = lhs_shape.rank() - idx - 1; + int rhs_idx = rhs_shape.rank() - idx - 1; + + int32_t lhs_dim = lhs_idx >= 0 ? lhs_shape.dim(lhs_idx) : 1; + int32_t rhs_dim = rhs_idx >= 0 ? rhs_shape.dim(rhs_idx) : 1; + + if (lhs_dim != 1 && rhs_dim != 1 && lhs_dim != rhs_dim) + throw std::runtime_error("Incompatible shapes for broadcast"); + + out_shape.prepend(std::max(lhs_dim, rhs_dim)); + } + + return out_shape; +} + +// Calculate output height and width of convolution-like operation +std::pair<int, int> calcConvLikeHeightAndWidth(const int in_h, const int in_w, const int ker_h, + const int ker_w, const ir::Padding pad, + const ir::Stride stride) +{ + int32_t out_h = 0, out_w = 0; + + switch (pad.type) + { + case ir::PaddingType::SAME: + out_h = ceil_div(in_h, stride.vertical); + out_w = ceil_div(in_w, stride.horizontal); + break; + case ir::PaddingType::VALID: + out_h = ceil_div(in_h - ker_h + 1, stride.vertical); + out_w = ceil_div(in_w - ker_w + 1, stride.horizontal); + break; + case ir::PaddingType::EXPLICIT: + out_h = (in_h + pad.param.top + pad.param.bottom - ker_h) / stride.vertical + 1; + out_w = (in_w + pad.param.left + pad.param.right - ker_w) / stride.horizontal + 1; + break; + default: + assert(false); + } + + return {out_h, out_w}; +} + +} // namespace + +// +// Shape inference +// + +Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape) +{ + return {broadcastShapes(lhs_shape, rhs_shape)}; +} + +Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param ¶m, + const ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw, + param.padding, param.stride); + // Pooling don't change number of channels and batch size + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}}; +} + +Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param ¶m) +{ + const int32_t concat_axis = param.axis; + const auto &first_in_shape = in_shapes[0]; + + // Check that all shapes are equal except for concat axis dimension + for (const auto &in_shape : in_shapes) + { + assert(in_shape.rank() == first_in_shape.rank()); + for (int64_t dim_idx = 0; dim_idx < in_shape.rank(); ++dim_idx) + assert(dim_idx == concat_axis || in_shape.dim(dim_idx) == first_in_shape.dim(dim_idx)); + } + + // Calculate output shape + ir::Shape out_shape(first_in_shape); + out_shape.dim(concat_axis) = 0; + for (const auto &in_shape : in_shapes) + out_shape.dim(concat_axis) += in_shape.dim(concat_axis); + return {out_shape}; +} + +Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param ¶m, + const ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw, + param.padding, param.stride); + // Pooling don't change number of channels and batch size + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}}; +} + +Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::Conv2D::Param ¶m, ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in] + auto kf_shape = ker_shape.asFeature(layout); + assert(ifm_shape.C == kf_shape.C); + + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W, + param.padding, param.stride); + + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.N}}; +} + +Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::DepthwiseConv2D::Param ¶m, + ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + + // Kernel format is [1, kernel_height, kernel_width, depth_out] + auto kf_shape = ker_shape.asFeature(layout); + assert(kf_shape.C == static_cast<int32_t>(ifm_shape.C * param.multiplier)); + assert(kf_shape.N == 1); + + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W, + param.padding, param.stride); + + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.C}}; +} + +Shapes inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape) +{ + assert(in_shape.rank() >= 2); + assert(ker_shape.rank() == 2); + + const auto input_size_with_batch = in_shape.num_elements(); + const auto num_units = ker_shape.dim(0); + const auto input_size = ker_shape.dim(1); + const auto batch_size = input_size_with_batch / input_size; + assert(input_size_with_batch % input_size == 0); + + return {{ir::Shape({static_cast<int32_t>(batch_size), num_units})}}; +} + +} // namespace shape_inference +} // namespace neurun diff --git a/runtime/neurun/core/src/util/Utils.cc b/runtime/neurun/core/src/util/Utils.cc new file mode 100644 index 000000000..1e24e28d4 --- /dev/null +++ b/runtime/neurun/core/src/util/Utils.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Utils.h" + +#include <cassert> + +namespace neurun +{ +namespace util +{ + +const char *to_string(const ir::PaddingType type) +{ + assert((type == ir::PaddingType::EXPLICIT) || (type == ir::PaddingType::SAME) || + (type == ir::PaddingType::VALID)); + + switch (type) + { + case ir::PaddingType::EXPLICIT: + return "Padding::EXPLICIT"; + case ir::PaddingType::SAME: + return "Padding::SAME"; + case ir::PaddingType::VALID: + return "Padding::VALID"; + } + + return nullptr; +} + +Coordinates convertCoordinates(const Coordinates &from_coordinates, ir::Layout from_layout, + ir::Layout to_layout) +{ + assert(from_coordinates.size() == 4); + Coordinates to{from_coordinates}; + if (from_layout == ir::Layout::NHWC && to_layout == ir::Layout::NCHW) + { + to.set(0, from_coordinates[0]); + to.set(1, from_coordinates[3]); + to.set(2, from_coordinates[1]); + to.set(3, from_coordinates[2]); + } + else if (from_layout == ir::Layout::NCHW && to_layout == ir::Layout::NHWC) + { + to.set(0, from_coordinates[0]); + to.set(1, from_coordinates[2]); + to.set(2, from_coordinates[3]); + to.set(3, from_coordinates[1]); + } + + return to; +} + +} // namespace util +} // namespace neurun diff --git a/runtime/neurun/core/src/util/logging.cc b/runtime/neurun/core/src/util/logging.cc new file mode 100644 index 000000000..c23e2b53c --- /dev/null +++ b/runtime/neurun/core/src/util/logging.cc @@ -0,0 +1,7 @@ +#include "util/logging.h" + +neurun::util::logging::Context &neurun::util::logging::Context::get() noexcept +{ + static Context ctx; + return ctx; +} |