Деформация Faster R-CNN

компьютерное зрение
Деформация Faster R-CNN

Цель этой статьи — проиллюстрировать различные изменения, которые Xiao M претерпел на уровне Transform.

Подробный код см.:pytorch-tutorial/transform.py

Сяо М подошел к двери второго уровня, а на двери лежала книга.RCNNImageTransformНесколько крупных персонажей, а его высота и ширина были специально собраны между дверями. Маленький М подумал про себя, я просто боюсь, что это послеTransformПотом, боюсь, изменится.

        raw_image_shape: List[Tuple[int, int]] = []
        for image in images:
            raw_image_shape.append((image.shape[1], image.shape[2])) # 记录原始宽高

        images, targets = self.transform(images, targets)  # 进入 RCNNImageTransform

Если смотреть дальше вправо, на ней нарисован дизайн всего лабиринта.

image.png

Поэтому нам нужно пройти всего три шага в текущем лабиринте: Нормализация\rightarrow Resize \rightarrow Merge into a Batch

    def forward(self,
        images,         # type: List[Tensor]
        targets=None    # type: Optional[List[Dict[str, Tensor]]]
    ):
        for idx in range(len(images)):
            image = images[idx]
            target =  targets[idx] if targets is not None else None
            '''1. Normalize'''
            image = self.normalize(image)
            '''2. Resize'''
            image, target = self.resize(image, target)

            images[idx] = image
            if targets is not None:
                targets[idx] = target
        # 记录调整后的图片大小
        image_sizes = [img.shape[-2:] for img in images]

        '''3. Merge into a Batch'''
        images = self.batch_images(images)
        image_size_list: List[Tuple[int, int]] = []

        for img_size in image_sizes:
            image_size_list.append((img_size[0], img_size[1]))

        image_list = ImageList(images, image_size_list)

        return image_list, targets

Normalize

    '''对图片做标准化处理'''
    def normalize(self, image: Tensor):
        dtype, device = image.dtype, image.device
        mean = torch.as_tensor(self.image_mean, dtype=dtype, device=device)
        std = torch.as_tensor(self.image_std, dtype=dtype, device=device)

        return (image - mean[:, None, None]) / std[:, None, None]

Разработчики текущего лабиринта установили значения по умолчанию для среднего значения и дисперсии следующим образом.

        if image_mean is None:
            image_mean = [0.485, 0.456, 0.406] # R G B 三层的均值
        if image_std is None:
            image_std = [0.229, 0.224, 0.225] # R G B 三层的方差

После того, как маленький M подвергся нормализации, значение каждого пикселя вычитается из среднего и делится на дисперсию.

Resize

    '''将图片大小调整到指定的范围'''
    def resize(self, image, target):
        height, weight = image.shape[-2:]
        max_size = max([height, weight])
        min_size = min([height, weight])

        scale_factor = self.min_size / min_size

        if max_size * scale_factor > self.max_size:
            scale_factor = self.max_size / max_size
        
        # interpolate 使用插值的方法来缩放图片
        image = F.interpolate(
            input=image[None], 
            scale_factor=scale_factor,
            mode='bilinear',
            align_corners=False
        )[0]

        if target is None:
            return image, target
        
        bbox = target['boxes']
        bbox = resize_boxes(bbox, [height, weight], image.shape[-2:])

        target['boxes'] = bbox

        return image, target

resize_boxes()См. код:pytorch-tutorial/utils.py

После изменения размера маленькой буквы M ее ширина и высота ограничиваются значениями min_size ~ max_size.

Merge into a Batch

   
    '''将一批图片打包成一个batch'''
    def batch_images(self, 
        images,             # 输入的一批图片
        size_divisible=32   # 将图片的宽高调整到 size_divisible 的整数倍
    ):
        # type: (List[Tensor], int) -> Tensor
        # 获取一个batch的所有图片中最大的 channel、height、width
        max_shape = get_max_shape([list(img.shape) for img in images])
        stride = float(size_divisible)

        # 宽高向上调整到 stride 的整数倍
        max_shape[1] = int(math.ceil(max_shape[1] / stride) * stride)
        max_shape[2] = int(math.ceil(max_shape[2] / stride) * stride)

        batch_size = [len(images)] + max_shape

        # 创建shape为batch,且全0的tensor, 与 image[0] 设备、类型相同
        batch_image = images[0].new_full(batch_size, 0)

        for img, pad_img in zip(images, batch_image):
            pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img)

        return batch_image

Учитывая, что может быть несколько изображений, чтобы пройти лабиринт вместе, на этом шаге все изображения будут упакованы в пакет.

Сначала получить максимальный канал MAX_C, максимальную высоту и ширину MAX_H, MAX_W всех картинок, а затем преобразовать их вsize_divisibleКратно , что удобно для аппаратно-ускоренной обработки.

Наконец, все изображения расширены до канала MAX_C, изображения высокого размера MAX_H, MAX_W большого размера, конкретные шаги: изображение верхнего левого угла в качестве контрольной точки, после расширения, отсутствие локального дополнения0.

Как показано на рисунке ниже, лишняя часть — это белая область.Когда маленькое M расширяется до максимальной ширины и высоты, белая область устанавливается на 0.

На данный момент Сяо М завершил второй уровень.Transform

После выхода с таможни все тело Сяо М. изменилось. Увидев себя в зеркале, он выглядел красивым и красивым, как на красивой картинке, и его настроение также улучшилось.BackboneПо дороге он также напевал песенку.

        # Standardize
        images, targets = self.transform(images, targets)  # 对图像进行预处理 ImageList

        # 将图像输入到 backbone 得到特征图 并存放在 有序字典中
        feature_maps = self.backbone(images.image_list)

Как видно из приведенного выше кода, Xiao M испыталBackboneПосле этого сталоFeature Map, то онBackboneЧто в нем произошло? И послушайте следующее разложение...