1 /**
2 * Copyright 2019-2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <iostream>
17 #include <memory>
18 #include <vector>
19
20 #include "common/common.h"
21 #include "minddata/dataset/core/client.h"
22 #include "minddata/dataset/core/tensor.h"
23 #include "minddata/dataset/engine/datasetops/source/image_folder_op.h"
24 #include "minddata/dataset/engine/datasetops/source/tf_reader_op.h"
25 #include "minddata/dataset/engine/jagged_connector.h"
26 #include "minddata/dataset/kernels/image/decode_op.h"
27 #include "minddata/dataset/kernels/image/resize_op.h"
28 #include "minddata/dataset/kernels/tensor_op.h"
29 #include "utils/log_adapter.h"
30
31 using namespace mindspore::dataset;
32 using mindspore::LogStream;
33 using mindspore::MsLogLevel::INFO;
34
35 namespace mindspore {
36 namespace dataset {
37 namespace test {
38 class NoOp : public TensorOp {
39 public:
NoOp()40 NoOp(){};
41
~NoOp()42 ~NoOp(){};
43
Compute(const std::shared_ptr<Tensor> & input,std::shared_ptr<Tensor> * output)44 Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override {
45 *output = std::move(input);
46 return Status::OK();
47 };
48
Print(std::ostream & out) const49 void Print(std::ostream &out) const override { out << "NoOp"; };
50
Name() const51 std::string Name() const override { return kNoOp; }
52 };
53
54 class ThreeToOneOp : public TensorOp {
55 public:
ThreeToOneOp()56 ThreeToOneOp(){};
57
~ThreeToOneOp()58 ~ThreeToOneOp(){};
59
NumInput()60 uint32_t NumInput() override { return 3; }
61 // Compute function that holds the actual implementation of the operation.
Compute(const TensorRow & input,TensorRow * output)62 Status Compute(const TensorRow &input, TensorRow *output) override {
63 output->push_back(input[0]);
64 return Status::OK();
65 };
66
Print(std::ostream & out) const67 void Print(std::ostream &out) const override { out << "ThreeToOneOp"; };
68
Name() const69 std::string Name() const override { return "ThreeToOneOp"; }
70 };
71
72 class OneToThreeOp : public TensorOp {
73 public:
OneToThreeOp()74 OneToThreeOp(){};
75
~OneToThreeOp()76 ~OneToThreeOp(){};
77
NumOutput()78 uint32_t NumOutput() override { return 3; }
79
80 // Compute function that holds the actual implementation of the operation.
81 // Simply pushing the same shared pointer of the first element of input vector three times.
Compute(const TensorRow & input,TensorRow * output)82 Status Compute(const TensorRow &input, TensorRow *output) override {
83 output->push_back(input[0]);
84 output->push_back(input[0]);
85 output->push_back(input[0]);
86 return Status::OK();
87 };
88
Print(std::ostream & out) const89 void Print(std::ostream &out) const override { out << "OneToThreeOp"; };
90
Name() const91 std::string Name() const override { return "OneToThreeOp"; };
92 };
93 } // namespace test
94 } // namespace dataset
95 } // namespace mindspore
96
97 class MindDataTestMapOp : public UT::DatasetOpTesting {
98 public:
SetUp()99 void SetUp() override {
100 DatasetOpTesting::SetUp();
101 dataset_path_ = datasets_root_path_ + "" + "/testDataset2/testDataset2.data";
102 schema_path_ = datasets_root_path_ + "" + "/testDataset2/datasetSchema.json";
103
104 GlobalInit();
105
106 // Start with an empty execution tree
107 my_tree_ = std::make_shared<ExecutionTree>();
108 }
109
CreateTFReaderOp()110 std::shared_ptr<TFReaderOp> CreateTFReaderOp() {
111 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
112 auto op_connector_size = config_manager->op_connector_size();
113
114 std::unique_ptr<DataSchema> schema = std::make_unique<DataSchema>();
115 std::vector<std::string> columns_to_load = {"image", "label", "A", "B"};
116 (void)schema->LoadSchemaFile(schema_path_, columns_to_load);
117 std::vector<std::string> files = {dataset_path_};
118 std::shared_ptr<TFReaderOp> my_tfreader_op = std::make_shared<TFReaderOp>(
119 1, 2, 0, files, std::move(schema), op_connector_size, columns_to_load, false, 1, 0, false);
120 (void)my_tfreader_op->Init();
121 return my_tfreader_op;
122 }
123
124 std::shared_ptr<ExecutionTree> my_tree_;
125
126 private:
127 std::string dataset_path_;
128 std::string schema_path_;
129 };
130
131 std::shared_ptr<ImageFolderOp> ImageFolder(int64_t num_works, int64_t rows, int64_t conns, std::string path,
132 bool shuf = false, std::shared_ptr<SamplerRT> sampler = nullptr,
133 std::map<std::string, int32_t> map = {}, bool decode = false);
134
135 // std::shared_ptr<ExecutionTree> Build(std::vector<std::shared_ptr<DatasetOp>> ops);
136
137 // TestAsMap scenario:
138 // TFReaderOp reads a dataset that have column ordering |image|label|A|B|.
139 // A TensorOp that does nothing picks the "image" column and produces a column named "X".
140 // Thus, based on the new MapOp behaviour, the column ordering will be |X|label|A|B|.
141 // Verify that the "image" column is removed and "X" column is added.
TEST_F(MindDataTestMapOp,TestAsMap)142 TEST_F(MindDataTestMapOp, TestAsMap) {
143 Status rc;
144 MS_LOG(INFO) << "Doing TestAsMap.";
145
146 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total of 10 rows.
147 auto my_tfreader_op = this->CreateTFReaderOp();
148 rc = my_tree_->AssociateNode(my_tfreader_op);
149 EXPECT_TRUE(rc.IsOk());
150 auto my_no_op = std::make_shared<mindspore::dataset::test::NoOp>();
151 std::vector<std::shared_ptr<TensorOp>> my_func_list;
152 my_func_list.push_back(my_no_op);
153 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
154 auto op_connector_size = config_manager->op_connector_size();
155 std::vector<std::string> in_columns = {"image"};
156 std::vector<std::string> out_columns = {"X"};
157 std::shared_ptr<MapOp> my_map_op =
158 std::make_shared<MapOp>(in_columns, out_columns, std::move(my_func_list), 1, op_connector_size);
159 rc = my_tree_->AssociateNode(my_map_op);
160 EXPECT_TRUE(rc.IsOk());
161 rc = my_map_op->AddChild(my_tfreader_op);
162 EXPECT_TRUE(rc.IsOk());
163
164 // Assign the tree root
165 rc = my_tree_->AssignRoot(my_map_op);
166 EXPECT_TRUE(rc.IsOk());
167
168 // Now prepare the tree
169 rc = my_tree_->Prepare();
170 EXPECT_TRUE(rc.IsOk());
171 rc = my_tree_->Launch();
172 EXPECT_TRUE(rc.IsOk());
173
174 // Start the loop of reading tensors from our pipeline
175 DatasetIterator di(my_tree_);
176 TensorMap tensor_map;
177 rc = di.GetNextAsMap(&tensor_map);
178 EXPECT_TRUE(rc.IsOk());
179 EXPECT_EQ(tensor_map.size(), 4);
180 EXPECT_EQ(tensor_map.find("image"), tensor_map.end());
181 EXPECT_NE(tensor_map.find("label"), tensor_map.end());
182 EXPECT_NE(tensor_map.find("X"), tensor_map.end());
183 EXPECT_NE(tensor_map.find("A"), tensor_map.end());
184 EXPECT_NE(tensor_map.find("B"), tensor_map.end());
185 }
186
187 // Test3to1 scenario:
188 // TFReaderOp reads a dataset that have column ordering |image|label|A|B|.
189 // A 3-to-1 TensorOp picks the columns [image, A, B] and produce a column named "X".
190 // Thus, based on the new MapOp behaviour, the column ordering will be |X|label|.
191 // Verify that the only columns "X" and "label" exist.
TEST_F(MindDataTestMapOp,Test3to1)192 TEST_F(MindDataTestMapOp, Test3to1) {
193 Status rc;
194 MS_LOG(INFO) << "Doing Test3to1.";
195
196 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total of 10 rows.
197 auto my_tfreader_op = this->CreateTFReaderOp();
198 rc = my_tree_->AssociateNode(my_tfreader_op);
199 EXPECT_TRUE(rc.IsOk());
200 auto my_op = std::make_shared<mindspore::dataset::test::ThreeToOneOp>();
201 std::vector<std::shared_ptr<TensorOp>> my_func_list;
202 my_func_list.push_back(my_op);
203 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
204 auto op_connector_size = config_manager->op_connector_size();
205 std::vector<std::string> in_columns = {"image", "A", "B"};
206 std::vector<std::string> out_columns = {"X"};
207
208 std::shared_ptr<MapOp> my_map_op =
209 std::make_shared<MapOp>(in_columns, out_columns, std::move(my_func_list), 1, op_connector_size);
210
211 rc = my_tree_->AssociateNode(my_map_op);
212 EXPECT_TRUE(rc.IsOk());
213 rc = my_map_op->AddChild(my_tfreader_op);
214 EXPECT_TRUE(rc.IsOk());
215 rc = my_tree_->AssignRoot(my_map_op);
216 EXPECT_TRUE(rc.IsOk());
217 rc = my_tree_->Prepare();
218 EXPECT_TRUE(rc.IsOk());
219 rc = my_tree_->Launch();
220 EXPECT_TRUE(rc.IsOk());
221
222 // Start the loop of reading tensors from our pipeline
223 DatasetIterator di(my_tree_);
224 TensorMap tensor_map;
225 rc = di.GetNextAsMap(&tensor_map);
226 EXPECT_TRUE(rc.IsOk());
227 while (!tensor_map.empty()) {
228 EXPECT_EQ(tensor_map.size(), 2);
229 EXPECT_EQ(tensor_map.find("image"), tensor_map.end());
230 EXPECT_NE(tensor_map.find("label"), tensor_map.end());
231 EXPECT_NE(tensor_map.find("X"), tensor_map.end());
232 EXPECT_EQ(tensor_map.find("A"), tensor_map.end());
233 EXPECT_EQ(tensor_map.find("B"), tensor_map.end());
234 rc = di.GetNextAsMap(&tensor_map);
235 EXPECT_TRUE(rc.IsOk());
236 }
237 }
238
239 // Test1to3 scenario:
240 // TFReaderOp reads a dataset that have column ordering |image|label|A|B|.
241 // A 1-to-3 TensorOp picks the columns [image] and produce a column named [X, Y, Z].
242 // Thus, based on the new MapOp behaviour, the column ordering will be |X|Y|Z|label|A|B|.
243 // Verify that the only columns X, Y, Z are added (to the front) and followed by columns label, A, B..
TEST_F(MindDataTestMapOp,Test1to3)244 TEST_F(MindDataTestMapOp, Test1to3) {
245 Status rc;
246 MS_LOG(INFO) << "Doing Test1to3.";
247
248 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total of 10 rows.
249 auto my_tfreader_op = this->CreateTFReaderOp();
250 rc = my_tree_->AssociateNode(my_tfreader_op);
251 EXPECT_TRUE(rc.IsOk());
252 auto my_op = std::make_shared<mindspore::dataset::test::OneToThreeOp>();
253 std::vector<std::shared_ptr<TensorOp>> my_func_list;
254 my_func_list.push_back(my_op);
255 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
256 auto op_connector_size = config_manager->op_connector_size();
257 std::vector<std::string> in_columns = {"image"};
258 std::vector<std::string> out_columns = {"X", "Y", "Z"};
259
260 std::shared_ptr<MapOp> my_map_op =
261 std::make_shared<MapOp>(in_columns, out_columns, std::move(my_func_list), 1, op_connector_size);
262 // ProjectOp
263 std::vector<std::string> columns_to_project = {"X", "Y", "Z", "label", "A", "B"};
264 std::shared_ptr<ProjectOp> my_project_op = std::make_shared<ProjectOp>(columns_to_project);
265 rc = my_tree_->AssociateNode(my_project_op);
266 ASSERT_TRUE(rc.IsOk());
267
268 rc = my_tree_->AssignRoot(my_project_op);
269 ASSERT_TRUE(rc.IsOk());
270
271 rc = my_tree_->AssociateNode(my_map_op);
272 EXPECT_TRUE(rc.IsOk());
273
274 rc = my_project_op->AddChild(my_map_op);
275 EXPECT_TRUE(rc.IsOk());
276
277 rc = my_map_op->AddChild(my_tfreader_op);
278 EXPECT_TRUE(rc.IsOk());
279 rc = my_tree_->Prepare();
280 EXPECT_TRUE(rc.IsOk());
281 rc = my_tree_->Launch();
282 EXPECT_TRUE(rc.IsOk());
283
284 // Start the loop of reading tensors from our pipeline
285 DatasetIterator di(my_tree_);
286 TensorMap tensor_map;
287 rc = di.GetNextAsMap(&tensor_map);
288 EXPECT_TRUE(rc.IsOk());
289 EXPECT_EQ(tensor_map.size(), 6);
290 EXPECT_EQ(tensor_map.find("image"), tensor_map.end());
291 EXPECT_NE(tensor_map.find("label"), tensor_map.end());
292 EXPECT_NE(tensor_map.find("A"), tensor_map.end());
293 EXPECT_NE(tensor_map.find("B"), tensor_map.end());
294 EXPECT_NE(tensor_map.find("X"), tensor_map.end());
295 EXPECT_NE(tensor_map.find("Y"), tensor_map.end());
296 EXPECT_NE(tensor_map.find("Z"), tensor_map.end());
297
298 // Getting the next row as vector (by position).
299 TensorRow tensor_list;
300 rc = di.FetchNextTensorRow(&tensor_list);
301 EXPECT_TRUE(rc.IsOk());
302
303 // Based on the schema file, create the golden result to compare with.
304 std::vector<DataType::Type> golden_types({DataType::Type::DE_UINT8, DataType::Type::DE_UINT8,
305 DataType::Type::DE_UINT8, DataType::Type::DE_INT64,
306 DataType::Type::DE_FLOAT32, DataType::Type::DE_INT64});
307
308 std::vector<uint64_t> golden_ranks({3, 3, 3, 1, 4, 1});
309
310 std::vector<TensorShape> golden_shapes({TensorShape({3, 4, 2}), TensorShape({3, 4, 2}), TensorShape({3, 4, 2}),
311 TensorShape({7}), TensorShape({1, 13, 14, 12}), TensorShape({9})});
312
313 while (!tensor_list.empty()) {
314 for (uint32_t i = 0; i < tensor_list.size(); i++) {
315 EXPECT_EQ(tensor_list[i]->type(), golden_types[i]);
316 EXPECT_EQ(tensor_list[i]->Rank(), golden_ranks[i]);
317 EXPECT_EQ(tensor_list[i]->shape(), golden_shapes[i]);
318 EXPECT_NE(tensor_list[i]->GetBuffer(), nullptr);
319 }
320 rc = di.FetchNextTensorRow(&tensor_list);
321 EXPECT_TRUE(rc.IsOk());
322 }
323 }
324
325 // TestMultiTensorOp scenario:
326 // TFReaderOp reads a dataset that have column ordering |image|label|A|B|.
327 // A series of 3-to-1 and 1-to-3 TensorOps are applied to [image, A, B] and
328 // produce final output columns [X, Y, Z].
329 // Based on the new MapOp behaviour, the column ordering will be |X|Y|Z|label|.
TEST_F(MindDataTestMapOp,TestMultiTensorOp)330 TEST_F(MindDataTestMapOp, TestMultiTensorOp) {
331 Status rc;
332 MS_LOG(INFO) << "Doing TestMultiTensorOp.";
333
334 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total of 10 rows.
335 auto my_tfreader_op = this->CreateTFReaderOp();
336 rc = my_tree_->AssociateNode(my_tfreader_op);
337 EXPECT_TRUE(rc.IsOk());
338 auto my_op1 = std::make_shared<mindspore::dataset::test::ThreeToOneOp>();
339 auto my_op2 = std::make_shared<mindspore::dataset::test::OneToThreeOp>();
340 std::vector<std::shared_ptr<TensorOp>> my_func_list;
341 my_func_list.push_back(my_op1);
342 my_func_list.push_back(my_op2);
343 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
344 auto op_connector_size = config_manager->op_connector_size();
345 std::vector<std::string> in_columns = {"image", "A", "B"};
346 std::vector<std::string> out_columns = {"X", "Y", "Z"};
347
348 std::shared_ptr<MapOp> my_map_op =
349 std::make_shared<MapOp>(in_columns, out_columns, std::move(my_func_list), 1, op_connector_size);
350
351 rc = my_tree_->AssociateNode(my_map_op);
352 EXPECT_TRUE(rc.IsOk());
353 rc = my_map_op->AddChild(my_tfreader_op);
354 EXPECT_TRUE(rc.IsOk());
355 rc = my_tree_->AssignRoot(my_map_op);
356 EXPECT_TRUE(rc.IsOk());
357 rc = my_tree_->Prepare();
358 EXPECT_TRUE(rc.IsOk());
359 rc = my_tree_->Launch();
360 EXPECT_TRUE(rc.IsOk());
361
362 // Start the loop of reading tensors from our pipeline
363 DatasetIterator di(my_tree_);
364 TensorMap tensor_map;
365 rc = di.GetNextAsMap(&tensor_map);
366 EXPECT_TRUE(rc.IsOk());
367 while (!tensor_map.empty()) {
368 EXPECT_EQ(tensor_map.size(), 4);
369 EXPECT_EQ(tensor_map.find("image"), tensor_map.end());
370 EXPECT_EQ(tensor_map.find("A"), tensor_map.end());
371 EXPECT_EQ(tensor_map.find("B"), tensor_map.end());
372 EXPECT_NE(tensor_map.find("label"), tensor_map.end());
373 EXPECT_NE(tensor_map.find("X"), tensor_map.end());
374 EXPECT_NE(tensor_map.find("Y"), tensor_map.end());
375 EXPECT_NE(tensor_map.find("Z"), tensor_map.end());
376
377 // XYZ are Tensor shared_ptr to image, so it should have the same shape as image column.
378 EXPECT_EQ(tensor_map["X"]->shape(), TensorShape({3, 4, 2}));
379 EXPECT_EQ(tensor_map["Y"]->shape(), TensorShape({3, 4, 2}));
380 EXPECT_EQ(tensor_map["Z"]->shape(), TensorShape({3, 4, 2}));
381 rc = di.GetNextAsMap(&tensor_map);
382 EXPECT_TRUE(rc.IsOk());
383 }
384 }
385
TEST_F(MindDataTestMapOp,TestTFReaderRepeatMap)386 TEST_F(MindDataTestMapOp, TestTFReaderRepeatMap) {
387 Status rc;
388 MS_LOG(INFO) << "Doing TestTFReaderRepeatMap.";
389 uint32_t num_repeats = 3;
390
391 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total
392 // of 10 rows.
393 auto my_tfreader_op = this->CreateTFReaderOp();
394 rc = my_tree_->AssociateNode(my_tfreader_op);
395 EXPECT_TRUE(rc.IsOk());
396 auto my_no_op = std::make_shared<mindspore::dataset::test::NoOp>();
397 std::vector<std::shared_ptr<TensorOp>> my_func_list;
398 my_func_list.push_back(my_no_op);
399
400 std::shared_ptr<RepeatOp> my_repeat_op = std::make_shared<RepeatOp>(num_repeats);
401 rc = my_tree_->AssociateNode(my_repeat_op);
402 EXPECT_TRUE(rc.IsOk());
403
404 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
405 auto op_connector_size = config_manager->op_connector_size();
406 std::vector<std::string> in_columns = {"label"};
407 std::vector<std::string> out_columns = {};
408
409 std::shared_ptr<MapOp> my_map_op =
410 std::make_shared<MapOp>(in_columns, out_columns, std::move(my_func_list), 5, op_connector_size);
411
412 rc = my_tree_->AssociateNode(my_map_op);
413 EXPECT_TRUE(rc.IsOk());
414
415 rc = my_map_op->AddChild(my_repeat_op);
416 EXPECT_TRUE(rc.IsOk());
417
418 my_tfreader_op->SetTotalRepeats(num_repeats);
419 my_tfreader_op->SetNumRepeatsPerEpoch(num_repeats);
420 rc = my_repeat_op->AddChild(my_tfreader_op);
421 EXPECT_TRUE(rc.IsOk());
422
423 rc = my_tree_->AssignRoot(my_map_op);
424 EXPECT_TRUE(rc.IsOk());
425
426 rc = my_tree_->Prepare();
427 EXPECT_TRUE(rc.IsOk());
428 rc = my_tree_->Launch();
429 EXPECT_TRUE(rc.IsOk());
430
431 // Start the loop of reading tensors from our pipeline
432 DatasetIterator di(my_tree_);
433 TensorRow tensor_list;
434 rc = di.FetchNextTensorRow(&tensor_list);
435 EXPECT_TRUE(rc.IsOk());
436 EXPECT_EQ(tensor_list.size(), 4);
437 uint32_t row_count = 0;
438 while (!tensor_list.empty()) {
439 row_count++;
440 MS_LOG(INFO) << "row_count: " << row_count << ".";
441 rc = di.FetchNextTensorRow(&tensor_list);
442 EXPECT_TRUE(rc.IsOk());
443 }
444 ASSERT_EQ(row_count, 10 * num_repeats);
445 }
446
TEST_F(MindDataTestMapOp,TestTFReaderMapRepeat)447 TEST_F(MindDataTestMapOp, TestTFReaderMapRepeat) {
448 Status rc;
449 MS_LOG(INFO) << "Doing TestTFReaderMapRepeat.";
450 uint32_t num_repeats = 3;
451
452 // Note: The above TFReader config yields 5 buffers, each with 2 rows, for a total
453 // of 10 rows.
454 auto my_tfreader_op = this->CreateTFReaderOp();
455 rc = my_tree_->AssociateNode(my_tfreader_op);
456 EXPECT_TRUE(rc.IsOk());
457 auto my_no_op = std::make_shared<mindspore::dataset::test::NoOp>();
458 std::vector<std::shared_ptr<TensorOp>> my_func_list;
459 my_func_list.push_back(my_no_op);
460
461 std::shared_ptr<RepeatOp> my_repeat_op = std::make_shared<RepeatOp>(num_repeats);
462 rc = my_tree_->AssociateNode(my_repeat_op);
463 EXPECT_TRUE(rc.IsOk());
464
465 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
466 auto op_connector_size = config_manager->op_connector_size();
467 std::vector<std::string> input_columns = {"label"};
468 std::vector<std::string> output_columns = {};
469 std::shared_ptr<MapOp> my_map_op =
470 std::make_shared<MapOp>(input_columns, output_columns, std::move(my_func_list), 50, op_connector_size);
471
472 rc = my_tree_->AssociateNode(my_map_op);
473 EXPECT_TRUE(rc.IsOk());
474
475 my_map_op->SetTotalRepeats(num_repeats);
476 my_map_op->SetNumRepeatsPerEpoch(num_repeats);
477 rc = my_repeat_op->AddChild(my_map_op);
478 EXPECT_TRUE(rc.IsOk());
479
480 my_tfreader_op->SetTotalRepeats(num_repeats);
481 my_tfreader_op->SetNumRepeatsPerEpoch(num_repeats);
482 rc = my_map_op->AddChild(my_tfreader_op);
483 EXPECT_TRUE(rc.IsOk());
484
485 rc = my_tree_->AssignRoot(my_repeat_op);
486 EXPECT_TRUE(rc.IsOk());
487
488 rc = my_tree_->Prepare();
489 EXPECT_TRUE(rc.IsOk());
490 rc = my_tree_->Launch();
491 EXPECT_TRUE(rc.IsOk());
492
493 // Start the loop of reading tensors from our pipeline
494 DatasetIterator di(my_tree_);
495 TensorRow tensor_list;
496 rc = di.FetchNextTensorRow(&tensor_list);
497 EXPECT_TRUE(rc.IsOk());
498 EXPECT_EQ(tensor_list.size(), 4);
499 uint32_t row_count = 0;
500 while (!tensor_list.empty()) {
501 row_count++;
502 MS_LOG(INFO) << "row_count: " << row_count << ".";
503 rc = di.FetchNextTensorRow(&tensor_list);
504 EXPECT_TRUE(rc.IsOk());
505 }
506 ASSERT_EQ(row_count, 10 * num_repeats);
507 }
508
TEST_F(MindDataTestMapOp,TFReader_Decode_Repeat_Resize)509 TEST_F(MindDataTestMapOp, TFReader_Decode_Repeat_Resize) {
510 Status rc;
511 MS_LOG(INFO) << "Doing TFReader_Decode_Repeat_Resize.";
512 uint32_t num_repeats = 2;
513
514 std::string dataset_path = datasets_root_path_ + "/" + "test_tf_file_3_images/train-0000-of-0001.data";
515 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
516 auto op_connector_size = config_manager->op_connector_size();
517 std::unique_ptr<DataSchema> schema = std::make_unique<DataSchema>();
518 std::vector<std::string> columns_to_load = {"image", "label"};
519 std::vector<std::string> files = {dataset_path};
520 std::shared_ptr<TFReaderOp> my_tfreader_op = std::make_shared<TFReaderOp>(
521 1, 2, 0, files, std::move(schema), op_connector_size, columns_to_load, false, 1, 0, false);
522 (void)my_tfreader_op->Init();
523
524 rc = my_tree_->AssociateNode(my_tfreader_op);
525 EXPECT_TRUE(rc.IsOk());
526 auto decode_op = std::make_shared<DecodeOp>();
527 std::vector<std::shared_ptr<TensorOp>> my_func_list;
528 my_func_list.push_back(decode_op);
529
530 std::shared_ptr<RepeatOp> my_repeat_op = std::make_shared<RepeatOp>(num_repeats);
531 rc = my_tree_->AssociateNode(my_repeat_op);
532 EXPECT_TRUE(rc.IsOk());
533 std::vector<std::string> input_columns = {"image"};
534 std::vector<std::string> output_columns = {};
535 std::shared_ptr<MapOp> my_map_decode_op =
536 std::make_shared<MapOp>(input_columns, output_columns, std::move(my_func_list), 4, op_connector_size);
537 rc = my_tree_->AssociateNode(my_map_decode_op);
538 EXPECT_TRUE(rc.IsOk());
539
540 auto resize_op = std::make_shared<ResizeOp>(300, 300);
541 std::vector<std::shared_ptr<TensorOp>> my_func_list2;
542 my_func_list2.push_back(resize_op);
543 std::shared_ptr<MapOp> my_map_resize_op =
544 std::make_shared<MapOp>(input_columns, output_columns, std::move(my_func_list2), 5, op_connector_size);
545 rc = my_tree_->AssociateNode(my_map_resize_op);
546 EXPECT_TRUE(rc.IsOk());
547
548 my_tfreader_op->SetTotalRepeats(num_repeats);
549 my_tfreader_op->SetNumRepeatsPerEpoch(num_repeats);
550 rc = my_map_decode_op->AddChild(my_tfreader_op);
551 EXPECT_TRUE(rc.IsOk());
552
553 my_map_decode_op->SetTotalRepeats(num_repeats);
554 my_map_decode_op->SetNumRepeatsPerEpoch(num_repeats);
555 rc = my_repeat_op->AddChild(my_map_decode_op);
556 EXPECT_TRUE(rc.IsOk());
557
558 rc = my_map_resize_op->AddChild(my_repeat_op);
559 EXPECT_TRUE(rc.IsOk());
560
561 rc = my_tree_->AssignRoot(my_map_resize_op);
562 EXPECT_TRUE(rc.IsOk());
563
564 rc = my_tree_->Prepare();
565 EXPECT_TRUE(rc.IsOk());
566 rc = my_tree_->Launch();
567 EXPECT_TRUE(rc.IsOk());
568
569 // Start the loop of reading tensors from our pipeline
570 DatasetIterator di(my_tree_);
571 TensorRow tensor_list;
572 rc = di.FetchNextTensorRow(&tensor_list);
573 EXPECT_TRUE(rc.IsOk());
574 EXPECT_EQ(tensor_list.size(), 2);
575 uint32_t row_count = 0;
576 while (!tensor_list.empty()) {
577 row_count++;
578 rc = di.FetchNextTensorRow(&tensor_list);
579 EXPECT_TRUE(rc.IsOk());
580 }
581
582 ASSERT_EQ(row_count, 6);
583 }
584
TEST_F(MindDataTestMapOp,ImageFolder_Decode_Repeat_Resize)585 TEST_F(MindDataTestMapOp, ImageFolder_Decode_Repeat_Resize) {
586 Status rc;
587 MS_LOG(INFO) << "Doing ImageFolder_Decode_Repeat_Resize.";
588
589 std::string folder_path = datasets_root_path_ + "/testPK/data";
590
591 uint32_t num_repeats = 2;
592 std::shared_ptr<RepeatOp> repeat_op = std::make_shared<RepeatOp>(num_repeats);
593 EXPECT_TRUE(rc.IsOk());
594
595 auto decode_op = std::make_shared<DecodeOp>();
596 std::vector<std::shared_ptr<TensorOp>> func_list;
597 func_list.push_back(decode_op);
598 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
599 int32_t op_connector_size = config_manager->op_connector_size();
600 int32_t num_parallel_workers = config_manager->num_parallel_workers();
601 std::vector<std::string> input_columns = {"image"};
602 std::vector<std::string> output_columns = {};
603 std::shared_ptr<MapOp> map_decode_map =
604 std::make_shared<MapOp>(input_columns, output_columns, func_list, 4, op_connector_size);
605
606 auto resize_op = std::make_shared<ResizeOp>(300, 300);
607 std::vector<std::shared_ptr<TensorOp>> func_list2;
608 func_list2.push_back(resize_op);
609 std::shared_ptr<MapOp> map_resize_op =
610 std::make_shared<MapOp>(input_columns, output_columns, func_list2, 5, op_connector_size);
611
612 auto image_folder_op = ImageFolder(num_parallel_workers, 2, 32, folder_path, false);
613 image_folder_op->SetTotalRepeats(num_repeats);
614 image_folder_op->SetNumRepeatsPerEpoch(num_repeats);
615 map_decode_map->SetTotalRepeats(num_repeats);
616 map_decode_map->SetNumRepeatsPerEpoch(num_repeats);
617 my_tree_ = Build({image_folder_op, map_decode_map, repeat_op, map_resize_op});
618 rc = my_tree_->Prepare();
619 EXPECT_TRUE(rc.IsOk());
620 rc = my_tree_->Launch();
621 EXPECT_TRUE(rc.IsOk());
622
623 // Start the loop of reading tensors from our pipeline
624 DatasetIterator di(my_tree_);
625 TensorMap tensor_map;
626 ASSERT_OK(di.GetNextAsMap(&tensor_map));
627 EXPECT_TRUE(rc.IsOk());
628 uint64_t i = 0;
629 int32_t label = 0;
630 int32_t img_class[] = {0, 1, 2, 3};
631 std::string result;
632 while (tensor_map.size() != 0) {
633 tensor_map["label"]->GetItemAt<int32_t>(&label, {});
634 MS_LOG(DEBUG) << "row:" << i << "\tlabel:" << label << "\n";
635 EXPECT_TRUE(img_class[(i % 44) / 11] == label);
636 // Dump all the image into string, to be used as a comparison later.
637 result.append((char *)tensor_map["image"]->GetBuffer(), (int64_t)tensor_map["image"]->Size());
638 ASSERT_OK(di.GetNextAsMap(&tensor_map));
639 i++;
640 }
641 EXPECT_TRUE(i == 88);
642
643 // Part-2 : creating mapop with performance mode = false, to check if the result is the same
644 // as when performance mode = true.
645 repeat_op = std::make_shared<RepeatOp>(num_repeats);
646 EXPECT_TRUE(rc.IsOk());
647 map_decode_map = std::make_shared<MapOp>(input_columns, output_columns, func_list, 14, op_connector_size);
648
649 map_resize_op = std::make_shared<MapOp>(input_columns, output_columns, func_list2, 15, op_connector_size);
650
651 image_folder_op = ImageFolder(16, 2, 32, folder_path, false);
652 image_folder_op->SetTotalRepeats(num_repeats);
653 image_folder_op->SetNumRepeatsPerEpoch(num_repeats);
654 map_decode_map->SetTotalRepeats(num_repeats);
655 map_decode_map->SetNumRepeatsPerEpoch(num_repeats);
656 auto my_tree_2 = Build({image_folder_op, map_decode_map, repeat_op, map_resize_op});
657
658 rc = my_tree_2->Prepare();
659 EXPECT_TRUE(rc.IsOk());
660 rc = my_tree_2->Launch();
661 EXPECT_TRUE(rc.IsOk());
662
663 // Start the loop of reading tensors from our pipeline
664 DatasetIterator di2(my_tree_2);
665 ASSERT_OK(di2.GetNextAsMap(&tensor_map));
666 EXPECT_TRUE(rc.IsOk());
667 i = 0;
668 label = 0;
669 std::string result2;
670 while (tensor_map.size() != 0) {
671 tensor_map["label"]->GetItemAt<int32_t>(&label, {});
672 MS_LOG(DEBUG) << "row:" << i << "\tlabel:" << label << "\n";
673 EXPECT_TRUE(img_class[(i % 44) / 11] == label);
674 result2.append((char *)tensor_map["image"]->GetBuffer(), (int64_t)tensor_map["image"]->Size());
675 ASSERT_OK(di2.GetNextAsMap(&tensor_map));
676 i++;
677 }
678 EXPECT_TRUE(i == 88);
679
680 EXPECT_EQ(result.size(), result2.size());
681 EXPECT_EQ(result, result2);
682 }
683
TEST_F(MindDataTestMapOp,ImageFolder_Decode_Repeat_Resize_NoInputColumns)684 TEST_F(MindDataTestMapOp, ImageFolder_Decode_Repeat_Resize_NoInputColumns) {
685 Status rc;
686 MS_LOG(INFO) << "Doing ImageFolder_Decode_Repeat_Resize_NoInputColumns.";
687
688 std::string folder_path = datasets_root_path_ + "/testPK/data";
689
690 uint32_t num_repeats = 2;
691 std::shared_ptr<RepeatOp> repeat_op = std::make_shared<RepeatOp>(num_repeats);
692 ;
693
694 auto decode_op = std::make_shared<DecodeOp>();
695 std::vector<std::shared_ptr<TensorOp>> func_list;
696 func_list.push_back(decode_op);
697 std::shared_ptr<ConfigManager> config_manager = GlobalContext::config_manager();
698 auto op_connector_size = config_manager->op_connector_size();
699 std::vector<std::string> input_columns = {};
700 std::vector<std::string> output_columns = {};
701 std::shared_ptr<MapOp> map_decode_map =
702 std::make_shared<MapOp>(input_columns, output_columns, std::move(func_list), 4, op_connector_size);
703 ;
704
705 auto resize_op = std::make_shared<ResizeOp>(300, 300);
706 std::vector<std::shared_ptr<TensorOp>> func_list2;
707 func_list2.push_back(resize_op);
708 std::shared_ptr<MapOp> map_resize_op =
709 std::make_shared<MapOp>(input_columns, output_columns, std::move(func_list2), 5, op_connector_size);
710 ;
711
712 auto image_folder_op = ImageFolder(16, 2, 32, folder_path, false);
713 image_folder_op->SetTotalRepeats(num_repeats);
714 image_folder_op->SetNumRepeatsPerEpoch(num_repeats);
715 map_decode_map->SetTotalRepeats(num_repeats);
716 map_decode_map->SetNumRepeatsPerEpoch(num_repeats);
717 my_tree_ = Build({image_folder_op, map_decode_map, repeat_op, map_resize_op});
718 rc = my_tree_->Prepare();
719 EXPECT_TRUE(rc.IsOk());
720 rc = my_tree_->Launch();
721 EXPECT_TRUE(rc.IsOk());
722
723 // Start the loop of reading tensors from our pipeline
724 DatasetIterator di(my_tree_);
725 TensorMap tensor_map;
726 ASSERT_OK(di.GetNextAsMap(&tensor_map));
727 EXPECT_TRUE(rc.IsOk());
728 uint64_t i = 0;
729 int32_t label = 0;
730 int32_t img_class[] = {0, 1, 2, 3};
731 std::string result;
732 while (tensor_map.size() != 0) {
733 tensor_map["label"]->GetItemAt<int32_t>(&label, {});
734 EXPECT_TRUE(img_class[(i % 44) / 11] == label);
735 ASSERT_OK(di.GetNextAsMap(&tensor_map));
736 i++;
737 }
738 EXPECT_TRUE(i == 88);
739 }
740