使用模型¶
从 Yacs 配置构建模型¶
从 yacs 配置对象,可以使用诸如 build_model
、build_backbone
、build_roi_heads
等函数构建模型(及其子模型)。
from detectron2.modeling import build_model
model = build_model(cfg) # returns a torch.nn.Module
build_model
仅构建模型结构并使用随机参数填充它。请参阅以下内容,了解如何将现有检查点加载到模型中以及如何使用 model
对象。
加载/保存检查点¶
from detectron2.checkpoint import DetectionCheckpointer
DetectionCheckpointer(model).load(file_path_or_url) # load a file, usually from cfg.MODEL.WEIGHTS
checkpointer = DetectionCheckpointer(model, save_dir="output")
checkpointer.save("model_999") # save to output/model_999.pth
Detectron2 的检查点识别 pytorch 的 .pth
格式中的模型,以及我们模型库中的 .pkl
文件。有关其使用方式的更多详细信息,请参阅 API 文档。
可以使用 torch.{load,save}
(针对 .pth
文件)或 pickle.{dump,load}
(针对 .pkl
文件)任意操作模型文件。
使用模型¶
可以使用 outputs = model(inputs)
调用模型,其中 inputs
是一个 list[dict]
。每个字典对应于一幅图像,所需键取决于模型类型以及模型是处于训练模式还是评估模式。例如,为了进行推理,所有现有模型都期望“image”键,以及可选的“height”和“width”。下面将解释现有模型的输入和输出的详细格式。
训练:在训练模式下,所有模型都必须在 EventStorage
下使用。训练统计信息将被放入存储中
from detectron2.utils.events import EventStorage
with EventStorage() as storage:
losses = model(inputs)
推理:如果你只想使用现有模型进行简单的推理,DefaultPredictor 是模型周围的包装器,它提供这种基本功能。它包含默认行为,包括模型加载、预处理,并对单个图像而不是批处理进行操作。有关使用方式,请参阅其文档。
你也可以像这样直接运行推理
model.eval()
with torch.no_grad():
outputs = model(inputs)
模型输入格式¶
用户可以实现支持任何任意输入格式的自定义模型。这里我们将介绍 detectron2 中所有内置模型支持的标准输入格式。它们都将 list[dict]
作为输入。每个字典对应于一幅图像的信息。
该字典可能包含以下键
“image”:
Tensor
,采用 (C, H, W) 格式。通道的含义由cfg.INPUT.FORMAT
定义。图像归一化(如果有)将在模型内部使用cfg.MODEL.PIXEL_{MEAN,STD}
执行。“height”, “width”: 推理中所需的输出高度和宽度,它不一定是
image
字段的高度或宽度的相同值。例如,image
字段包含调整大小的图像(如果调整大小用作预处理步骤)。但你可能希望输出以原始分辨率呈现。如果提供,模型将以该分辨率生成输出,而不是以image
作为模型输入时的分辨率。这样效率更高,也更准确。“instances”: 用于训练的 Instances 对象,具有以下字段
“gt_boxes”: 一个 Boxes 对象,存储 N 个框,每个实例一个。
“gt_classes”:
Tensor
,类型为 long,N 个标签的向量,范围为 [0, num_categories)。“gt_masks”: 一个 PolygonMasks 或 BitMasks 对象,存储 N 个掩码,每个实例一个。
“gt_keypoints”: 一个 Keypoints 对象,存储 N 个关键点集,每个实例一个。
“sem_seg”:
Tensor[int]
,采用 (H, W) 格式。用于训练的语义分割真值。值表示从 0 开始的类别标签。“proposals”: 一个 Instances 对象,仅用于 Fast R-CNN 风格的模型,具有以下字段
“proposal_boxes”: 一个 Boxes 对象,存储 P 个提议框。
“objectness_logits”:
Tensor
,P 个分数的向量,每个提议一个。
对于内置模型的推理,仅需要“image”键,而“width/height”是可选的。
我们目前没有为全景分割训练定义标准输入格式,因为模型现在使用自定义数据加载器生成的自定义格式。
如何与数据加载器连接:¶
默认 DatasetMapper 的输出是一个字典,它遵循上述格式。在数据加载器执行批处理后,它将变为 list[dict]
,内置模型支持该格式。
模型输出格式¶
在训练模式下,内置模型输出一个 dict[str->ScalarTensor]
,其中包含所有损失。
在推理模式下,内置模型输出一个 list[dict]
,每幅图像一个字典。根据模型执行的任务,每个字典可能包含以下字段
“instances”: Instances 对象,具有以下字段
“pred_boxes”: Boxes 对象,存储 N 个框,每个检测到的实例一个。
“scores”:
Tensor
,N 个置信度分数的向量。“pred_classes”:
Tensor
,N 个标签的向量,范围为 [0, num_categories)。
“pred_masks”: 一个形状为 (N, H, W) 的
Tensor
,每个检测到的实例的掩码。“pred_keypoints”: 一个形状为 (N, num_keypoint, 3) 的
Tensor
。最后一维中的每一行都是 (x, y, score)。置信度分数大于 0。
“sem_seg”:
Tensor
,采用 (num_categories, H, W) 格式,语义分割预测。“proposals”: Instances 对象,具有以下字段
“proposal_boxes”: Boxes 对象,存储 N 个框。
“objectness_logits”: N 个置信度分数的 torch 向量。
“panoptic_seg”: 一个
(pred: Tensor, segments_info: Optional[list[dict]])
元组。pred
张量具有 (H, W) 形状,包含每个像素的段 ID。如果
segments_info
存在,则每个字典描述pred
中的一个段 ID,并具有以下字段“id”: 段 ID
“isthing”: 该段是否是事物还是素材
“category_id”: 该段的类别 ID。
如果像素的 ID 不存在于
segments_info
中,则认为它是 全景分割 中定义的空值标签。如果
segments_info
为 None,则pred
中的所有像素值必须 ≥ -1。值为 -1 的像素被分配空值标签。否则,每个像素的类别 ID 通过category_id = pixel // metadata.label_divisor
获得。
部分执行模型:¶
有时你可能希望获得模型内部的中间张量,例如特定层的输入、后处理之前的输出。由于通常存在数百个中间张量,因此没有提供你需要的中间结果的 API。你具有以下选择
编写一个(子)模型。按照 教程,你可以重写模型组件(例如模型的头部),使其与现有组件做同样的事情,但返回你需要的输出。
部分执行模型。你可以像往常一样创建模型,但使用自定义代码来执行它,而不是它的
forward()
。例如,以下代码在掩码头部之前获得掩码特征。images = ImageList.from_tensors(...) # preprocessed input tensor model = build_model(cfg) model.eval() features = model.backbone(images.tensor) proposals, _ = model.proposal_generator(images, features) instances, _ = model.roi_heads(images, features, proposals) mask_features = [features[f] for f in model.roi_heads.in_features] mask_features = model.roi_heads.mask_pooler(mask_features, [x.pred_boxes for x in instances])
使用 前向钩子。前向钩子可以帮助你获得特定模块的输入或输出。如果它们不是你想要的,它们至少可以与部分执行一起使用以获得其他张量。
所有选项都需要你阅读现有模型的文档,有时还需要阅读代码,以了解内部逻辑,以便编写代码来获得内部张量。