{ "cells": [ { "cell_type": "markdown", "source": [ "# Optimizing the Data Processing\n", "\n", "`Ascend` `GPU` `CPU` `Data Preparation`\n", "\n", "[![Run in ModelArts](https://gitee.com/mindspore/docs/raw/r1.6/resource/_static/logo_modelarts_en.png)](https://authoring-modelarts-cnnorth4.huaweicloud.com/console/lab?share-url-b64=aHR0cHM6Ly9taW5kc3BvcmUtd2Vic2l0ZS5vYnMuY24tbm9ydGgtNC5teWh1YXdlaWNsb3VkLmNvbS9ub3RlYm9vay9tYXN0ZXIvcHJvZ3JhbW1pbmdfZ3VpZGUvZW4vbWluZHNwb3JlX29wdGltaXplX2RhdGFfcHJvY2Vzc2luZy5pcHluYg==&imageid=65f636a0-56cf-49df-b941-7d2a07ba8c8c) [![Download Notebook](https://gitee.com/mindspore/docs/raw/r1.6/resource/_static/logo_notebook_en.png)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r1.6/programming_guide/en/mindspore_optimize_data_processing.ipynb) [![View Source On Gitee](https://gitee.com/mindspore/docs/raw/r1.6/resource/_static/logo_source_en.png)](https://gitee.com/mindspore/docs/blob/r1.6/docs/mindspore/programming_guide/source_en/optimize_data_processing.ipynb)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Overview\n", "\n", "Data is the most important factor of deep learning. Data quality determines the upper limit of deep learning result, whereas model quality enables the result to approach the upper limit. Therefore, high-quality data input is beneficial to the entire deep neural network. During the entire data processing and data augmentation process, data continuously flows through a pipeline to the training system." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "![pipeline](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/pipeline.png)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "MindSpore provides data processing and data augmentation functions for users. In the pipeline process, if each step can be properly used, the data performance will be greatly improved. This section describes how to optimize performance during data loading, data processing, and data augmentation based on the [CIFAR-10 dataset[1]](#references).\n", "\n", "In addition, the storage, architecture and computing resources of the operating system will influence the performance of data processing to a certain extent.\n", "\n", "## Preparations\n", "\n", "### Importing Modules\n", "\n", "The `dataset` module provides APIs for loading and processing datasets." ], "metadata": {} }, { "cell_type": "code", "execution_count": 1, "source": [ "import mindspore.dataset as ds" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "The `numpy` module is used to generate ndarrays." ], "metadata": {} }, { "cell_type": "code", "execution_count": 2, "source": [ "import numpy as np" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Downloading the Required Dataset\n", "\n", "Run the following command to download the dataset:\n", "Download the CIFAR-10 Binary format dataset, decompress them and store them in the `./datasets` path, use this dataset when loading data." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "import os\n", "import requests\n", "import tarfile\n", "import zipfile\n", "import shutil\n", "\n", "requests.packages.urllib3.disable_warnings()\n", "\n", "def download_dataset(url, target_path):\n", " \"\"\"download and decompress dataset\"\"\"\n", " if not os.path.exists(target_path):\n", " os.makedirs(target_path)\n", " download_file = url.split(\"/\")[-1]\n", " if not os.path.exists(download_file):\n", " res = requests.get(url, stream=True, verify=False)\n", " if download_file.split(\".\")[-1] not in [\"tgz\", \"zip\", \"tar\", \"gz\"]:\n", " download_file = os.path.join(target_path, download_file)\n", " with open(download_file, \"wb\") as f:\n", " for chunk in res.iter_content(chunk_size=512):\n", " if chunk:\n", " f.write(chunk)\n", " if download_file.endswith(\"zip\"):\n", " z = zipfile.ZipFile(download_file, \"r\")\n", " z.extractall(path=target_path)\n", " z.close()\n", " if download_file.endswith(\".tar.gz\") or download_file.endswith(\".tar\") or download_file.endswith(\".tgz\"):\n", " t = tarfile.open(download_file)\n", " names = t.getnames()\n", " for name in names:\n", " t.extract(name, target_path)\n", " t.close()\n", " print(\"The {} file is downloaded and saved in the path {} after processing\".format(os.path.basename(url), target_path))\n", "\n", "download_dataset(\"https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz\", \"./datasets\")\n", "test_path = \"./datasets/cifar-10-batches-bin/test\"\n", "train_path = \"./datasets/cifar-10-batches-bin/train\"\n", "os.makedirs(test_path, exist_ok=True)\n", "os.makedirs(train_path, exist_ok=True)\n", "if not os.path.exists(os.path.join(test_path, \"test_batch.bin\")):\n", " shutil.move(\"./datasets/cifar-10-batches-bin/test_batch.bin\", test_path)\n", "[shutil.move(\"./datasets/cifar-10-batches-bin/\"+i, train_path) for i in os.listdir(\"./datasets/cifar-10-batches-bin/\") if os.path.isfile(\"./datasets/cifar-10-batches-bin/\"+i) and not i.endswith(\".html\") and not os.path.exists(os.path.join(train_path, i))]" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "The directory structure of the downloaded dataset file is as follows:\n", "\n", "```text\n", "./datasets/cifar-10-batches-bin\n", "├── readme.html\n", "├── test\n", "│ └── test_batch.bin\n", "└── train\n", " ├── batches.meta.txt\n", " ├── data_batch_1.bin\n", " ├── data_batch_2.bin\n", " ├── data_batch_3.bin\n", " ├── data_batch_4.bin\n", " └── data_batch_5.bin\n", "```" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Download cifar-10 Python file format dataset, decompress them in the `./datasets/cifar-10-batches-py` path, use this dataset when converting data." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "download_dataset(\"https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-python.tar.gz\", \"./datasets\")" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "The directory structure of the extracted dataset file is as follows:\n", "\n", "```text\n", "./datasets/cifar-10-batches-py\n", "├── batches.meta\n", "├── data_batch_1\n", "├── data_batch_2\n", "├── data_batch_3\n", "├── data_batch_4\n", "├── data_batch_5\n", "├── readme.html\n", "└── test_batch\n", "```" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Optimizing the Data Loading Performance\n", "\n", "MindSpore provides multiple data loading methods, including common dataset loading, user-defined dataset loading, and the MindSpore data format loading. The dataset loading performance varies depending on the underlying implementation method.\n", "\n", "| | Common Dataset | User-defined Dataset | MindRecord Dataset |\n", "| :----: | :----: | :----: | :----: |\n", "| Underlying implementation | C++ | Python | C++ |\n", "| Performance | High | Medium | High |\n", "\n", "### Performance Optimization Solution" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "![data-loading-performance-scheme](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/data_loading_performance_scheme.png)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Suggestions on data loading performance optimization are as follows:\n", "\n", "- Built-in loading operators are preferred for supported dataset formats. For details, see [Built-in Loading Operators](https://www.mindspore.cn/docs/api/en/r1.6/api_python/mindspore.dataset.html), if the performance cannot meet the requirements, use the multi-thread concurrency solution. For details, see [Multi-thread Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-thread-optimization-solution).\n", "- For a dataset format that is not supported, convert the format to the mindspore data format and then use the `MindDataset` class to load the dataset (Please refer to the [API](https://www.mindspore.cn/docs/api/en/r1.6/api_python/dataset/mindspore.dataset.MindDataset.html) for detailed use). Please refer to [Converting Dataset to MindRecord](https://www.mindspore.cn/docs/programming_guide/en/r1.6/convert_dataset.html), if the performance cannot meet the requirements, use the multi-thread concurrency solution, for details, see [Multi-thread Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-thread-optimization-solution).\n", "- For dataset formats that are not supported, the user-defined `GeneratorDataset` class is preferred for implementing fast algorithm verification (Please refer to the [API](https://www.mindspore.cn/docs/api/en/r1.6/api_python/dataset/mindspore.dataset.GeneratorDataset.html) for detailed use), if the performance cannot meet the requirements, the multi-process concurrency solution can be used. For details, see [Multi-process Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-process-optimization-solution).\n", "\n", "### Code Example\n", "\n", "Based on the preceding suggestions of data loading performance optimization, the `Cifar10Dataset` class of built-in loading operators (Please refer to the [API](https://www.mindspore.cn/docs/api/en/r1.6/api_python/dataset/mindspore.dataset.Cifar10Dataset.html) for detailed use), the `MindDataset` class after data conversion, and the `GeneratorDataset` class are used to load data. The sample code is displayed as follows:\n", "\n", "1. Use the `Cifar10Dataset` class of built-in operators to load the CIFAR-10 dataset in binary format. The multi-thread optimization solution is used for data loading. Four threads are enabled to concurrently complete the task. Finally, a dictionary iterator is created for the data and a data record is read through the iterator." ], "metadata": {} }, { "cell_type": "code", "execution_count": 5, "source": [ "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n", "\n", "# create Cifar10Dataset for reading data\n", "cifar10_dataset = ds.Cifar10Dataset(cifar10_path, num_parallel_workers=4)\n", "# create a dictionary iterator and read a data record through the iterator\n", "print(next(cifar10_dataset.create_dict_iterator()))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n", "[[[209, 206, 192],\n", " [211, 209, 201],\n", " [221, 217, 213],\n", " ...\n", " [172, 175, 194],\n", " [169, 173, 190],\n", " [115, 121, 145]],\n", " [[226, 230, 211],\n", " [227, 229, 218],\n", " [230, 232, 221],\n", " ...\n", " [153, 153, 171],\n", " [156, 156, 173],\n", " [106, 111, 129]],\n", " [[214, 226, 203],\n", " [214, 222, 204],\n", " [217, 227, 206],\n", " ...\n", " [167, 166, 176],\n", " [147, 147, 156],\n", " [ 78, 84, 96]],\n", " ...\n", " [[ 40, 69, 61],\n", " [ 37, 63, 57],\n", " [ 43, 68, 66],\n", " ...\n", " [ 55, 70, 69],\n", " [ 40, 54, 51],\n", " [ 27, 44, 36]],\n", " [[ 33, 61, 50],\n", " [ 37, 65, 56],\n", " [ 54, 72, 74],\n", " ...\n", " [ 47, 60, 56],\n", " [ 58, 66, 64],\n", " [ 36, 50, 46]],\n", " [[ 29, 41, 37],\n", " [ 38, 60, 59],\n", " [ 51, 76, 81],\n", " ...\n", " [ 32, 51, 43],\n", " [ 47, 61, 54],\n", " [ 56, 67, 66]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 5)}\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "2. Use the `Cifar10ToMR` class to convert the CIFAR-10 dataset into the MindSpore data format. In this example, the CIFAR-10 dataset in Python file format is used. Then use the `MindDataset` class to load the dataset in the MindSpore data format. The multi-thread optimization solution is used for data loading. Four threads are enabled to concurrently complete the task. Finally, a dictionary iterator is created for data and a data record is read through the iterator." ], "metadata": {} }, { "cell_type": "code", "execution_count": 6, "source": [ "import os\n", "from mindspore.mindrecord import Cifar10ToMR\n", "\n", "trans_path = \"./transform/\"\n", "\n", "if not os.path.exists(trans_path):\n", " os.mkdir(trans_path)\n", "\n", "os.system(\"rm -f {}cifar10*\".format(trans_path))\n", "\n", "cifar10_path = './datasets/cifar-10-batches-py'\n", "cifar10_mindrecord_path = './transform/cifar10.record'\n", "\n", "cifar10_transformer = Cifar10ToMR(cifar10_path, cifar10_mindrecord_path)\n", "# execute transformation from CIFAR-10 to MindRecord\n", "cifar10_transformer.transform(['label'])\n", "\n", "# create MindDataset for reading data\n", "cifar10_mind_dataset = ds.MindDataset(dataset_files=cifar10_mindrecord_path, num_parallel_workers=4)\n", "# create a dictionary iterator and read a data record through the iterator\n", "print(next(cifar10_mind_dataset.create_dict_iterator()))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "{'data': Tensor(shape=[1283], dtype=UInt8, value= [255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255, 219, 0, 67, \n", " 107, 249, 17, 58, 213, 185, 117, 181, 143, 255, 217]), 'id': Tensor(shape=[], dtype=Int64, value= 32476), 'label': Tensor(shape=[], dtype=Int64, value= 9)}\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "3. The `GeneratorDataset` class is used to load the user-defined dataset, and the multi-process optimization solution is used. Four processes are enabled to concurrently complete the task. Finally, a dictionary iterator is created for the data, and a data record is read through the iterator." ], "metadata": {} }, { "cell_type": "code", "execution_count": 7, "source": [ "def generator_func(num):\n", " for i in range(num):\n", " yield (np.array([i]),)\n", "\n", "# create a GeneratorDataset object for reading data\n", "dataset = ds.GeneratorDataset(source=generator_func(5), column_names=[\"data\"], num_parallel_workers=4)\n", "# create a dictionary iterator and read a data record through the iterator\n", "print(next(dataset.create_dict_iterator()))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "{'data': Tensor(shape=[1], dtype=Int64, value= [0])}\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Optimizing the Shuffle Performance\n", "\n", "The shuffle operation is used to shuffle ordered datasets or repeated datasets. MindSpore provides the `shuffle` function for users. A larger value of `buffer_size` indicates a higher shuffling degree, consuming more time and computing resources. This API allows users to shuffle the data at any time during the entire pipeline process.Please refer to [shuffle](https://www.mindspore.cn/docs/programming_guide/en/r1.6/pipeline.html#shuffle). However, because the underlying implementation methods are different, the performance of this method is not as good as that of setting the `shuffle` parameter to directly shuffle data by referring to the [Built-in Loading Operators](https://www.mindspore.cn/docs/api/en/r1.6/api_python/mindspore.dataset.html).\n", "\n", "### Performance Optimization Solution" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "![shuffle-performance-scheme](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/shuffle_performance_scheme.png)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Suggestions on shuffle performance optimization are as follows:\n", "\n", "- Use the `shuffle` parameter of built-in loading operators to shuffle data.\n", "- If the `shuffle` function is used and the performance still cannot meet the requirements, adjust the value of the `buffer_size` parameter to improve the performance.\n", "\n", "### Code Example\n", "\n", "Based on the preceding shuffle performance optimization suggestions, the `shuffle` parameter of the `Cifar10Dataset` class of built-in loading operators and the `Shuffle` function are used to shuffle data. The sample code is displayed as follows:\n", "\n", "1. Use the `Cifar10Dataset` class of built-in operators to load the CIFAR-10 dataset. In this example, the CIFAR-10 dataset in binary format is used, and the `shuffle` parameter is set to True to perform data shuffle. Finally, a dictionary iterator is created for the data and a data record is read through the iterator." ], "metadata": {} }, { "cell_type": "code", "execution_count": 8, "source": [ "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n", "\n", "# create Cifar10Dataset for reading data\n", "cifar10_dataset = ds.Cifar10Dataset(cifar10_path, shuffle=True)\n", "# create a dictionary iterator and read a data record through the iterator\n", "print(next(cifar10_dataset.create_dict_iterator()))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n", "[[[119, 193, 196],\n", " [121, 192, 204],\n", " [123, 193, 209],\n", " ...\n", " [110, 168, 177],\n", " [109, 167, 176],\n", " [110, 168, 178]],\n", " [[110, 188, 199],\n", " [109, 185, 202],\n", " [111, 186, 204],\n", " ...\n", " [107, 173, 179],\n", " [107, 173, 179],\n", " [109, 175, 182]],\n", " [[110, 186, 200],\n", " [108, 183, 199],\n", " [110, 184, 199],\n", " ...\n", " [115, 183, 189],\n", " [117, 185, 190],\n", " [117, 185, 191]],\n", " ...\n", " [[210, 253, 250],\n", " [212, 251, 250],\n", " [214, 250, 249],\n", " ...\n", " [194, 247, 247],\n", " [190, 246, 245],\n", " [184, 245, 244]],\n", " [[215, 253, 251],\n", " [218, 252, 250],\n", " [220, 251, 249],\n", " ...\n", " [200, 248, 248],\n", " [195, 247, 245],\n", " [189, 245, 244]],\n", " [[216, 253, 253],\n", " [222, 251, 250],\n", " [225, 250, 249],\n", " ...\n", " [204, 249, 248],\n", " [200, 246, 244],\n", " [196, 245, 244]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 0)}\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "2. Use the `shuffle` function to shuffle data. Set `buffer_size` to 3 and use the `GeneratorDataset` class to generate data." ], "metadata": {} }, { "cell_type": "code", "execution_count": 9, "source": [ "def generator_func():\n", " for i in range(5):\n", " yield (np.array([i, i+1, i+2, i+3, i+4]),)\n", "\n", "ds1 = ds.GeneratorDataset(source=generator_func, column_names=[\"data\"])\n", "print(\"before shuffle:\")\n", "for data in ds1.create_dict_iterator():\n", " print(data[\"data\"])\n", "\n", "ds2 = ds1.shuffle(buffer_size=3)\n", "print(\"after shuffle:\")\n", "for data in ds2.create_dict_iterator():\n", " print(data[\"data\"])" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "before shuffle:\n", "[0 1 2 3 4]\n", "[1 2 3 4 5]\n", "[2 3 4 5 6]\n", "[3 4 5 6 7]\n", "[4 5 6 7 8]\n", "after shuffle:\n", "[2 3 4 5 6]\n", "[0 1 2 3 4]\n", "[1 2 3 4 5]\n", "[4 5 6 7 8]\n", "[3 4 5 6 7]\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Optimizing the Data Augmentation Performance\n", "\n", "During image classification training, especially when the dataset is small, users can use data augmentation to preprocess images to enrich the dataset. MindSpore provides multiple data augmentation methods, including:\n", "\n", "- Use the built-in C operator (`c_transforms` module) to perform data augmentation.\n", "- Use the built-in Python operator (`py_transforms` module) to perform data augmentation.\n", "- Users can define Python functions as needed to perform data augmentation.\n", "\n", "Please refer to [Data Augmentation](https://www.mindspore.cn/docs/programming_guide/en/r1.6/augmentation.html). The performance varies according to the underlying implementation methods.\n", "\n", "| Module | Underlying API | Description |\n", "| :----: | :----: | :----: |\n", "| c_transforms | C++ (based on OpenCV) | High performance |\n", "| py_transforms | Python (based on PIL) | This module provides multiple image augmentation functions and the method for converting PIL images into NumPy arrays |\n", "\n", "### Performance Optimization Solution" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "![data-enhancement-performance-scheme](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/data_enhancement_performance_scheme.png)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Suggestions on data augmentation performance optimization are as follows:\n", "\n", "- The `c_transforms` module is preferentially used to perform data augmentation for its highest performance. If the performance cannot meet the requirements, refer to [Multi-thread Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-thread-optimization-solution), [Compose Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#compose-optimization-solution), or [Operator Fusion Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#operator-fusion-optimization-solution).\n", "- If the `py_transforms` module is used to perform data augmentation and the performance still cannot meet the requirements, refer to [Multi-thread Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-thread-optimization-solution), [Multi-process Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-process-optimization-solution), [Compose Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#compose-optimization-solution), or [Operator Fusion Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#operator-fusion-optimization-solution).\n", "- The `c_transforms` module maintains buffer management in C++, and the `py_transforms` module maintains buffer management in Python. Because of the performance cost of switching between Python and C++, it is advised not to use different operator types together.\n", "- If the user-defined Python functions are used to perform data augmentation and the performance still cannot meet the requirements, use the [Multi-thread Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-thread-optimization-solution) or [Multi-process Optimization Solution](https://www.mindspore.cn/docs/programming_guide/en/r1.6/optimize_data_processing.html#multi-process-optimization-solution). If the performance still cannot be improved, in this case, optimize the user-defined Python code.\n", "\n", "MindSpore also supports users to use the data enhancement methods in the `c_transforms` and `py_transforms` modules at the same time, but due to the different underlying implementations of the two, excessive mixing will increase resource overhead and reduce processing performance. It is recommended that users can use the operators in `c_transforms` or `py_transforms` alone; or use one of them first, and then use the other. Please do not switch frequently between the data enhancement interface of two different implementation modules.\n", "\n", "### Code Example\n", "\n", "Based on the preceding suggestions of data augmentation performance optimization, the `c_transforms` module and user-defined Python function are used to perform data augmentation. The code is displayed as follows:\n", "\n", "1. The `c_transforms` module is used to perform data augmentation. During data augmentation, the multi-thread optimization solution is used. Four threads are enabled to concurrently complete the task. The operator fusion optimization solution is used and the `RandomResizedCrop` fusion class is used to replace the `RandomResize` and `RandomCrop` classes." ], "metadata": {} }, { "cell_type": "code", "execution_count": 10, "source": [ "import mindspore.dataset.vision.c_transforms as C\n", "import matplotlib.pyplot as plt\n", "\n", "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n", "\n", "# create Cifar10Dataset for reading data\n", "cifar10_dataset = ds.Cifar10Dataset(cifar10_path, num_parallel_workers=4)\n", "transforms = C.RandomResizedCrop((800, 800))\n", "# apply the transform to the dataset through dataset.map()\n", "cifar10_dataset = cifar10_dataset.map(operations=transforms, input_columns=\"image\", num_parallel_workers=4)\n", "\n", "data = next(cifar10_dataset.create_dict_iterator())\n", "plt.imshow(data[\"image\"].asnumpy())\n", "plt.show()" ], "outputs": [ { "output_type": "display_data", "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" } } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "2. A user-defined Python function is used to perform data augmentation. During data augmentation, the multi-process optimization solution is used, and four processes are enabled to concurrently complete the task." ], "metadata": {} }, { "cell_type": "code", "execution_count": 11, "source": [ "def generator_func():\n", " for i in range(5):\n", " yield (np.array([i, i+1, i+2, i+3, i+4]),)\n", "\n", "ds3 = ds.GeneratorDataset(source=generator_func, column_names=[\"data\"])\n", "print(\"before map:\")\n", "for data in ds3.create_dict_iterator():\n", " print(data[\"data\"])\n", "\n", "func = lambda x: x**2\n", "ds4 = ds3.map(operations=func, input_columns=\"data\", python_multiprocessing=True, num_parallel_workers=4)\n", "print(\"after map:\")\n", "for data in ds4.create_dict_iterator():\n", " print(data[\"data\"])" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "before map:\n", "[0 1 2 3 4]\n", "[1 2 3 4 5]\n", "[2 3 4 5 6]\n", "[3 4 5 6 7]\n", "[4 5 6 7 8]\n", "after map:\n", "[ 0 1 4 9 16]\n", "[ 1 4 9 16 25]\n", "[ 4 9 16 25 36]\n", "[ 9 16 25 36 49]\n", "[16 25 36 49 64]\n" ] } ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Optimizing the Operating System Performance\n", "\n", "Data processing is performed on the host. Therefore, configurations of the host or operating system may affect the performance of data processing. Major factors include storage, NUMA architecture, and CPU (computing resources).\n", "\n", "1. Storage\n", "\n", " The data loading process involves frequent disk operations, and the performance of disk reading and writing directly affects the speed of data loading. Solid State Drive (SSD) is recommended for storing large datasets. SSD reduces the impact of I/O on data processing.\n", "\n", " > In most cases, after a dataset is loaded, it is stored in page cache of the operating system. To some extent, this reduces I/O overheads and accelerates reading subsequent epochs.\n", "\n", "2. NUMA architecture\n", "\n", " NUMA (Non-uniform Memory Architecture) is developed to solve the scalability problem of traditional Symmetric Multi-processor systems. The NUMA system has multiple memory buses. Several processors are connected to one memory via memory bus to form a group. This way, the entire large system is divided into several groups, the concept of this group is called a node in the NUMA system. Memory belonging to this node is called local memory, memory belonging to other nodes (with respect to this node) is called foreign memory. Therefore, the latency for each node to access its local memory is different from accessing foreign memory. This needs to be avoided during data processing. Generally, the following command can be used to bind a process to a node:\n", "\n", " ```bash\n", " numactl --cpubind=0 --membind=0 python train.py\n", " ```\n", "\n", " The example above binds the `train.py` process to `numa node` 0." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "3. CPU (computing resource)\n", "\n", " Although the data processing speed can be accelerated through multi-threaded parallel technology, there is actually no guarantee that CPU computing resources will be fully utilized. If you can artificially complete the configuration of computing resources in advance, it will be able to improve the utilization of CPU computing resources to a certain extent.\n", "\n", " - Resource allocation\n", "\n", " In distributed training, multiple training processes are run on one device. These training processes allocate and compete for computing resources based on the policy of the operating system. When there is a large number of processes, data processing performance may deteriorate due to resource contention. In some cases, users need to manually allocate resources to avoid resource contention.\n", "\n", " ```bash\n", " numactl --cpubind=0 python train.py\n", " ```\n", "\n", " or\n", "\n", " ```bash\n", " taskset -c 0-15 python train.py\n", " ```\n", "\n", " > The `numactl` method directly specifies `numa node id`. The `taskset` method allows for finer control by specifying `cpu core` within a `numa node`. The `core id` range from 0 to 15.\n", "\n", " - CPU frequency\n", "\n", " The setting of CPU frequency is critical to maximizing the computing power of the host CPU. Generally, the Linux kernel supports the tuning of the CPU frequency to reduce power consumption. Power consumption can be reduced to varying degrees by selecting power management policies for different system idle states. However, lower power consumption means slower CPU wake-up which in turn impacts performance. Therefore, if the CPU's power setting is in the conservative or powersave mode, `cpupower` command can be used to switch performance modes, resulting in significant data processing performance improvement.\n", "\n", " ```bash\n", " cpupower frequency-set -g performance\n", " ```" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Performance Optimization Solution Summary\n", "\n", "### Multi-thread Optimization Solution\n", "\n", "During the data pipeline process, the number of threads for related operators can be set to improve the concurrency and performance. If the user does not manually specify the `num_parallel_workers` parameter, each data processing operation will use 8 sub-threads for concurrent processing by default. For example:\n", "\n", "- During data loading, the `num_parallel_workers` parameter in the built-in data loading class is used to set the number of threads.\n", "- During data augmentation, the `num_parallel_workers` parameter in the `map` function is used to set the number of threads.\n", "- During batch processing, the `num_parallel_workers` parameter in the `batch` function is used to set the number of threads.\n", "\n", "For details, see [Built-in Loading Operators](https://www.mindspore.cn/docs/api/en/r1.6/api_python/mindspore.dataset.html).\n", "\n", "When using MindSpore for standalone or distributed training, the setting of the `num_parallel_workers` parameter should follow the following principles:\n", "\n", "- The summary of the `num_parallel_workers` parameter set for each data loading and processing operation should not be greater than the maximum number of CPU cores of the machine, otherwise it will cause resource competition between each operation.\n", "- Before setting the `num_parallel_workers` parameter, it is recommended to use MindSpore's Profiler (performance analysis) tool to analyze the performance of each operation in the training, and allocate more resources to the operation with pool performance, that is, set a large `num_parallel_workers` to balance the throughput between various operations and avoid unnecessary waiting.\n", "- In a standalone training scenario, increasing the `num_parallel_workers` parameter can often directly improve processing performance, but in a distributed scenario, due to increased CPU competition, blindly increasing `num_parallel_workers` may lead to performance degradation. You need to try to use a compromise value.\n", "\n", "### Multi-process Optimization Solution\n", "\n", "During data processing, operators implemented by Python support the multi-process mode. For example:\n", "\n", "- By default, the `GeneratorDataset` class is in multi-process mode. The `num_parallel_workers` parameter indicates the number of enabled processes. The default value is 1. For details, see [GeneratorDataset](https://www.mindspore.cn/docs/api/en/r1.6/api_python/dataset/mindspore.dataset.GeneratorDataset.html).\n", "- If the user-defined Python function or the `py_transforms` module is used to perform data augmentation and the `python_multiprocessing` parameter of the `map` function is set to True, the `num_parallel_workers` parameter indicates the number of processes and the default value of the `python_multiprocessing` parameter is False. In this case, the `num_parallel_workers` parameter indicates the number of threads. For details, see [Built-in Loading Operators](https://www.mindspore.cn/docs/api/en/r1.6/api_python/mindspore.dataset.html).\n", "\n", "### Compose Optimization Solution\n", "\n", "Map operators can receive the Tensor operator list and apply all these operators based on a specific sequence. Compared with the Map operator used by each Tensor operator, such Fat Map operators can achieve better performance, as shown in the following figure:" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "![compose](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/compose.png)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Operator Fusion Optimization Solution\n", "\n", "Some fusion operators are provided to aggregate the functions of two or more operators into one operator. For details, see [Augmentation Operators](https://www.mindspore.cn/docs/api/en/r1.6/api_python/mindspore.dataset.vision.html). Compared with the pipelines of their components, such fusion operators provide better performance. As shown in the figure:\n", "\n", "![operator-fusion](https://gitee.com/mindspore/docs/raw/r1.6/docs/mindspore/programming_guide/source_en/images/operator_fusion.png)\n", "\n", "### Operating System Optimization Solution\n", "\n", "- Use Solid State Drives to store the data.\n", "- Bind the process to a NUMA node.\n", "- Manually allocate more computing resources.\n", "- Set a higher CPU frequency.\n", "\n", "## References\n", "\n", "[1] Alex Krizhevsky. [Learning Multiple Layers of Features from Tiny Images](http://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf)." ], "metadata": {} } ], "metadata": { "kernelspec": { "display_name": "MindSpore", "language": "python", "name": "mindspore" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }