Skip to content

Commit 7738d8d

Browse files
committed
Working serialization for instance and semantic segmentation
1 parent 616c271 commit 7738d8d

File tree

5 files changed

+95
-43
lines changed

5 files changed

+95
-43
lines changed

src/cpp/include/utils/config.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ static inline std::map<std::string, ov::Layout> parseLayoutString(const std::str
122122
return layouts;
123123
}
124124

125-
126125
static inline ov::Layout getLayoutFromShape(const ov::PartialShape& shape) {
127126
if (shape.size() == 2) {
128127
return "NC";
@@ -159,13 +158,14 @@ static inline ov::Layout getLayoutFromShape(const ov::PartialShape& shape) {
159158
throw std::runtime_error("Usupported " + std::to_string(shape.size()) + "D shape");
160159
}
161160

162-
static inline ov::Layout getInputLayout(const ov::Output<ov::Node>& input, std::map<std::string, ov::Layout>& inputsLayouts) {
161+
static inline ov::Layout getInputLayout(const ov::Output<ov::Node>& input,
162+
std::map<std::string, ov::Layout>& inputsLayouts) {
163163
ov::Layout layout = ov::layout::get_layout(input);
164164
if (layout.empty()) {
165165
if (inputsLayouts.empty()) {
166166
layout = getLayoutFromShape(input.get_partial_shape());
167167
std::cout << "Automatically detected layout '" << layout.to_string() << "' for input '"
168-
<< input.get_any_name() << "' will be used." << std::endl;
168+
<< input.get_any_name() << "' will be used." << std::endl;
169169
} else if (inputsLayouts.size() == 1) {
170170
layout = inputsLayouts.begin()->second;
171171
} else {

src/cpp/src/tasks/classification.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ cv::Size Classification::serialize(std::shared_ptr<ov::Model>& ov_model) {
129129
throw std::logic_error("Classification model wrapper supports topologies with up to 4 outputs");
130130
}
131131

132-
133132
size_t topk = 1;
134133
topk = utils::get_from_any_maps("topk", config, {}, topk);
135134
std::vector<std::string> labels;

src/cpp/src/tasks/instance_segmentation.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,65 @@ cv::Mat segm_postprocess(const SegmentedObject& box, const cv::Mat& unpadded, in
122122
}
123123

124124
cv::Size InstanceSegmentation::serialize(std::shared_ptr<ov::Model>& ov_model) {
125-
return {};
125+
if (ov_model->inputs().size() != 1) {
126+
throw std::logic_error("MaskRCNNModel model wrapper supports topologies with only 1 input");
127+
}
128+
const auto& input = ov_model->input();
129+
auto config = ov_model->has_rt_info("model_info") ? ov_model->get_rt_info<ov::AnyMap>("model_info") : ov::AnyMap{};
130+
std::string layout = "";
131+
layout = utils::get_from_any_maps("layout", config, {}, layout);
132+
auto inputsLayouts = utils::parseLayoutString(layout);
133+
const ov::Layout& inputLayout = utils::getInputLayout(input, inputsLayouts);
134+
const ov::Shape& inputShape = input.get_partial_shape().get_max_shape();
135+
if (inputShape.size() != 4 || inputShape[ov::layout::channels_idx(inputLayout)] != 3) {
136+
throw std::logic_error("3-channel 4-dimensional model's input is expected");
137+
}
138+
139+
auto interpolation_mode = cv::INTER_LINEAR;
140+
utils::RESIZE_MODE resize_mode = utils::RESIZE_FILL;
141+
142+
std::vector<float> scale_values;
143+
std::vector<float> mean_values;
144+
scale_values = utils::get_from_any_maps("scale_values", config, ov::AnyMap{}, scale_values);
145+
mean_values = utils::get_from_any_maps("mean_values", config, ov::AnyMap{}, mean_values);
146+
uint8_t pad_value = 0;
147+
bool reverse_input_channels = false;
148+
149+
ov_model = utils::embedProcessing(
150+
ov_model,
151+
input.get_any_name(),
152+
inputLayout,
153+
resize_mode,
154+
interpolation_mode,
155+
ov::Shape{inputShape[ov::layout::width_idx(inputLayout)], inputShape[ov::layout::height_idx(inputLayout)]},
156+
pad_value,
157+
reverse_input_channels,
158+
mean_values,
159+
scale_values);
160+
161+
cv::Size input_shape(inputShape[ov::layout::width_idx(inputLayout)],
162+
inputShape[ov::layout::height_idx(inputLayout)]);
163+
164+
// --------------------------- Prepare output -----------------------------------------------------
165+
struct NameRank {
166+
std::string name;
167+
size_t rank;
168+
};
169+
std::vector<NameRank> filtered;
170+
filtered.reserve(3);
171+
for (ov::Output<ov::Node>& output : ov_model->outputs()) {
172+
const std::unordered_set<std::string>& out_names = output.get_names();
173+
if (out_names.find(saliency_map_name) == out_names.end() &&
174+
out_names.find(feature_vector_name) == out_names.end()) {
175+
filtered.push_back({output.get_any_name(), output.get_partial_shape().get_max_shape().size()});
176+
}
177+
}
178+
if (filtered.size() != 3 && filtered.size() != 4) {
179+
throw std::logic_error(std::string{"MaskRCNNModel model wrapper supports topologies with "} +
180+
saliency_map_name + ", " + feature_vector_name + " and 3 or 4 other outputs");
181+
}
182+
183+
return input_shape;
126184
}
127185

128186
InstanceSegmentation InstanceSegmentation::load(const std::string& model_path) {

src/cpp/src/tasks/semantic_segmentation.cpp

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ cv::Size SemanticSegmentation::serialize(std::shared_ptr<ov::Model>& ov_model) {
5454
if (layout.empty()) {
5555
layout = utils::getLayoutFromShape(input.get_partial_shape());
5656
}
57-
const ov::Shape& inputShape = input.get_partial_shape().get_max_shape();
58-
if (inputShape.size() != 4 || inputShape[ov::layout::channels_idx(layout)] != 3) {
57+
const ov::Shape& shape = input.get_partial_shape().get_max_shape();
58+
if (shape.size() != 4 || shape[ov::layout::channels_idx(layout)] != 3) {
5959
throw std::logic_error("3-channel 4-dimensional model's input is expected");
6060
}
6161
if (ov_model->outputs().size() > 2) {
@@ -90,29 +90,18 @@ cv::Size SemanticSegmentation::serialize(std::shared_ptr<ov::Model>& ov_model) {
9090
scale_values = utils::get_from_any_maps("scale_values", config, ov::AnyMap{}, scale_values);
9191
mean_values = utils::get_from_any_maps("mean_values", config, ov::AnyMap{}, mean_values);
9292

93-
std::cout << "inputNames: " << input.get_any_name() << std::endl;
94-
std::cout << "inputLayout: " << layout.to_string() << std::endl;
95-
std::cout << "resize_mode: " << resize_mode << std::endl;
96-
std::cout << "interpolationMode" << interpolation_mode << std::endl;
97-
std::cout << "shape"
98-
<< ov::Shape{inputShape[ov::layout::width_idx(layout)], inputShape[ov::layout::height_idx(layout)]}
99-
<< std::endl;
100-
std::cout << "pad_value" << pad_value << std::endl;
101-
std::cout << "reverse_input_channels" << reverse_input_channels << std::endl;
102-
std::cout << "mean_values" << mean_values.size() << std::endl;
103-
std::cout << "scale_values" << scale_values.size() << std::endl;
104-
105-
ov_model = utils::embedProcessing(
106-
ov_model,
107-
input.get_any_name(),
108-
layout,
109-
resize_mode,
110-
interpolation_mode,
111-
ov::Shape{inputShape[ov::layout::width_idx(layout)], inputShape[ov::layout::height_idx(layout)]},
112-
pad_value,
113-
reverse_input_channels,
114-
mean_values,
115-
scale_values);
93+
auto input_shape = ov::Shape{shape[ov::layout::width_idx(layout)], shape[ov::layout::height_idx(layout)]};
94+
95+
ov_model = utils::embedProcessing(ov_model,
96+
input.get_any_name(),
97+
layout,
98+
resize_mode,
99+
interpolation_mode,
100+
input_shape,
101+
pad_value,
102+
reverse_input_channels,
103+
mean_values,
104+
scale_values);
116105

117106
ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(ov_model);
118107
ov::Layout out_layout = utils::getLayoutFromShape(ov_model->output(out_name).get_partial_shape());
@@ -126,16 +115,7 @@ cv::Size SemanticSegmentation::serialize(std::shared_ptr<ov::Model>& ov_model) {
126115
}
127116
ov_model = ppp.build();
128117

129-
// outputNames.push_back(out_name);
130-
// for (ov::Output<ov::Node>& output : model->outputs()) {
131-
// const std::unordered_set<std::string>& out_names = output.get_names();
132-
// if (out_names.find(feature_vector_name) == out_names.end()) {
133-
// outputNames.emplace_back(feature_vector_name);
134-
// return;
135-
// }
136-
// }
137-
138-
return cv::Size{};
118+
return cv::Size(input_shape[0], input_shape[1]);
139119
}
140120

141121
std::map<std::string, ov::Tensor> SemanticSegmentation::preprocess(cv::Mat image) {

tests/cpp/test_accuracy.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,25 @@ TEST_P(ModelParameterizedTest, AccuracyTest) {
9898
}
9999

100100
} else if (data.type == "SegmentationModel") {
101-
GTEST_SKIP(); // Skip since serialization is broken for now.
102-
// auto model = SemanticSegmentation::load(model_path);
101+
auto model = SemanticSegmentation::load(model_path);
102+
103+
for (auto& test_data : data.test_data) {
104+
std::string image_path = DATA_DIR + '/' + test_data.image;
105+
cv::Mat image = cv::imread(image_path);
106+
auto result = model.infer(image);
107+
108+
EXPECT_EQ(format_test_output_to_string(model, result), test_data.reference[0]);
109+
}
103110
} else if (data.type == "MaskRCNNModel") {
104-
GTEST_SKIP();
111+
auto model = InstanceSegmentation::load(model_path);
112+
113+
for (auto& test_data : data.test_data) {
114+
std::string image_path = DATA_DIR + '/' + test_data.image;
115+
cv::Mat image = cv::imread(image_path);
116+
auto result = model.infer(image);
117+
118+
EXPECT_EQ(format_test_output_to_string(model, result), test_data.reference[0]);
119+
}
105120
} else if (data.type == "ClassificationModel") {
106121
auto model = Classification::load(model_path);
107122
for (auto& test_data : data.test_data) {

0 commit comments

Comments
 (0)