这两天再做卷积神经网络的训练,数据集是CIFAR-10和CIFAR-100。虽然pytorch自带使用这两个数据集的类(datasets.CIFAR10()和datasets.CIFAR100()),使用的时候不用关心内部是如何对数据集进行处理的,但是心里还是想把这两个数据集可视化一下。顺便在这里做个笔记,为有心人提供参考,一起学习。
数据集简介:
CIFAR-10 与 CIFAR-100是计算机视觉中最基本的两个数据集,每个数据集都包含60k张图片,并且都是50k张训练,10k张测试。这两个数据集的压缩包解压后分别得到‘cifar-10-batches-py’和‘cifar-100-python’这两个文件夹,也就是datasets.CIFAR10()和datasets.CIFAR100()这两个类要用到的文件夹。
cifar-10-batches-py文件夹内容:
cifar-100-python文件夹内容:
下面我们主要对这两个文件夹进行操作,将里面的图片提取出来。
说到基本数据集当然还有MNIST,EMNIST等,但是这些太过简单,在学术论文中,基本被抛弃使用。甚至从近些年的趋势来看,CIFAR-10的使用频率也在下降,因为随着视觉领域的算法越发的SOTA,尤其是随着Transformer和MLP(这里的MLP不是几十年前的那种简单MLP,大家可以参考这篇文章,https://arxiv.org/pdf/2105.01601.pdf)的加入,这些简单的数据集已经支撑不起检验一个算法性能的重任。相反一些大的数据集使用的频率在增加,比如 ImageNet,ImageNet21k,JFT-300M等。
提取CIFAR-10:
因为CIFAR-10和CIFAR-100原始数据集都是序列化后的数据,因此在查看和提取过程需要用到pickle包,进行反序列化,可以形象地看成是解压。
CIFAR-10的训练集存储在‘data_batch_i’(i=1,2,3,4,5)这五个文件内,因为训练集包含50k的样本,因此每个文件包含10k个样本。我们可以看一下他们中都有些什么:
1)类型
import pickle
for i in range(5):
with open('.\cifar-10-batches-py\data_batch_' + str(i + 1), 'rb') as f:
file = pickle.load(f, encoding='bytes')
print(type(file))
结果:
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
可以看出它们都是字典。
2)字典里的内容
因为它们包含的内容格式都是一样的,所以这里只打印一个。
for i in range(5):
with open('.\cifar-10-batches-py\data_batch_' + str(i + 1), 'rb') as f:
file = pickle.load(f, encoding='bytes')#反序列化
for i in file:
print(i,type(file[i]))
break
结果:
b'batch_label' <class 'bytes'>
b'labels' <class 'list'>
b'data' <class 'numpy.ndarray'>
b'filenames' <class 'list'>
这里的‘b’表示的是bytes类型。可以看出这5个字典中每个字典都包含b’batch_label’,b’labels’ ,b’data’,b’filenames这4个键。
b’batch_label’:
b’batch_label’为 <class ‘bytes’>类型。5个文件每个文件的b’batch_label’如下:
b'training batch 1 of 5'
b'training batch 2 of 5'
b'training batch 3 of 5'
b'training batch 4 of 5'
b'training batch 5 of 5'
‘’‘其实就是每个文件的别名或标签。’‘’
b’labels’
b’labels’ 为<class ‘list’>类型。顾名思义,b’labels’就是每个文件中所有样本对应的标签。因为每个文件都包含10k个样本,所以b’labels’的长度自然为10k。这里只打印第一个文件的部分片段。
里面的每个标签都在区间[0,9]内。
[6, 9, 9, 4, 1, 1, 2, 7, 8, 3, 4, 7,... 5, 1, 2, 9, 2, 2, 1, 6, 3, 9, 1, 1, 5]
b’data’
b’data’为<class ‘numpy.ndarray’>类型。里面存储的就是样本(图片)的像素值了。二维数组,第一维长度是10k,第二维长度是3x32x32(样本通道x样本宽x样本高)。
[[ 59 43 50 ... 140 84 72] [154 126 105 ... 139 142 144] [255 253 253 ... 83 83 84] ... [ 71 60 74 ... 68 69 68] [250 254 211 ... 215 255 254] [ 62 61 60 ... 130 130 131]]
b’filenames’
b’filenames’ 也为<class ‘list’>类型,里面存放的是每个样本的名称(bytes类型),因此长度也为10k。这里就举第一个文件的部分片段。
[b'leptodactylus_pentadactylus_s_000004.png', b'camion_s_000148.png',..., b'truck_s_000036.png', b'car_s_002296.png', b'estate_car_s_001433.png', b'cur_s_000170.png']
很直接,就是每个图片的名称。
提取图片完整代码如下:
import numpy as np
import pickle
import os
from PIL import Image
if __name__ == '__main__':
channels = 3
img_width, img_height = 32, 32
ima_dir = r'***'
if not os.path.exists(ima_dir):
os.mkdir(ima_dir)
# os.makedirs()
data = []
label = []
data_name = []
for i in range(5):
with open('***\cifar-10-batches-py\data_batch_' + str(i + 1), 'rb') as f:
file = pickle.load(f, encoding='bytes')
data.extend(file[b'data'])
label.extend(file[b'labels'])
data_name.extend(file[b'filenames'])
with open(r'***\cifar-10-labels.txt', 'w') as f:
for i in label:
f.write(str(i) + '\n')
images = np.reshape(data, [-1, channels, img_width, img_height])
for ind in range(len(images)):
r = images[ind][0]
g = images[ind][1]
b = images[ind][2]
ir = Image.fromarray(r)
ig = Image.fromarray(g)
ib = Image.fromarray(b)
rgb = Image.merge('RGB', (ir, ig, ib))
img_path = os.path.join(ima_dir, data_name[ind].decode())
rgb.save(img_path, 'PNG')
提取结果
提取训练集类似。
提取CIFAR-100:
与CIFAR-10不同的是CIFAR-100的训练数据全部放在了文件夹train里面。
import pickle
with open(r'.\cifar-100-python\train', 'rb') as f:
file = pickle.load(f, encoding='bytes')#反序列化
for i in file:
print(i,type(file[i]))
结果:
b'filenames' <class 'list'>
b'batch_label' <class 'bytes'>
b'fine_labels' <class 'list'>
b'coarse_labels' <class 'list'>
b'data' <class 'numpy.ndarray'>
b’filenames’
这里的b’filenames’同CIFAR-10一样,只不过长度变为了50k。
b’batch_label’
b'training batch 1 of 1'
其实就是这个文件的一个别名或标签。
b’fine_labels’
精标签。CIFAR-100有两种标签,一类是粗标签,20个类,在此基础上又将每个样本细分类为了100个类,即精标签。
b’coarse_labels’
粗标签。
b’data’
同CIFAR-10一样,原始数据的像素。
提取图片完整代码如下:
import pickle
import numpy as np
import os
from PIL import Image
if __name__ == '__main__':
img_dir = r'***'
channels = 3
width = 32
height = 32
if not os.path.exists(os.path.join(img_dir, 'cifar100_real_images')):
os.mkdir(
os.path.join(img_dir, 'cifar100_real_images')
)
filenames = []
fine_labels = []
coarse_labels = []
data = []
with open(r'***\cifar-100-python\train', 'rb') as f:
file = pickle.load(f, encoding='bytes')
for i in file:
if i == b'filenames':
filenames = [name.decode() for name in file[i]]
if i == b'fine_labels':
fine_labels = file[i]
if i == b'coarse_labels':
coarse_labels = file[i]
if i == b'data':
data = file[i]
data = np.reshape(data, [-1, channels, width, height])
for ind in range(len(data)):
r = data[ind][0]
g = data[ind][1]
b = data[ind][2]
ir = Image.fromarray(r)
ig = Image.fromarray(g)
ib = Image.fromarray(b)
rgb = Image.merge('RGB', (ir, ig, ib))
rgb.save(os.path.join(img_dir, 'cifar100_real_images', str(ind)+'.png'),'PNG')
with open(r'***\cifar-100-labels.txt','w') as f:
for i,j in list(zip(fine_labels,coarse_labels)):
f.write(str(i)+' '*5+str(j)+'\n')
这里需要注意一下,因为在b’filenames’中有两个样本名称一样,这样的话要是根据这些名称生成样本,会被覆盖掉一个,结果是49999个样本。所以不能像CIFAR-10那样根据名称生成样本。
提取结果如下:
提取训练集类似。