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