导入数据集相关库和类
首先,导入了 NumPy 库,并将其简称为 np 。要知道,NumPy 乃是用于科学计算的关键库,作用非凡。接着,从 mindspore.dataset 当中导入了 vision 模块。此外,还从 mindspore.dataset 里引入了 MnistDataset 和 GeneratorDataset 这两个与数据集紧密相关的类。最后,导入了 matplotlib 库的 pyplot 模块,并简称为 plt ,其主要用于实现数据的可视化。
代码如下:
import numpy as np
from mindspore.dataset import vision
from mindspore.dataset import MnistDataset, GeneratorDataset
import matplotlib.pyplot as plt
数据集加载
首先是从开放数据集去下载数据,随后导入了一个叫“download”的功能模块或者函数。接下来,设定了一个字符串变量“url”,这个“url”代表着要下载的数据所在的网址。最后呢,调用“download”这个函数来下载“url”所指定的那些数据,并且把数据存放到当前的目录(“./”)当中。要注意哦,下载的这些数据是压缩文件(zip 格式的),要是本地已经有相同的文件了,那就会进行替换操作。
代码如下:
# Download data from open datasets
from download import download
url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/" \
"notebook/datasets/MNIST_Data.zip"
path = download(url, "./", kind="zip", replace=True)
运行结果:
创建了一个名为 train_dataset 的数据集对象,该数据集是基于“MNIST_Data/train”路径下的数据创建的 MnistDataset 类型,并且设置了不进行随机打乱(shuffle=False)。然后,打印出 train_dataset 的数据类型。
代码如下:
train_dataset = MnistDataset("MNIST_Data/train", shuffle=False)
print(type(train_dataset))
运行结果:
<class 'mindspore.dataset.engine.datasets_vision.MnistDataset'>
数据集迭代
数据集加载后,一般以迭代方式获取数据,然后送入神经网络中进行训练。我们可以用create_tuple_iterator或create_dict_iterator接口创建数据迭代器,迭代访问数据。
访问的数据类型默认为Tensor;若设置output_numpy=True,访问的数据类型为Numpy。
以下定义了一个用于可视化的函数,其旨在对 9 张图片进行迭代展示。此函数的目的在于以 3x3 的布局对数据集中的图像及其对应的标签予以可视化呈现。
代码如下:
def visualize(dataset):
#创建一个大小为 4x4 的图形窗口。
figure = plt.figure(figsize=(4, 4))
#定义了子图的列数和行数,均为 3。
cols, rows = 3, 3
#调整子图之间的水平间距(wspace)和垂直间距(hspace)为 0.5 。
plt.subplots_adjust(wspace=0.5, hspace=0.5)
#通过枚举数据集的迭代器,获取图像和标签。
for idx, (image, label) in enumerate(dataset.create_tuple_iterator()):
#在图形中添加一个子图,位置由当前的索引决定。
figure.add_subplot(rows, cols, idx + 1)
#为子图设置标题,标题内容为标签的整数形式。
plt.title(int(label))
#关闭坐标轴的显示。
plt.axis("off")
#在子图中显示图像,使用灰度颜色映射(cmap="gray")。
plt.imshow(image.asnumpy().squeeze(), cmap="gray")
#当达到 9 个(3x3)子图时,停止循环。
if idx == cols * rows - 1:
break
#显示图形窗口,展示所有的子图。
plt.show()
调用名为 visualize 的函数,并将 train_dataset 作为参数传递给这个函数进行可视化展示。
代码如下:
visualize(train_dataset)
运行结果:(随机)
数据集的常用操作
shuffle
数据集随机shuffle可以消除数据排列造成的分布不均问题。
首先,对名为 train_dataset 的数据集进行打乱操作,打乱时使用的缓冲区大小为 64。然后,调用 visualize 函数,并将打乱后的 train_dataset 作为参数传递给这个函数,以进行相应的可视化展示。
代码如下:
train_dataset = train_dataset.shuffle(buffer_size=64)
visualize(train_dataset)
运行结果:(随机)
map
map操作是数据预处理的关键操作,可以针对数据集指定列(column)添加数据变换(Transforms),将数据变换应用于该列数据的每个元素,并返回包含变换后元素的新数据集。
对数据集 train_dataset 中的数据进行处理和输出信息。
首先,通过 next(train_dataset.create_tuple_iterator()) 获取数据集中的一组数据(图像 image 和标签 label),然后打印出图像的形状和数据类型。接着,使用 map 方法对数据集中的 'image' 列应用 vision.Rescale(1.0 / 255.0, 0) 这个缩放操作,将图像的像素值缩放到 0 到 1 之间。最后,再次获取一组经过缩放处理后的数据,并打印出此时图像的形状和数据类型,以查看缩放操作的效果。
代码如下:
image, label = next(train_dataset.create_tuple_iterator())
print(image.shape, image.dtype)
train_dataset = train_dataset.map(vision.Rescale(1.0 / 255.0, 0), input_columns='image')
image, label = next(train_dataset.create_tuple_iterator())
print(image.shape, image.dtype)
运行结果:
(28, 28, 1) UInt8
(28, 28, 1) Float32
batch
将数据集打包为固定大小的batch是在有限硬件资源下使用梯度下降进行模型优化的折中方法,可以保证梯度下降的随机性和优化计算量。
代码如下:
train_dataset = train_dataset.batch(batch_size=32)
image, label = next(train_dataset.create_tuple_iterator())
print(image.shape, image.dtype)
分析:
首先,train_dataset = train_dataset.batch(batch_size=32) 这行代码将数据集 train_dataset 按照每个批次 32 个样本进行分组。
然后,通过 next(train_dataset.create_tuple_iterator()) 获取经过批次处理后的数据集的一组数据(图像 image 和标签 label)。
最后,打印出获取到的这组图像数据的形状和数据类型。
运行结果:
(32, 28, 28, 1) Float32
自定义数据集
可随机访问数据集
定义了一个名为 RandomAccessDataset 的类,其作用是创建一个可随机访问的数据集对象。
__init__ 方法:这是类的初始化方法。在创建 RandomAccessDataset 对象时会被调用。它初始化了两个 NumPy 数组 _data 和 _label ,_data 是一个 5 行 2 列的全 1 数组,_label 是一个 5 行 1 列的全 0 数组。
__getitem__ 方法:这个方法使得对象可以通过索引(index)来获取数据。当通过索引访问对象时(如 obj[index]),会调用这个方法,并返回指定索引处的 _data 和 _label 的值。
__len__ 方法:这个方法返回数据集的长度,即 _data 的长度(这里是 5)。它用于一些需要知道数据集大小的操作,例如在循环中。
代码如下:
# Random-accessible object as input source
class RandomAccessDataset:
def __init__(self):
self._data = np.ones((5, 2))
self._label = np.zeros((5, 1))
def __getitem__(self, index):
return self._data[index], self._label[index]
def __len__(self):
return len(self._data)
创建了一个 RandomAccessDataset 类的实例 loader 。然后,使用这个实例 loader 作为数据源创建了一个 GeneratorDataset 对象 dataset ,并指定了列名为 ["data", "label"] 。最后,通过一个 for 循环遍历 dataset 中的数据,并打印每次循环得到的数据。
代码如下:
loader = RandomAccessDataset()
dataset = GeneratorDataset(source=loader, column_names=["data", "label"])
for data in dataset:
print(data)
运行结果:
[Tensor(shape=[2], dtype=Float64, value= [ 1.00000000e+00, 1.00000000e+00]), Tensor(shape=[1], dtype=Float64, value= [ 0.00000000e+00])]
[Tensor(shape=[2], dtype=Float64, value= [ 1.00000000e+00, 1.00000000e+00]), Tensor(shape=[1], dtype=Float64, value= [ 0.00000000e+00])]
[Tensor(shape=[2], dtype=Float64, value= [ 1.00000000e+00, 1.00000000e+00]), Tensor(shape=[1], dtype=Float64, value= [ 0.00000000e+00])]
[Tensor(shape=[2], dtype=Float64, value= [ 1.00000000e+00, 1.00000000e+00]), Tensor(shape=[1], dtype=Float64, value= [ 0.00000000e+00])]
[Tensor(shape=[2], dtype=Float64, value= [ 1.00000000e+00, 1.00000000e+00]), Tensor(shape=[1], dtype=Float64, value= [ 0.00000000e+00])]
创建了一个名为 loader 的列表,其中包含三个 numpy 数组:np.array(0) 、np.array(1) 和 np.array(2) 。
接着使用 loader 作为数据源创建了一个名为 dataset 的 GeneratorDataset 对象,并指定列名为 ["data"] 。
最后通过一个 for 循环遍历 dataset 中的数据,并打印每次循环得到的数据。
代码如下:
# list, tuple are also supported.
loader = [np.array(0), np.array(1), np.array(2)]
dataset = GeneratorDataset(source=loader, column_names=["data"])
for data in dataset:
print(data)
运行结果:
[Tensor(shape=[], dtype=Int64, value= 0)]
[Tensor(shape=[], dtype=Int64, value= 1)]
[Tensor(shape=[], dtype=Int64, value= 2)]
可迭代数据集
可迭代的数据集是实现了__iter__和__next__方法的数据集,表示可以通过迭代的方式逐步获取数据样本。这种类型的数据集特别适用于随机访问成本太高或者不可行的情况。
代码如下:
# Iterator as input source
class IterableDataset():
def __init__(self, start, end):
'''''init the class object to hold the data'''
self.start = start
self.end = end
def __next__(self):
'''''iter one data and return'''
return next(self.data)
def __iter__(self):
'''''reset the iter'''
self.data = iter(range(self.start, self.end))
return self
分析:定义了一个名为 IterableDataset 的类。
__init__ 方法:用于初始化类的对象,接收 start 和 end 两个参数,用于表示数据的起始和结束范围。
__next__ 方法:每次迭代时取出一个数据并返回。但这里的实现存在问题,因为代码中没有定义 self.data ,直接使用 next(self.data) 会导致错误。正确的实现应该是从已经初始化的 self.data 中获取下一个元素。
__iter__ 方法:在每次迭代开始时,将 range(self.start, self.end) 转换为一个迭代器,并将其赋值给 self.data ,然后返回自身,使得该对象可用于迭代操作。
总的来说,这个类的目的是创建一个可迭代的数据集对象,能够在迭代时依次返回指定范围内的整数。但需要注意 __next__ 方法中对 self.data 的使用需要在前面进行正确的初始化。
创建了一个 IterableDataset 类的对象 loader ,其数据范围是从 1 到 5 。然后创建了一个 GeneratorDataset 对象 dataset ,将 loader 作为数据源,并指定了列名为 ["data"] 。最后通过一个 for 循环遍历 dataset 中的每个元素 d ,并将其打印出来。
代码如下:
loader = IterableDataset(1, 5)
dataset = GeneratorDataset(source=loader, column_names=["data"])
for d in dataset:
print(d)
运行结果:
[Tensor(shape=[], dtype=Int64, value= 1)]
[Tensor(shape=[], dtype=Int64, value= 2)]
[Tensor(shape=[], dtype=Int64, value= 3)]
[Tensor(shape=[], dtype=Int64, value= 4)]
生成器
定义了一个名为 my_generator 的生成器函数,它接受 start 和 end 两个参数,通过 for 循环使用 yield 关键字依次生成从 start 到 end - 1 的整数。由于生成器实例只能被迭代一次,所以使用 lambda 表达式来包装 my_generator 函数,以便能够生成多个实例。然后创建了一个 GeneratorDataset 对象 dataset ,将这个包装后的函数作为数据源,并指定列名为 ["data"] 。最后通过 for 循环遍历 dataset 中的每个元素 d ,并将其打印出来。
代码如下:
# Generator
def my_generator(start, end):
for i in range(start, end):
yield i
# since a generator instance can be only iterated once, we need to wrap it by lambda to generate multiple instances
dataset = GeneratorDataset(source=lambda: my_generator(3, 6), column_names=["data"])
for d in dataset:
print(d)
运行结果:
[Tensor(shape=[], dtype=Int64, value= 3)]
[Tensor(shape=[], dtype=Int64, value= 4)]
[Tensor(shape=[], dtype=Int64, value= 5)]
打印时间:
import time
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),'qianduanjidi')
运行截图: