aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorIsabella Gottardi <isabella.gottardi@arm.com>2018-11-27 08:51:10 +0000
committerIsabella Gottardi <isabella.gottardi@arm.com>2018-12-13 11:21:59 +0000
commit7234ed8c3d07c76963eb3bce9530994421ad7e67 (patch)
tree6834d5fc3cc23eb47bcfad3a4191d91c87c8f9e0 /utils
parent0e7210de821a7d1164017b8b9e11b53805185b25 (diff)
downloadComputeLibrary-7234ed8c3d07c76963eb3bce9530994421ad7e67.tar.gz
COMPMID-1808: Add Detection Output Layer to the GraphAPI
COMPMID-1710: Integrate Detection ouput in MobilenetSSD graph example Change-Id: I384d1eb492ef14ece58f2023ad7bbc16f834450b Reviewed-on: https://review.mlplatform.org/356 Tested-by: Arm Jenkins <bsgcomp@arm.com> Reviewed-by: Pablo Marquez <pablo.tello@arm.com> Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
Diffstat (limited to 'utils')
-rw-r--r--utils/GraphUtils.cpp71
-rw-r--r--utils/GraphUtils.h63
2 files changed, 134 insertions, 0 deletions
diff --git a/utils/GraphUtils.cpp b/utils/GraphUtils.cpp
index 2f1df7aef2..ab2c753eac 100644
--- a/utils/GraphUtils.cpp
+++ b/utils/GraphUtils.cpp
@@ -420,6 +420,77 @@ void ValidationOutputAccessor::report_top_n(size_t top_n, size_t total_samples,
_output_stream << "Accuracy : " << accuracy << std::endl;
}
+DetectionOutputAccessor::DetectionOutputAccessor(const std::string &labels_path, std::vector<TensorShape> &imgs_tensor_shapes, std::ostream &output_stream)
+ : _labels(), _tensor_shapes(std::move(imgs_tensor_shapes)), _output_stream(output_stream)
+{
+ _labels.clear();
+
+ std::ifstream ifs;
+
+ try
+ {
+ ifs.exceptions(std::ifstream::badbit);
+ ifs.open(labels_path, std::ios::in | std::ios::binary);
+
+ for(std::string line; !std::getline(ifs, line).fail();)
+ {
+ _labels.emplace_back(line);
+ }
+ }
+ catch(const std::ifstream::failure &e)
+ {
+ ARM_COMPUTE_ERROR("Accessing %s: %s", labels_path.c_str(), e.what());
+ }
+}
+
+template <typename T>
+void DetectionOutputAccessor::access_predictions_tensor(ITensor &tensor)
+{
+ const size_t num_detection = tensor.info()->valid_region().shape.y();
+ const auto output_prt = reinterpret_cast<T *>(tensor.buffer() + tensor.info()->offset_first_element_in_bytes());
+
+ if(num_detection > 0)
+ {
+ _output_stream << "---------------------- Detections ----------------------" << std::endl
+ << std::endl;
+
+ _output_stream << std::left << std::setprecision(4) << std::setw(8) << "Image | " << std::setw(8) << "Label | " << std::setw(12) << "Confidence | "
+ << "[ xmin, ymin, xmax, ymax ]" << std::endl;
+
+ for(size_t i = 0; i < num_detection; ++i)
+ {
+ auto im = static_cast<const int>(output_prt[i * 7]);
+ _output_stream << std::setw(8) << im << std::setw(8)
+ << _labels[output_prt[i * 7 + 1]] << std::setw(12) << output_prt[i * 7 + 2]
+ << " [" << (output_prt[i * 7 + 3] * _tensor_shapes[im].x())
+ << ", " << (output_prt[i * 7 + 4] * _tensor_shapes[im].y())
+ << ", " << (output_prt[i * 7 + 5] * _tensor_shapes[im].x())
+ << ", " << (output_prt[i * 7 + 6] * _tensor_shapes[im].y())
+ << "]" << std::endl;
+ }
+ }
+ else
+ {
+ _output_stream << "No detection found." << std::endl;
+ }
+}
+
+bool DetectionOutputAccessor::access_tensor(ITensor &tensor)
+{
+ ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(&tensor, 1, DataType::F32);
+
+ switch(tensor.info()->data_type())
+ {
+ case DataType::F32:
+ access_predictions_tensor<float>(tensor);
+ break;
+ default:
+ ARM_COMPUTE_ERROR("NOT SUPPORTED!");
+ }
+
+ return false;
+}
+
TopNPredictionsAccessor::TopNPredictionsAccessor(const std::string &labels_path, size_t top_n, std::ostream &output_stream)
: _labels(), _output_stream(output_stream), _top_n(top_n)
{
diff --git a/utils/GraphUtils.h b/utils/GraphUtils.h
index d7f24afdd8..131378e5bd 100644
--- a/utils/GraphUtils.h
+++ b/utils/GraphUtils.h
@@ -283,6 +283,36 @@ private:
size_t _positive_samples_top5;
};
+/** Detection output accessor class */
+class DetectionOutputAccessor final : public graph::ITensorAccessor
+{
+public:
+ /** Constructor
+ *
+ * @param[in] labels_path Path to labels text file.
+ * @param[in] imgs_tensor_shapes Network input images tensor shapes.
+ * @param[out] output_stream (Optional) Output stream
+ */
+ DetectionOutputAccessor(const std::string &labels_path, std::vector<TensorShape> &imgs_tensor_shapes, std::ostream &output_stream = std::cout);
+ /** Allow instances of this class to be move constructed */
+ DetectionOutputAccessor(DetectionOutputAccessor &&) = default;
+ /** Prevent instances of this class from being copied (As this class contains pointers) */
+ DetectionOutputAccessor(const DetectionOutputAccessor &) = delete;
+ /** Prevent instances of this class from being copied (As this class contains pointers) */
+ DetectionOutputAccessor &operator=(const DetectionOutputAccessor &) = delete;
+
+ // Inherited methods overriden:
+ bool access_tensor(ITensor &tensor) override;
+
+private:
+ template <typename T>
+ void access_predictions_tensor(ITensor &tensor);
+
+ std::vector<std::string> _labels;
+ std::vector<TensorShape> _tensor_shapes;
+ std::ostream &_output_stream;
+};
+
/** Result accessor class */
class TopNPredictionsAccessor final : public graph::ITensorAccessor
{
@@ -472,6 +502,39 @@ inline std::unique_ptr<graph::ITensorAccessor> get_output_accessor(const arm_com
return arm_compute::support::cpp14::make_unique<TopNPredictionsAccessor>(graph_parameters.labels, top_n, output_stream);
}
}
+/** Generates appropriate output accessor according to the specified graph parameters
+ *
+ * @note If the output accessor is requested to validate the graph then ValidationOutputAccessor is generated
+ * else if output_accessor_file is empty will generate a DummyAccessor else will generate a TopNPredictionsAccessor
+ *
+ * @param[in] graph_parameters Graph parameters
+ * @param[in] tensor_shapes Network input images tensor shapes.
+ * @param[in] is_validation (Optional) Validation flag (default = false)
+ * @param[out] output_stream (Optional) Output stream (default = std::cout)
+ *
+ * @return An appropriate tensor accessor
+ */
+inline std::unique_ptr<graph::ITensorAccessor> get_detection_output_accessor(const arm_compute::utils::CommonGraphParams &graph_parameters,
+ std::vector<TensorShape> tensor_shapes,
+ bool is_validation = false,
+ std::ostream &output_stream = std::cout)
+{
+ if(!graph_parameters.validation_file.empty())
+ {
+ return arm_compute::support::cpp14::make_unique<ValidationOutputAccessor>(graph_parameters.validation_file,
+ output_stream,
+ graph_parameters.validation_range_start,
+ graph_parameters.validation_range_end);
+ }
+ else if(graph_parameters.labels.empty())
+ {
+ return arm_compute::support::cpp14::make_unique<DummyAccessor>(0);
+ }
+ else
+ {
+ return arm_compute::support::cpp14::make_unique<DetectionOutputAccessor>(graph_parameters.labels, tensor_shapes, output_stream);
+ }
+}
/** Generates appropriate npy output accessor according to the specified npy_path
*
* @note If npy_path is empty will generate a DummyAccessor else will generate a NpyAccessor