百度网盘下载:
链接: https://pan.baidu.com/s/1Uro6RuEbRGGCQ8iXvF2SAQ 密码: hl31
提到Imagenet大家都知道,是一个非常大型、有名的开源数据集。一般设计一个新的分类网络就会在Imagenet 1000类的数据上进行训练以及验证。包括常见的目标检测网络等,所使用的backbone一般都会先基于Imagenet进行预训练。但对于普通研究员或者开发者而言,这个数据集太大了(全部下载大概有100GB左右),而且训练对硬件要求也非常高,通常都是很多块高端显卡并行训练,即使是这样的配置通常还要训练好几天的时间。所以让很多人望而却步(我就是其中之一,关键太大,而且国内下载很慢)。
2016年google DeepMind团队从Imagnet数据集中抽取的一小部分(大小约3GB)制作了Mini-Imagenet数据集,共有100个类别,每个类别都有600张图片,共60000张(都是.jpg
结尾的文件),而且图像的大小并不是固定的。
![]() |
![]() |
![]() |
![]() |
数据集的结构为:
├── mini-imagenet: 数据集根目录
├── images: 所有的图片都存在这个文件夹中
├── train.csv: 对应训练集的标签文件
├── val.csv: 对应验证集的标签文件
└── test.csv: 对应测试集的标签文件
Mini-Imagenet数据集中还包含了train.csv
、val.csv
以及test.csv
三个文件。需要注意的是,当时作者制作这个数据集时主要是针对小样本学习领域的,而且提供的标签文件并不是从每个类别中进行采样的。我自己用pandas
包分析了下每个标签文件。
train.csv
包含38400张图片,共64个类别。val.csv
包含9600张图片,共16个类别。test.csv
包含12000张图片,共20个类别。每个csv
文件之间的图像以及类别都是相互独立的,即共60000张图片,100个类。
用pandas
读取的csv
文件数据格式如下,每一行对应一张图片的名称和所属类别:
filename label
0 n0153282900000005.jpg n01532829
1 n0153282900000006.jpg n01532829
2 n0153282900000007.jpg n01532829
3 n0153282900000010.jpg n01532829
4 n0153282900000014.jpg n01532829
至于每个类别对应的实际物体名称,可查看这个json文件,这个文件是Imagenet1000类数据中对应的标签文件。
{"0": ["n01440764", "tench"],
"1": ["n01443537", "goldfish"],
"2": ["n01484850", "great_white_shark"],
...
}
根据上面分析的,如果想用Mini-Imgenet数据集直接去训练自己的分类网络是不可行的,因为train.csv
和val.csv
并不是从每个类别中进行采样的,所以我们需要自己去构建一个新的train.csv
和val.csv
文件。下面是我自己写的一个构建train.csv
和val.csv
标签文件的脚本,该脚本会从这100个类别中按给定的比例去划分训练集和验证集。
import os
import json
import pandas as pd
from PIL import Image
import matplotlib.pyplot as plt
def read_csv_classes(csv_dir: str, csv_name: str):
data = pd.read_csv(os.path.join(csv_dir, csv_name))
# print(data.head(1)) # filename, label
label_set = set(data["label"].drop_duplicates().values)
print("{} have {} images and {} classes.".format(csv_name,
data.shape[0],
len(label_set)))
return data, label_set
def calculate_split_info(path: str, label_dict: dict, rate: float = 0.2):
# read all images
image_dir = os.path.join(path, "images")
images_list = [i for i in os.listdir(image_dir) if i.endswith(".jpg")]
print("find {} images in dataset.".format(len(images_list)))
train_data, train_label = read_csv_classes(path, "train.csv")
val_data, val_label = read_csv_classes(path, "val.csv")
test_data, test_label = read_csv_classes(path, "test.csv")
# Union operation
labels = (train_label | val_label | test_label)
labels = list(labels)
labels.sort()
print("all classes: {}".format(len(labels)))
# create classes_name.json
classes_label = dict([(label, [index, label_dict[label]]) for index, label in enumerate(labels)])
json_str = json.dumps(classes_label, indent=4)
with open('classes_name.json', 'w') as json_file:
json_file.write(json_str)
# concat csv data
data = pd.concat([train_data, val_data, test_data], axis=0)
print("total data shape: {}".format(data.shape))
# split data on every classes
num_every_classes = []
split_train_data = []
split_val_data = []
for label in labels:
class_data = data[data["label"] == label]
num_every_classes.append(class_data.shape[0])
# shuffle
shuffle_data = class_data.sample(frac=1, random_state=1)
num_train_sample = int(class_data.shape[0] * (1 - rate))
split_train_data.append(shuffle_data[:num_train_sample])
split_val_data.append(shuffle_data[num_train_sample:])
# imshow
imshow_flag = False
if imshow_flag:
img_name, img_label = shuffle_data.iloc[0].values
img = Image.open(os.path.join(image_dir, img_name))
plt.imshow(img)
plt.title("class: " + classes_label[img_label][1])
plt.show()
# plot classes distribution
plot_flag = False
if plot_flag:
plt.bar(range(1, 101), num_every_classes, align='center')
plt.show()
# concatenate data
new_train_data = pd.concat(split_train_data, axis=0)
new_val_data = pd.concat(split_val_data, axis=0)
# save new csv data
new_train_data.to_csv(os.path.join(path, "new_train.csv"))
new_val_data.to_csv(os.path.join(path, "new_val.csv"))
def main():
data_dir = "/home/wz/mini-imagenet/" # 指向数据集的根目录
json_path = "./imagenet_class_index.json" # 指向imagenet的索引标签文件
# load imagenet labels
label_dict = json.load(open(json_path, "r"))
label_dict = dict([(v[0], v[1]) for k, v in label_dict.items()])
calculate_split_info(data_dir, label_dict)
if __name__ == '__main__':
main()
项目地址:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing
在pytorch_classification
->mini-imagenet
文件夹中,里面提供了两个训练脚本,一个是针对单GPU的,一个是针对多GPU的。在这个项目中是以训练ShuffleNetv2为例进行讲解的。训练了100个epoch,达到了78%的准确率。
接着,我拿这个预训练权重去做迁移学习,训练其他的小数据集,确实也有一定帮助。在我测试过程中,如果不使用预训练权重,训练自己的数据集能达到80%的准确率,如果使用预训练权重能达到90%的准确率。当然基于Mini-Imagenet的预训练权重和基于Imagenet的预训练权重还有一些差距,毕竟数据量摆在这。之前使用基于Imagenet的预训练权重准确率可以达到94%。
当然,对于自己新搭的网络,如果想快速验证一下,Mini-Imagenet也是一个不错的选择。