【项目003】数据准备(Data Preparation) 学生版 | 教学版 | 发布版 | 返回首页

作者:欧新宇(Xinyu OU)
当前版本:Release v1.0
开发平台:Paddle 2.3.2
运行环境:Intel Core i7-7700K CPU 4.2GHz, nVidia GeForce GTX 1080 Ti
本教案所涉及的数据集仅用于教学和交流使用,请勿用作商用。

最后更新:2022年12月31日


【实验目的】

  1. 学会对下载的数据集进行基本的分析和了解
  2. 能够按照规范的结构对自建数据集进行整理和规范
  3. 能够使用Python编写代码,实现对规范结构数据集进行列表生成,并按照训练集、验证集、训练验证集和测试集进行划分
  4. 对非规范数据能够进行规范化处理, 或按照规范标准对数据集进行划分
  5. 对不干净的数据,能够编写Python代码进行数据清洗

【实验内容】

垃圾分类数据集Garbage 是一个包含有40个类别,14802张图像的数据集。该数据集已经事先实现了训练(train)测试(test)的分割,其中测试集没有类别标签。数据集没有给出验证集的划分建议,因此在进行数据列表生成的时候,可以自行按照一定的比列来将官方提供的训练集看作是trainval进行二次划分,即将原来的 train 文件夹划分为训练集train和验证集val。使用train和val完成训练之后,再按照训练获得超参数,对整个训练验证集trainval进行训练,完成后直接输出 测试集结果 到平台进行评估。注意,本数据集给出了类别的标签字典,因此在生成和划分数据子集的时候,建议考虑基于该类别标签字典而非遍历文件夹的方式来完成。

垃圾分类数据集Garbage

【实验一】参数初始化(20分)

# pcodes00301_data_preparation
##################################################################################
# 数据集预处理
# 作者: Xinyu Ou (http://ouxinyu.cn)
# 数据集名称:垃圾分类数据集Garbage
# 数据集简介: 数据集包含40个类别,其中训练样本14402张,测试样本400张。
# 本程序功能:
# 1. 在训练集中抽取10%的样本作为验证数据集
# 2. 代码将生成4个带标注的列表文件:train, val, trainval, test
# 3. 数据集基本信息:数据集的基本信息使用json格式进行输出,包括数据库名称、数据样本的数量、类别数以及类别标签
###################################################################################

import os
import json
import codecs

#########################################################
# 1. 超参数的初始化 [Q1-1]
# [Your codes 1] 
num_train = 0
num_val = 0
num_trainval = 0
num_test = 0
class_dim = 0
dataset_info = {
    'dataset_name': '',
    'num_trainval': -1,
    'num_train': -1,
    'num_val': -1,
    'num_test': -1,
    'class_dim': -1,
    'label_dict': {}
}

# 设置图片的前缀,即图像根目录下的子目录路径
train_prefix = 'train'  # train_prefix = val_prefix = trainval_prefix  
test_prefix = 'test'

#########################################################
# 2. 数据集相关路径定义。本地运行时,需要修改数据集的名称和绝对路径,注意和文件夹名称一致。
# 2.1 数据集源路径定义
dataset_name = 'Garbage'
dataset_path = 'D:\\Workspace\\ExpDatasets\\'
dataset_root_path = os.path.join(dataset_path, dataset_name)
exclusion = ['.DS_Store', '.ipynb_checkpoints']    # 被排除的文件夹

# 2.2 数据集输出路径定义 [Q2-1]
# [Your codes 2]
trainval_list = os.path.join(dataset_root_path, 'trainval.txt')
train_list = os.path.join(dataset_root_path, 'train.txt')
val_list = os.path.join(dataset_root_path, 'val.txt')
test_list = os.path.join(dataset_root_path, 'test.txt')
dataset_info_list = os.path.join(dataset_root_path, 'dataset_info.json')
garbage_dict_path = os.path.join(dataset_root_path, 'garbage_dict.json')

# 2.3 检测数据集列表是否已经存在,如果存在则先删除。
# 在Garbage数据集中,测试集只需要一次性写入,可以通过'w'参数进行覆盖写入,而不用进行手动删除。
if os.path.exists(train_list):
    os.remove(train_list)
if os.path.exists(val_list):
    os.remove(val_list)
if os.path.exists(trainval_list):
    os.remove(trainval_list)
if os.path.exists(dataset_info_list):
    os.remove(dataset_info_list)

# 2.4 从官方文件garbage_dict.json获取类别标签
with open(garbage_dict_path, 'r', encoding='utf-8') as f_dict:
    garbage_dict = json.load(f_dict)

# 2.5 读取数据清洗获得的坏样本列表,并将坏文件写入列表以备后续排除(本例可忽略)

【实验二】数据集划分(60分)

# 3. 生成四个不同的数据子集列表
# 3.1 生成测试集列表 [Q3-1]
# 特别注意,因测试集的输出结果需要使用专门的系统进行评估(AIStudio),因此测试集样本列表需要对文件严格按照数字从小到大进行排序
# [Your codes 3]
testImg_list = os.listdir(os.path.join(dataset_root_path, test_prefix))
test_numbers = []
for testImg in testImg_list:
    if testImg not in exclusion:
        test_name = testImg.split('.')              # 拆分文件名和扩展名
        test_numbers.append(int(test_name[0][4:]))  # 获取文件名中的数字部分
