数据是深度学习的基础,有好的数据输入,可以对整个深度神经网络训练起到非常积极的作用。所以在获取到原始的数据集后,数据加载训练前,因为数据量、性能等等限制,往往会需要先进行数据处理或者数据增强,从而获得更加优化的数据输入。
同样,MindSpore也为用户提供了数据处理以及数据增强的功能。
从本质上来说,数据增强是通过数据处理中的
map
(映射)进行实现,但是因为数据增强提供丰富的变换操作,所以将其单独提出进行描述。
MindSpore支持多种处理数据操作,包括复制、分批、洗牌、映射等等,详细见下表:
数据处理 | 说明 |
---|---|
repeat | 对数据集进行复制,来加倍数据量。 |
batch | 将数据分批处理,有益于加速训练过程。 |
shuffle | 对数据进行混洗。 |
map | 将提供的函数或算子作用于指定的列数据。 |
zip | 将多个数据集合并成一个数据集。 |
各个操作可以单独进行使用,实际使用过程中往往会根据实际需要进行组合使用,组合使用时推荐使用的顺序如下所示:
如下示例中,读取MNIST数据集时,对数据进行shuffle、batch、repeat操作。
import mindspore.dataset as ds
ds1 = ds.MnistDataset(MNIST_DATASET_PATH, MNIST_SCHEMA) # Create MNIST dataset.
ds1 = ds1.shuffle(buffer_size=10000)
ds1 = ds1.batch(32, drop_remainder=True)
ds1 = ds1.repeat(10)
上面操作先对数据进行混洗,再将每32条数据组成一个batch,最后将数据集重复10次。
下面将构造一个简单数据集ds1
,并对其进行数据处理操作,来介绍各类数据处理操作的详细使用。
import mindspore.dataset as ds
generator_func()
用于生成数据集。
def generator_func():
for i in range(5):
yield (np.array([i, i+1, i+2]),)
GeneratorDataset
创建ds1
数据集,用于执行数据处理操作。
ds1 = ds.GeneratorDataset(generator_func, ["data"])
print("ds1:")
for data in ds1.create_dict_iterator():
print(data["data"])
ds1:
[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]
在有限的数据集内,为了优化网络,通常会将一个数据集训练多次。
在机器学习中,每训练完一个完整的数据集,我们称为训练完了一个epoch。
加倍数据集,通常用在多个epoch(迭代)训练中,通过repeat()
来加倍数据量。repeat()
定义如下:
def repeat(self, count=None):
我们可以定义ds2
数据集,调用repeat
来加倍数据量。示例代码如下:
ds2 = ds.GeneratorDataset(generator_func, ["data"])
ds2 = ds2.repeat(2)
print("ds2:")
for data in ds2.create_dict_iterator():
print(data["data"])
其中,将倍数设为2,故ds2
数据量为原始数据集ds1
的2倍,输出:
ds2:
[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]
[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]
将数据集进行分批。在实际训练中,可将数据分批处理,将几个数据作为1组,进行训练,减少训练轮次,达到加速训练过程的目的。MindSpore通过batch()
函数来实现数据集分批,函数定义如下:
def batch(self, batch_size, drop_remainder=False, num_parallel_workers=None)
使用GeneratorDataset产生的数据集ds1
构建2个数据集。
ds2
,每2条数据为1组。ds3
,每3条数据为1组,并将不足1组的数据截掉。ds2
示例代码如下:
ds2 = ds1.batch(batch_size=2) # Default drop_remainder is False, the last remainder batch isn't dropped.
print("batch size:2 drop remainder:False")
for data in ds2.create_dict_iterator():
print(data["data"])
输出如下所示:
batch size:2 drop remainder:False
[[0 1 2]
[1 2 3]]
[[2 3 4]
[3 4 5]]
[[4 5 6]]
ds3
示例代码如下:
ds3 = ds1.batch(batch_size=3, drop_remainder=True) # When drop_remainder is True, the last remainder batch will be dropped.
print("batch size:3 drop remainder:True")
for data in ds3.create_dict_iterator():
print(data["data"])
输出如下所示:
batch size:3 drop remainder:True
[[0 1 2]
[1 2 3]
[2 3 4]]
对于有序的数据集或者进行过repeat的数据集可以进行混洗。
shuffle操作主要用来将数据混洗,设定的buffer_size越大,混洗程度越大,但时间、计算资源消耗会大。
shuffle()
定义如下:
def shuffle(self, buffer_size):
调用shuffle()
对数据集ds1
进行混洗,示例代码如下:
print("Before shuffle:")
for data in ds1.create_dict_iterator():
print(data["data"])
ds2 = ds1.shuffle(buffer_size=5)
print("After shuffle:")
for data in ds2.create_dict_iterator():
print(data["data"])
可能的输出如下,可以看到进行数据混洗后,数据的顺序发生了随机的变化。
Before shuffle:
[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]
After shuffle:
[3 4 5]
[2 3 4]
[4 5 6]
[1 2 3]
[0 1 2]
map(映射)即对数据进行处理,譬如将彩色图片的数据集转化为灰色图片的数据集等,应用非常灵活。
MindSpore提供map()
函数对数据集进行映射操作,用户可以将提供的函数或算子作用于指定的列数据。
用户可以自定义函数,也可以直接使用c_transforms
或py_transforms
做数据增强。
详细的数据增强操作,将在文后数据增强章节进行介绍。
map()
函数定义如下:
def map(self, input_columns=None, operations=None, output_columns=None, columns_order=None,
num_parallel_workers=None):
在以下示例中,使用map()
函数,将定义的匿名函数(lambda函数)作用于数据集ds1
,使数据集中数据乘以2。
func = lambda x : x*2 # Define lambda function to multiply each element by 2.
ds2 = ds1.map(input_columns="data", operations=func)
for data in ds2.create_dict_iterator():
print(data["data"])
代码输出如下,可以看到数据集ds2
中各行的数据均乘以了2。
[0 2 4]
[2 4 6]
[4 6 8]
[6 8 10]
[8 10 12]
MindSpore提供zip()
函数,可将多个数据集合并成1个数据集。
如果两个数据集的列名相同,则不会合并,请注意列的命名。
如果两个数据集的行数不同,合并后的行数将和较小行数保持一致。
def zip(self, datasets):
采用前面构造数据集ds1
的方法,构造1个数据集ds2
。
def generator_func2():
for i in range(5):
yield (np.array([i-3, i-2, i-1]),)
ds2 = ds.GeneratorDataset(generator_func2, ["data2"])
通过zip()
将数据集ds1
的data1
列和数据集ds2
的data2
列合并成数据集ds3
。
ds3 = ds.zip((ds1, ds2))
for data in ds3.create_dict_iterator():
print(data)
输出如下所示:
{'data1': array([0, 1, 2], dtype=int64), 'data2': array([-3, -2, -1], dtype=int64)}
{'data1': array([1, 2, 3], dtype=int64), 'data2': array([-2, -1, 0], dtype=int64)}
{'data1': array([2, 3, 4], dtype=int64), 'data2': array([-1, 0, 1], dtype=int64)}
{'data1': array([3, 4, 5], dtype=int64), 'data2': array([0, 1, 2], dtype=int64)}
{'data1': array([4, 5, 6], dtype=int64), 'data2': array([1, 2, 3], dtype=int64)}
在图片训练中,尤其在数据集较小的情况下,用户可以通过一系列的数据增强操作对图片进行预处理,从而丰富了数据集。
MindSpore提供c_transforms
模块以及py_transforms
模块函数供用户进行数据增强操作,用户也可以自定义函数或者算子进行数据增强。MindSpore提供的两个模块的简要说明如下表,详细的介绍请参考API中对应模块的说明。
模块名称 | 实现 | 说明 |
---|---|---|
c_transforms |
基于C++的OpenCV实现 | 具有较高的性能。 |
py_transforms |
基于Python的PIL实现 | 该模块提供了多种图像增强功能,并提供了PIL Image和numpy数组之间的传输方法。 |
对于喜欢在图像学习任务中使用Python PIL的用户,py_transforms
模块是处理图像增强的好工具。用户还可以使用Python PIL自定义自己的扩展。
数据增强需要使用map()
函数,详细map()
函数的使用,可参考map章节。
c_transforms
模块进行数据增强import mindspore.dataset.transforms.vision.c_transforms as transforms
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
Resize
为例:
dataset = ds.ImageFolderDatasetV2(DATA_DIR, decode=True) # Deocde images.
resize_op = transforms.Resize(size=(500,500), interpolation=Inter.LINEAR)
dataset.map(input_columns="image", operations=resize_op)
for data in dataset.create_dict_iterator():
imgplot_resized = plt.imshow(data["image"])
plt.show()
运行结果可以看到,原始图片与进行数据处理(Resize()
)后的图片对比,可以看到图片由原来的1024*683像素,变化为500*500像素。
图1:原始图片
图2:重设尺寸后的图片
py_transforms
模块进行数据增强import mindspore.dataset.transforms.vision.py_transforms as transforms
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
ComposeOp
接口将多个数据增强组合使用, 以RandomCrop
为例:
dataset = ds.ImageFolderDatasetV2(DATA_DIR)
transforms_list = [
transforms.Decode(), # Decode images to PIL format.
transforms.RandomCrop(size=(500,500)),
transforms.ToTensor() # Convert PIL images to Numpy ndarray.
]
compose = transforms.ComposeOp(transforms_list)
dataset = dataset.map(input_columns="image", operations=compose())
for data in dataset.create_dict_iterator():
print(data["image"])
imgplot_resized = plt.imshow(data["image"].transpose(1, 2, 0))
plt.show()
运行结果可以看到,原始图片与进行数据处理(RandomCrop()
)后的图片对比,可以看到图片由原来的1024*683像素,变化为500*500像素。
图1:原始图片
图2:按500*500随机裁剪后的图片
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。