• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
40   NoOp(){};
41 
42   ~NoOp(){};
43 
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 
49   void Print(std::ostream &out) const override { out << "NoOp"; };
50 
51   std::string Name() const override { return kNoOp; }
52 };
53 
54 class ThreeToOneOp : public TensorOp {
55  public:
56   ThreeToOneOp(){};
57 
58   ~ThreeToOneOp(){};
59 
60   uint32_t NumInput() override { return 3; }
61   // Compute function that holds the actual implementation of the operation.
62   Status Compute(const TensorRow &input, TensorRow *output) override {
63     output->push_back(input[0]);
64     return Status::OK();
65   };
66 
67   void Print(std::ostream &out) const override { out << "ThreeToOneOp"; };
68 
69   std::string Name() const override { return "ThreeToOneOp"; }
70 };
71 
72 class OneToThreeOp : public TensorOp {
73  public:
74   OneToThreeOp(){};
75 
76   ~OneToThreeOp(){};
77 
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.
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 
89   void Print(std::ostream &out) const override { out << "OneToThreeOp"; };
90 
91   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:
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 
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.
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.
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..
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|.
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 
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 
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 
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 
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 
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