Mosaic数据增强的实现
mosaic数据增强是一种在YOLOv4中首次引入的数据增强技术,它可以将4张训练图像以一定的比例合并成一张。这样可以让模型学习如何在比正常更小的尺度上识别物体,也可以在训练中显著减少对大批量大小的需求。
mosaic数据增强的优势主要有以下几点:
- 它可以丰富一张图像上的信息,让模型学习到更多的场景和目标。
- 它可以减少对大批量大小的依赖,因为一张图像上包含了四张图像的信息。
- 它可以提高模型对小目标的检测能力,因为将四张图像拼接成一张,相当于缩小了目标的尺寸。
- 它可以提高模型的泛化能力,因为它可以增加图像背景的复杂度,防止模型过拟合。
Mosaic的一种具体的实现方法如下:
- 从数据集中随机挑选四张图片。
- 对每张图片进行放大、缩小、平移等几何变换和平滑、模糊、对比度、亮度等像素变换。
- 随机从四张图片中各裁剪出一部分区域,进行拼接得到一张固定大小的图片如640x640。
- 对每张图片的GT框进行同样的几何变换,同时去除那些裁剪后小于某一阈值的标注框。
class MosicDataset(Dataset):
def __init__(self, size=(640, 640)):
super(MosicDataset, self).__init__()
self.src_data = VocDataset() # 一个DataSet类,每次返回一个图片,以及对应的标注框
self.dst_size = size
def __getitem__(self, idx):
scale_ratio = (0.6, 1.4)
src_img, src_boxes, _ = self.src_data[idx]
img_indexs = np.random.choice(np.arange(self.__len__()), size=3)
datas = [(src_img, src_boxes)]
# 随机取出三张图片加上固定的一张一共四张
for i in img_indexs:
img, boxes, _ = self.src_data[i]
datas.append((img, boxes))
random.shuffle(datas) # 打乱图片
h, w = self.dst_size
# 在640X640大小的背景上随机确定一点,过此点做垂直于四条边的线,将图片分为四部分
cy, cx = random.randint(h // 4, w * 3 // 4), random.randint(h // 4, w * 3 // 4)
cys = [cy, h - cy, 0] # 分别是第一部分的高度,第二部分的高度,最后一个为0,方便循环
cxs = [cx, w - cx, 0]
new_images = np.ones(shape=(h, w, 3), dtype=np.uint8) * 114
new_boxes = []
for i in range(2):
for j in range(2):
img, boxes = datas[i * 2 + j]
H, W, _ = img.shape
sr = np.random.uniform(scale_ratio[0], scale_ratio[1]) # 随机缩放图片
img = cv2.resize(img, (int(sr * W), int(sr * H)), interpolation=cv2.INTER_LINEAR)
H, W, _ = img.shape
# 随机在每张图片上进行裁剪
excursion_x, excursion_y = random.randint(0, max(H - cxs[i], 0)), random.randint(0, max(W - cys[j], 0))
# 将裁剪后的图片复制到画布上
new_images[cxs[i - 1]: cxs[i - 1] + min(cxs[i], H - excursion_x),
cys[j - 1]: cys[j - 1] + min(cys[j], W - excursion_y)] = img[
excursion_x: excursion_x + min(cxs[i],
H - excursion_x),
excursion_y: excursion_y + min(cys[j],
W - excursion_y)]
for box in boxes:
# 对标注框进行放缩
xmin, ymin, xmax, ymax = box[:4] * sr
# 确保标注框不会出界
xmin = np.clip(xmin - excursion_y, a_min=0, a_max=cys[j])
ymin = np.clip(ymin - excursion_x, a_min=0, a_max=cxs[i])
xmax = np.clip(xmax - excursion_y, a_min=0, a_max=cys[j])
ymax = np.clip(ymax - excursion_x, a_min=0, a_max=cxs[i])
# 排除裁剪后和裁剪前相比剩余部分较小的标注框:这里既可以用比例,也可以指定面积。
if ((ymax - ymin) * (xmax - xmin)) / ((box[3] - box[1]) * (box[2] - box[0]) * sr * sr) > 0.3:
# 将标注框还原到画布
new_boxes.append(
[xmin + cys[j - 1], ymin + cxs[i - 1], xmax + cys[j - 1], ymax + cxs[i - 1], box[-1]])
new_boxes = np.array(new_boxes, dtype=np.float32)
trans = transforms.Compose([transforms.ToTensor(),
transforms.ColorJitter(0.2, 0.2, 0.2),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
# new_images = trans(new_images)
# new_boxes = paddle.to_tensor(new_boxes, dtype=paddle.float32)
return new_images, new_boxes
def __len__(self):
return self.src_data.__len__()
诸事不顺,幸得二月初春,忽见嫩芽新发,才不致满面愁容。最后以白居易的一首诗结尾吧:
春风先发苑中梅,樱杏桃梨次第开。荠花榆荚深村里,亦道春风为我来。 — 唐代·白居易《春风》