You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

map_op_test.cc 28 kB

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