This module is used to read the data stored on the hard disk, package it and output it as the data type usable in MNN training. The source code of this module is located in the MNN_root/tools/train/source/data/directory. To use it, include the DataLoader.hpp header file. All other components in the module are imported to build DataLoader.

Related demo

  1. MNN_root/tools/train/source/demo/dataLoaderDemo.cpp

Use the MNIST dataset to build a DataLoader and output the DataLoader.

  1. MNN_root/tools/train/source/demo/dataLoaderTest.cpp

Use MNIST datasets to build DataLoader and test some components in DataLoader.

  1. MNN_root/tools/train/source/demo/``ImageDatasetDemo.cpp

Reads the image data saved on the hard disk and displays it. The display needs to use OpenCV and turn it on at compile time with the ‘MNN_USE_OPENCV ‘macro.

Custom Dataset

Reference The writing method of the preset Dataset in MNN_root/tools/train/source/datasets/ inherits the Dataset class and implements two abstract functions, for example:

  1. // MnistDataset.cpp
  2. // Returns an image and its label from the MNIST dataset.
  3. Example MnistDataset::get(size_t index) {
  4. auto data = _Input({1, kImageRows, kImageColumns}, NCHW, halide_type_of<uint8_t>());
  5. auto label = _Input({}, NCHW, halide_type_of<uint8_t>());
  6. auto dataPtr = mImagePtr + index * kImageRows * kImageColumns;
  7. ::memcpy(data->writeMap<uint8_t>(), dataPtr, kImageRows * kImageColumns);
  8. auto labelPtr = mLabelsPtr + index;
  9. ::memcpy(label->writeMap<uint8_t>(), labelPtr, 1);
  10. auto returnIndex = _Const(index);
  11. // return the index for test
  12. return {{data, returnIndex}, {label}};
  13. }
  14. // Returns the dataset size. 60000 for the training dataset, 10000 for the testing dataset.
  15. size_t MnistDataset::size() {
  16. return mImages->getInfo()->dim[0];
  17. }

DataLoader usage example

Workflow: Customize Dataset, construct DataLoader, read data, DataLoader->reset();

  1. //
  2. // ImageDatasetDemo.cpp
  3. // MNN
  4. //
  5. // Created by MNN on 2019/11/20.
  6. // Copyright © 2018, Alibaba Group Holding Limited
  7. //
  8. #include <iostream>
  9. #include "DataLoader.hpp"
  10. #include "DemoUnit.hpp"
  11. #include "ImageDataset.hpp"
  12. #include "RandomSampler.hpp"
  13. #include "Sampler.hpp"
  14. #include "Transform.hpp"
  15. #include "TransformDataset.hpp"
  16. #ifdef MNN_USE_OPENCV
  17. #include <opencv2/opencv.hpp> // use opencv to show pictures
  18. using namespace cv;
  19. #endif
  20. using namespace std;
  21. /*
  22. * this is an demo for how to use the ImageDataset and DataLoader
  23. */
  24. class ImageDatasetDemo : public DemoUnit {
  25. public:
  26. // this function is an example to use the lambda transform
  27. // here we use lambda transform to normalize data from 0~255 to 0~1
  28. static Example func(Example example) {
  29. // // an easier way to do this
  30. auto cast = _Cast(example.first[0], halide_type_of<float>());
  31. example.first[0] = _Multiply(cast, _Const(1.0f / 255.0f));
  32. return example;
  33. }
  34. virtual int run(int argc, const char* argv[]) override {
  35. if (argc != 3) {
  36. cout << "usage: ./runTrainDemo.out ImageDatasetDemo path/to/images/ path/to/image/txt\n" << endl;
  37. // The data format of the ImageDataset uses the data format of ImageNet.
  38. // You can define your own data set and its own data format.
  39. cout << "the ImageDataset read stored images as input data.\n"
  40. "use 'pathToImages' and a txt file to construct a ImageDataset.\n"
  41. "the txt file should use format as below:\n"
  42. " image1.jpg label1,label2,...\n"
  43. " image2.jpg label3,label4,...\n"
  44. " ...\n"
  45. "the ImageDataset would read images from:\n"
  46. " pathToImages/image1.jpg\n"
  47. " pathToImages/image2.jpg\n"
  48. " ...\n"
  49. << endl;
  50. return 0;
  51. }
  52. std::string pathToImages = argv[1];
  53. std::string pathToImageTxt = argv[2];
  54. // Preprocess of the configurable data in ImageDataset.
  55. auto converImagesToFormat = ImageDataset::DestImageFormat::RGB;
  56. int resizeHeight = 224;
  57. int resizeWidth = 224;
  58. std::vector<float> scales = {1/255.0, 1/255.0, 1/255.0};
  59. auto config = ImageDataset::ImageConfig(converImagesToFormat, resizeHeight, resizeWidth, scales);
  60. bool readAllImagesToMemory = false;
  61. // Construct the ImageDataset
  62. auto dataset = std::make_shared<ImageDataset>(pathToImages, pathToImageTxt, config, readAllImagesToMemory);
  63. const int batchSize = 1;
  64. const int numWorkers = 1;
  65. // Construct the DataLoader,
  66. // Here we stack the batch data into a VARP(Tensor)
  67. auto dataLoader = std::shared_ptr<DataLoader>(DataLoader::makeDataLoader(dataset, batchSize, true, false, numWorkers));
  68. const size_t iterations = dataset->size() / batchSize;
  69. for (int i = 0; i < iterations; i++) {
  70. // Reads the data.
  71. auto trainData = dataLoader->next();
  72. auto data = trainData[0].first[0]->readMap<float_t>();
  73. auto label = trainData[0].second[0]->readMap<int32_t>();
  74. cout << "index: " << i << " label: " << int(label[0]) << endl;
  75. #ifdef MNN_USE_OPENCV
  76. // only show the first picture in the batch
  77. Mat image = Mat(resizeHeight, resizeWidth, CV_32FC(3), (void*)data);
  78. imshow("image", image);
  79. waitKey(-1);
  80. #endif
  81. }
  82. // DataLoader must be reset for each completed pass over the dataset.
  83. // This will reset the sampler's internal state
  84. dataLoader->reset();
  85. return 0;
  86. }
  87. };
  88. DemoUnitSetRegister(ImageDatasetDemo, "ImageDatasetDemo");

Related classes and concepts

VARP

Variables in MNN dynamic graphs, similar to Tensor in PyTorch.

Example

Minimum unit of data output by DataLoader

  1. /**
  2. First: data: a vector of input tensors (for single input dataset is only one)
  3. Second: target: a vector of output tensors (for single output dataset is only one)
  4. */
  5. typedef std::pair<std::vector<VARP>, std::vector<VARP>> Example;

As you can see, an Example is a data pair. The first part is input and the second part is target. Since the network may have multiple inputs and multiple targets, the first and second are vector structures.

RandomSampler : public Sampler

Random sampling sequence generator. For example, if there are 1000 images in the image dataset, the sampling sequence 0~999 is generated, and whether to shuffle or not is specified according to the configuration.

  1. public:
  2. // size: length of the sampling sequence.
  3. // shuffle: true if the sampling sequence is to be randomly generated.
  4. explicit RandomSampler(size_t size, bool shuffle = true);
  5. // Resets the internal state of the sampler.
  6. void reset(size_t size) override;
  7. // Size of the sampler.
  8. size_t size() override;
  9. // Returns the sampling sequence generated internally.
  10. const std::vector<size_t> indices();
  11. // Returns the number of sampling sequences already used.
  12. size_t index();
  13. // Obtains the next batchSize sampling sequence.
  14. std::vector<size_t> next(size_t batchSize) override;
  15. private:
  16. std::vector<size_t> mIndices;
  17. size_t mIndex = 0;
  18. bool mShuffle;

Dataset

The abstract base class of a dataset. To customize a dataset, you must inherit this base class and implement abstract functions. For more information, see Description of preset datasets in MNN_root/tools/train/source/datasets/

  1. // Returns the size of te dataset. For a dataset with 1000 images, the size is 1000.
  2. virtual size_t size() = 0;
  3. // Returns the data at the specified index. If `index` is 123, then it returns the 123rd image data.
  4. virtual Example get(size_t index) = 0;
  5. // Returns the batch of data specified by the listed of indices.
  6. std::vector<Example> getBatch(std::vector<size_t> indices);

Transform

Abstract base class, to perform a certain transformation on each data in a batch, can be some preprocessing, etc.

BatchTransform

Abstract base class, to perform a certain transformation on a batch of data, can be some preprocessing, etc.

StackTransform : public BatchTransform

Combine a batch of data represented by vector output from a Dataset into a VARP, that is
Stack( (c, h, w), (c, h, w), (c, h, w)... ) --> (n, c, h, w)
``

LambdaTransform : public Transform

Process each Example of the Dataset output separately, such as centralization and normalization.

TransformDataset : public Dataset

To Transform a Dataset is still a Dataset used to output data.

DataLoaderConfig

Configure DataLoader with the following configuration items:

batchSize: specifies the batch size. numWorkers: the number of threads pre-read by multiple threads

DataLoader

According to the sampling sequence generated by the sampler, obtain the corresponding data from the corresponding Dataset and output

  1. // Constructor
  2. DataLoader(std::shared_ptr<BatchDataset> dataset, std::shared_ptr<Sampler> sampler,
  3. std::shared_ptr<DataLoaderConfig> config);
  4. // Contruct a DataLoader without Transform
  5. static DataLoader* makeDataLoader(std::shared_ptr<BatchDataset> dataset,
  6. const int batchSize,
  7. const bool stack = true, // Whether to stack a batch of data into a VARP(TENSOR)
  8. const bool shuffle = true,
  9. const int numWorkers = 0);
  10. // Construct a DataLoader with Transform,multiple Transforms can be stacked.
  11. static DataLoader* makeDataLoader(std::shared_ptr<BatchDataset> dataset,
  12. std::vector<std::shared_ptr<BatchTransform>> transforms,
  13. const int batchSize,
  14. const bool shuffle = true,
  15. const int numWorkers = 0);
  16. // The number of iterations after specifying the batch size. The latest batch can be smaller than the
  17. // batchsize.
  18. size_t iterNumber() const;
  19. // The size of the dataset.
  20. size_t size() const;
  21. // Gets the data for the next batch.
  22. std::vector<Example> next();
  23. // Clear internal data array, and resets the internal sampler.
  24. void clean();
  25. // clean() + resets the dataset. Every time the dataset completes a full round of data
  26. // output, it must be reset.
  27. void reset();