什么是细粒度分类
细粒度分类是一种机器学习任务,旨在将输入的数据分成具有高度相似性的细粒度类别。细粒度分类通常是针对具有相似外观但具有微小差异的对象或图像进行分类。相比于传统的分类任务,细粒度分类需要更细致的特征提取和模型训练,因为要区分的类别之间的区别非常微小。
细粒度图像分类指的是对属于相同类别下的不同子类别的物体进行分类,常见应用场景:自动驾驶、生物保护、癌细胞检测等。
数据集简介
细粒度分类任务面临着一些问题:
- 数据集难以获得
- 特征提取难度大
- 类内变异大
- 样本不平衡
- 鲁棒性差
由于存在上述问题,对于开源的数据集:CUB_200_2011数据集可以给我们很好的利用起来,如下图所示为CUB_200_2011数据集的标注部分:
CUB_200_2011数据集的下载链接如文章开头所示。该数据集总共有200个类别,都是鸟的子类;其中训练集共计5994张图像,测试集共计5794张图像,类别标注和数据集划分详见README文件,部分样例如下:
在数据集文件夹中含有标注信息:每张图像提供了目标(鸟)所在的位置信息object annotation,以及各个局部部件的位置信息part annotation。标注信息的结果读取经过可视化后如下所示:
读取数据集
在上面我们介绍到了关于CUB_200_2011数据集的一些基本信息,因此我们在处理细粒度分类任务时不能盲目的使用【目录式】或【索引式】进行数据的读取,我们在读取的时候应当注意到标注信息。
定义读取CUB_200_2011数据集的Dataset
python
复制代码
import os import cv2 from torch.utils.data import Dataset class CUB(Dataset): def __init__(self, path, train=True, transform=None, target_transform=None): self.root = path self.is_train = train self.transform = transform self.target_transform = target_transform self.images_path = {} with open(os.path.join(self.root, 'images.txt')) as f: for line in f: image_id, path = line.split() self.images_path[image_id] = path self.class_ids = {} with open(os.path.join(self.root, 'image_class_labels.txt')) as f: for line in f: image_id, class_id = line.split() self.class_ids[image_id] = class_id self.data_id = [] if self.is_train: with open(os.path.join(self.root, 'train_test_split.txt')) as f: for line in f: image_id, is_train = line.split() if int(is_train): self.data_id.append(image_id) if not self.is_train: with open(os.path.join(self.root, 'train_test_split.txt')) as f: for line in f: image_id, is_train = line.split() if not int(is_train): self.data_id.append(image_id) def __len__(self): return len(self.data_id) def __getitem__(self, index): """ Args: index: index of training dataset Returns: image and its corresponding label """ image_id = self.data_id[index] class_id = int(self._get_class_by_id(image_id)) - 1 path = self._get_path_by_id(image_id) image = cv2.imread(os.path.join(self.root, 'images', path)) if self.transform: image = self.transform(image) if self.target_transform: class_id = self.target_transform(class_id) return image, class_id def _get_path_by_id(self, image_id): return self.images_path[image_id] def _get_class_by_id(self, image_id): return self.class_ids[image_id]
利用Dataset构建自己的DataLoader
ini
复制代码
data_path = 'data/CUB_200_2011' # 设置数据路径 train_transforms = transforms.Compose([ transforms.ToPILImage(), transforms.Resize((RE_SIZE, RE_SIZE)), transforms.RandomCrop(IMAGE_SIZE, padding=8), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(MEAN, STD) ]) test_transforms = transforms.Compose([ transforms.ToPILImage(), transforms.Resize((RE_SIZE, RE_SIZE)), transforms.CenterCrop(IMAGE_SIZE), transforms.ToTensor(), transforms.Normalize(MEAN, STD) ]) train_dataset = CUB(data_path, train=True, transform=train_transforms, target_transform=None) train_dataloader = DataLoader(train_dataset, batch_size=batch_size, num_workers=0, shuffle=True) test_dataset = CUB(data_path, train=False, transform=test_transforms, target_transform=None) test_dataloader = DataLoader(test_dataset, batch_size=batch_size, num_workers=0, shuffle=True)
截止到这里我们对CUB_200_2011数据集已经完成了读取,在后面的任务就是分类了,对于分类任务可以参考torch中的经典卷积神经网络进行魔改完成自己的任务了,在我们的数据载入后是可以兼容符合粗粒度的分类任务的步骤的。
结尾
在本篇博客中,我们介绍了如何对CUB_200_2011数据集进行细粒度分类任务。CUB_200_2011数据集是一个非常有挑战性的细粒度分类数据集,其中包含了200个鸟类别,每个类别有多张高分辨率的图像。我们介绍了如何使用卷积神经网络(CNN)来对该数据集进行分类。
尽管细粒度分类任务非常具有挑战性,但它在实际应用中具有广泛的应用价值。例如,在生物学领域,细粒度分类可以用来识别不同的细胞类型或病理学图像中的不同病变类型。在计算机视觉领域,细粒度分类可以用来识别不同的物体子类,例如花朵的不同品种或飞机的不同型号。
虽然本文只是简单地介绍了细粒度分类任务和CUB_200_2011数据集,但这些知识可以为读者提供一个很好的起点,进一步深入研究和应用细粒度分类。