test_numbers.sort()                                 # 对测试文件,按照数字序号进行排序
num_test = len(test_numbers)

with codecs.open(test_list, 'w', 'utf-8') as f_test:
    for i in test_numbers:                          # 按照序号列表遍历测试数据,并生成测试文件列表
        image_path = os.path.join(dataset_root_path, test_prefix, 'test' + str(i) + '.jpg')
        f_test.write('{}\n'.format(image_path))
        
# 3.2 生成训练集、验证集和训练验证集列表 [Q3-2]
# [Your codes 4]
labelID_list = list(garbage_dict.keys())
with codecs.open(train_list, 'a', 'utf-8') as f_train, codecs.open(val_list, 'a', 'utf-8') as f_val, codecs.open(trainval_list, 'a', 'utf-8') as f_trainval:
    for label_id in labelID_list:
        trainImgs = os.listdir(os.path.join(dataset_root_path, train_prefix, label_id))
        count = 0
        for trainImg in trainImgs:
            if trainImg not in exclusion:
                image_path = os.path.join(dataset_root_path, train_prefix, label_id, trainImg)
                if count % 10 == 0:  # 抽取大约10%的样本作为验证数据
                    f_val.write("{}\t{}\n".format(image_path, label_id))
                    f_trainval.write("{}\t{}\n".format(image_path, label_id))
                    num_val += 1
                    num_trainval += 1
                else:
                    f_train.write("{}\t{}\n".format(image_path, label_id))
                    f_trainval.write("{}\t{}\n".format(image_path, label_id))
                    num_train += 1
                    num_trainval += 1
            count += 1

【实验三】结果输出(20分)

# 4. 输出统计结果
# 4.1 将数据集信息保存到json文件中供训练和部署使用 [Q4-1]
# 数据集信息包括:数据集名称,训练、验证、测试及训练验证集的样本数量、类别的数量和类别字典
# [Your codes 5] 
dataset_info['dataset_name'] = dataset_name
dataset_info['num_trainval'] = num_trainval
dataset_info['num_train'] = num_train
dataset_info['num_val'] = num_val
dataset_info['num_test'] = num_test
dataset_info['class_dim'] = len(garbage_dict)
dataset_info['label_dict'] = garbage_dict

# 4.2.输出数据集信息到json文件
with codecs.open(dataset_info_list, 'w', encoding='utf-8') as f_dataset_info:
    json.dump(dataset_info, f_dataset_info, ensure_ascii=False, indent=4, separators=(',', ':')) # 格式化字典格式的参数列表

# 4.3 在控制台中打印数据集基本统计信息 [Q4-2]
# 注意为方便可视化,考虑使用display()替代print()对字典进行输出,但display()只支持notebook接口。
# [Your codes 6] 
print("图像列表已生成, 其中训练验证集样本{},训练集样本{}个, 验证集样本{}个, 测试集样本{}个, 共计{}个。".format(num_trainval, num_train, num_val, num_test, num_train+num_val+num_test))
display(dataset_info)
图像列表已生成, 其中训练验证集样本14402,训练集样本12944, 验证集样本1458, 测试集样本400, 共计14802个。

{'dataset_name': 'Garbage',
    'num_trainval': 14402,
    'num_train': 12944,
    'num_val': 1458,
    'num_test': 400,
    'class_dim': 40,
    'label_dict': {'0': '其他垃圾/一次性快餐盒',
    '1': '其他垃圾/污损塑料',
    '2': '其他垃圾/烟蒂',
    '3': '其他垃圾/牙签',
    '4': '其他垃圾/破碎花盆及碟碗',
    '5': '其他垃圾/竹筷',
    '6': '厨余垃圾/剩饭剩菜',
    '7': '厨余垃圾/大骨头',
    '8': '厨余垃圾/水果果皮',
    '9': '厨余垃圾/水果果肉',
    '10': '厨余垃圾/茶叶渣',
    '11': '厨余垃圾/菜叶菜根',
    '12': '厨余垃圾/蛋壳',
    '13': '厨余垃圾/鱼骨',
    '14': '可回收物/充电宝',
    '15': '可回收物/包',
    '16': '可回收物/化妆品瓶',
    '17': '可回收物/塑料玩具',
    '18': '可回收物/塑料碗盆',
    '19': '可回收物/塑料衣架',
    '20': '可回收物/快递纸袋',
    '21': '可回收物/插头电线',
    '22': '可回收物/旧衣服',
    '23': '可回收物/易拉罐',
    '24': '可回收物/枕头',
    '25': '可回收物/毛绒玩具',
    '26': '可回收物/洗发水瓶',
    '27': '可回收物/玻璃杯',
    '28': '可回收物/皮鞋',
    '29': '可回收物/砧板',
    '30': '可回收物/纸板箱',
    '31': '可回收物/调料瓶',
    '32': '可回收物/酒瓶',
    '33': '可回收物/金属食品罐',
    '34': '可回收物/锅',
    '35': '可回收物/食用油桶',
    '36': '可回收物/饮料瓶',
    '37': '有害垃圾/干电池',
    '38': '有害垃圾/软膏',
    '39': '有害垃圾/过期药物'}}