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

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