Transforms v2: 端到端目标检测/分割示例¶
目标检测和分割任务原生支持:
torchvision.transforms.v2 允许联合转换图像、视频、边界框和掩码。
这个例子展示了一个使用Torchvision工具进行端到端实例分割训练的案例,使用了torchvision.datasets、torchvision.models和torchvision.transforms.v2。这里涵盖的所有内容同样适用于目标检测或语义分割任务。
import pathlib
import torch
import torch.utils.data
from torchvision import models, datasets, tv_tensors
from torchvision.transforms import v2
torch.manual_seed(0)
# This loads fake data for illustration purposes of this example. In practice, you'll have
# to replace this with the proper data.
# If you're trying to run that on Colab, you can download the assets and the
# helpers from https://github.com/pytorch/vision/tree/main/gallery/
ROOT = pathlib.Path("../assets") / "coco"
IMAGES_PATH = str(ROOT / "images")
ANNOTATIONS_PATH = str(ROOT / "instances.json")
from helpers import plot
数据集准备¶
我们首先加载CocoDetection数据集,看看它目前返回的内容。
dataset = datasets.CocoDetection(IMAGES_PATH, ANNOTATIONS_PATH)
sample = dataset[0]
img, target = sample
print(f"{type(img) = }\n{type(target) = }\n{type(target[0]) = }\n{target[0].keys() = }")
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
type(img) = <class 'PIL.Image.Image'>
type(target) = <class 'list'>
type(target[0]) = <class 'dict'>
target[0].keys() = dict_keys(['segmentation', 'iscrowd', 'image_id', 'bbox', 'category_id', 'id'])
Torchvision 数据集保留了数据集作者所设计的数据结构和类型。因此,默认情况下,输出结构可能并不总是与模型或转换兼容。
为了克服这个问题,我们可以使用
wrap_dataset_for_transforms_v2() 函数。对于
CocoDetection,这将目标
结构更改为一个列表的单一字典:
type(img) = <class 'PIL.Image.Image'>
type(target) = <class 'dict'>
target.keys() = dict_keys(['boxes', 'masks', 'labels'])
type(target['boxes']) = <class 'torchvision.tv_tensors._bounding_boxes.BoundingBoxes'>
type(target['labels']) = <class 'torch.Tensor'>
type(target['masks']) = <class 'torchvision.tv_tensors._mask.Mask'>
我们使用了target_keys参数来指定我们感兴趣的输出类型。我们的数据集现在返回一个目标,它是一个字典,其中的值是TVTensors(都是torch.Tensor的子类)。我们已经从之前的输出中删除了所有不必要的键,但如果你需要任何原始键,例如“image_id”,你仍然可以请求它。
注意
如果你只想进行检测,你不需要也不应该在target_keys中传递“masks”:如果样本中存在masks,它们将被转换,不必要地减慢你的转换速度。
作为基线,让我们看一下没有转换的示例:
plot([dataset[0], dataset[1]])

转换¶
现在让我们定义我们的预处理转换。所有转换都知道如何处理图像、边界框和相关的掩码。
转换通常作为数据集的transforms参数传递,以便它们可以利用来自torch.utils.data.DataLoader的多进程处理。
transforms = v2.Compose(
[
v2.ToImage(),
v2.RandomPhotometricDistort(p=1),
v2.RandomZoomOut(fill={tv_tensors.Image: (123, 117, 104), "others": 0}),
v2.RandomIoUCrop(),
v2.RandomHorizontalFlip(p=1),
v2.SanitizeBoundingBoxes(),
v2.ToDtype(torch.float32, scale=True),
]
)
dataset = datasets.CocoDetection(IMAGES_PATH, ANNOTATIONS_PATH, transforms=transforms)
dataset = datasets.wrap_dataset_for_transforms_v2(dataset, target_keys=["boxes", "labels", "masks"])
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
这里有几件事值得注意:
我们正在将PIL图像转换为
Image对象。这并不是严格必要的,但依赖张量(这里:一个张量子类)通常 会更快。我们正在调用
SanitizeBoundingBoxes来确保我们移除退化的边界框,以及它们对应的标签和掩码。SanitizeBoundingBoxes应该至少放置在检测管道的末端一次;如果使用了RandomIoUCrop,这一点尤其关键。
让我们看看样本在使用我们的增强管道后的样子:
plot([dataset[0], dataset[1]])

我们可以看到图像的颜色被扭曲、放大或缩小,并且被翻转。 边界框和遮罩也相应地进行了变换。无需多言,我们可以开始训练了。
数据加载和训练循环¶
下面我们使用的是Mask-RCNN,这是一个实例分割模型,但本教程中涵盖的所有内容也适用于目标检测和语义分割任务。
data_loader = torch.utils.data.DataLoader(
dataset,
batch_size=2,
# We need a custom collation function here, since the object detection
# models expect a sequence of images and target dictionaries. The default
# collation function tries to torch.stack() the individual elements,
# which fails in general for object detection, because the number of bounding
# boxes varies between the images of the same batch.
collate_fn=lambda batch: tuple(zip(*batch)),
)
model = models.get_model("maskrcnn_resnet50_fpn_v2", weights=None, weights_backbone=None).train()
for imgs, targets in data_loader:
loss_dict = model(imgs, targets)
# Put your training logic here
print(f"{[img.shape for img in imgs] = }")
print(f"{[type(target) for target in targets] = }")
for name, loss_val in loss_dict.items():
print(f"{name:<20}{loss_val:.3f}")
[img.shape for img in imgs] = [torch.Size([3, 512, 512]), torch.Size([3, 409, 493])]
[type(target) for target in targets] = [<class 'dict'>, <class 'dict'>]
loss_classifier 4.722
loss_box_reg 0.006
loss_mask 0.734
loss_objectness 0.691
loss_rpn_box_reg 0.036
培训参考资料¶
从这里,你可以查看torchvision 参考,在那里你会找到我们用来训练模型的实际训练脚本。
免责声明 我们参考中的代码比您自己使用场景所需的要复杂:这是因为我们支持不同的后端(PIL、张量、TVTensors)和不同的转换命名空间(v1和v2)。所以不要害怕简化,只保留您需要的部分。
脚本总运行时间: (0 分钟 5.188 秒)