〖MMDetection〗解析文件:mmdet/models/task_modules/prior_generators/anchor_generator.py

《深入解析 MMDetection 中的 AnchorGenerator》

在目标检测领域,锚点(anchors)是一种常用的技术,用于在不同的特征图上生成可能包含目标的区域。MMDetection 中的AnchorGenerator类就是用于生成这些锚点的重要工具。本文将深入剖析这个类的代码,帮助读者更好地理解其工作原理和功能。

一、类概述

AnchorGenerator是一个标准的锚点生成器,用于基于锚点的二维目标检测器。它可以根据不同的参数生成不同尺度、比例和位置的锚点,并可以在多个特征级别上生成锚点网格。这个类的主要功能包括:

  1. 初始化锚点生成器的参数,包括步长、比例、尺度、基本尺寸、中心位置等。
  2. 生成基本锚点,根据给定的参数生成单个级别上的基本锚点。
  3. 生成网格锚点,在多个特征级别上生成网格锚点,即根据特征图的大小和步长,将基本锚点放置在特征图的每个位置上。
  4. 生成稀疏锚点,根据给定的索引生成稀疏锚点。
  5. 生成有效标志,确定哪些锚点在图像的有效区域内。

二、关键代码分析

1. 初始化函数

def __init__(self,
                 strides: Union[List[int], List[Tuple[int, int]]],
                 ratios: List[float],
                 scales: Optional[List[int]] = None,
                 base_sizes: Optional[List[int]] = None,
                 scale_major: bool = True,
                 octave_base_scale: Optional[int] = None,
                 scales_per_octave: Optional[int] = None,
                 centers: Optional[List[Tuple[float, float]]] = None,
                 center_offset: float = 0.,
                 use_box_type: bool = False) -> None:
    # check center and center_offset
    if center_offset!= 0:
        assert centers is None, 'center cannot be set when center_offset' \
                                f'!=0, {centers} is given.'
    if not (0 <= center_offset <= 1):
        raise ValueError('center_offset should be in range [0, 1], '
                         f'{center_offset} is given.')
    if centers is not None:
        assert len(centers) == len(strides), \
            'The number of strides should be the same as centers, got ' \
            f'{strides} and {centers}'
    # calculate base sizes of anchors
    self.strides = [_pair(stride) for stride in strides]
    self.base_sizes = [min(stride) for stride in self.strides
                       ] if base_sizes is None else base_sizes
    assert len(self.base_sizes) == len(self.strides), \
        'The number of strides should be the same as base sizes, got ' \
        f'{self.strides} and {self.base_sizes}'
    # calculate scales of anchors
    assert ((octave_base_scale is not None
             and scales_per_octave is not None) ^ (scales is not None)), \
        'scales and octave_base_scale with scales_per_octave cannot' \
        ' be set at the same time'
    if scales is not None:
        self.scales = torch.Tensor(scales)
    elif octave_base_scale is not None and scales_per_octave is not None:
        octave_scales = np.array(
            [2**(i / scales_per_octave) for i in range(scales_per_octave)])
        scales = octave_scales * octave_base_scale
        self.scales = torch.Tensor(scales)
    else:
        raise ValueError('Either scales or octave_base_scale with '
                         'scales_per_octave should be set')
    self.octave_base_scale = octave_base_scale
    self.scales_per_octave = scales_per_octave
    self.ratios = torch.Tensor(ratios)
    self.scale_major = scale_major
    self.centers = centers
    self.center_offset = center_offset
    self.base_anchors = self.gen_base_anchors()
    self.use_box_type = use_box_type

在初始化函数中,设置了各种参数,并检查了参数的合法性。然后,计算了锚点的基本尺寸和尺度,并生成了基本锚点列表。

2.1 gen_base_anchors函数
  1. 功能:这个函数用于生成多尺度的基础锚点(base anchors),每个特征层级对应一组基础锚点。

  2. 工作流程

    • 初始化一个空列表multi_level_base_anchors来存储不同层级的基础锚点。
    • 遍历self.base_sizes列表,这个列表通常代表不同特征层级的基础尺寸。
    • 对于每个基础尺寸:
      • 如果self.centers不为None,则从self.centers中获取对应层级的中心坐标,否则将中心设为默认值(根据center_offset和基础尺寸计算)。
      • 调用self.gen_single_level_base_anchors函数生成该层级的基础锚点,并将其添加到multi_level_base_anchors列表中。
    • 最后返回包含所有层级基础锚点的列表。
2.2 gen_single_level_base_anchors函数
  1. 功能:生成单个特征层级的基础锚点。

  2. 工作流程

    • 接收参数:
      • base_size:单个特征层级的基础锚点尺寸。
      • scales:锚点的缩放比例。
      • ratios:锚点的高宽比。
      • center(可选):该层级基础锚点的中心坐标,如果为None则使用默认计算方式。
    • 初始化变量:
      • 如果centerNone,根据center_offset和基础尺寸计算锚点中心坐标x_centery_center
    • 计算高宽比相关变量:
      • 计算高宽比的平方根得到h_ratios
      • 计算宽度比例为高宽比平方根的倒数得到w_ratios
    • 根据scale_major的不同情况计算锚点宽度和高度:
      • 如果scale_major为真:
        • ws是通过基础尺寸乘以宽度比例(按列展开)再乘以缩放比例(按行展开),最后展平得到的张量,表示不同锚点的宽度。
        • 类似地,hs表示不同锚点的高度。
      • 否则:
        • 以另一种方式计算wshs
    • 生成基础锚点张量:
      • 通过锚点中心坐标和宽度、高度计算出四个坐标值,分别表示锚点的左上角和右下角坐标。
      • 将这四个坐标值组成一个列表base_anchors
      • 使用torch.stack将这个列表沿着最后一个维度堆叠成一个张量并返回,这个张量代表该层级的基础锚点。

以给定的调试过程为例:

  1. gen_base_anchors函数中,遍历self.base_sizes[4, 8, 16, 32, 64],对于每个基础尺寸调用gen_single_level_base_anchors生成对应层级的基础锚点。

  2. gen_single_level_base_anchors函数中,当处理基础尺寸为4时:

    • 由于centerNone,计算出x_center = 0y_center = 0
    • 计算出h_ratios = tensor([0.7071, 1.0000, 1.4142])w_ratios = tensor([1.4142, 1.0000, 0.7071])
    • 根据scale_major的情况(这里假设为真或假进行不同的计算),计算出ws = tensor([45.2548, 32.0000, 22.6274])hs = tensor([22.6274, 32.0000, 45.2548])
    • 最终生成基础锚点张量为tensor([[-22.6274, -11.3137, 22.6274, 11.3137], [-16.0000, -16.0000, 16.0000, 16.0000], [-11.3137, -22.6274, 11.3137, 22.6274]])

config:

anchor_generator=dict(
type='AnchorGenerator',
scales=[8],
ratios=[0.5, 1.0, 2.0],
strides=[4, 8, 16, 32, 64])
  1. 首先分析配置:

    • scales=[8]表示锚点的缩放比例只有一个值 8。
    • ratios=[0.5, 1.0, 2.0]给出了三种不同的高宽比。
    • strides=[4, 8, 16, 32, 64]这个参数在这里暂时不直接参与锚点生成的计算,但可能在后续的其他操作中有作用,比如确定不同特征层级对应的步长等。
  2. gen_base_anchors函数执行过程:

    • 遍历self.base_sizes,这里假设self.base_sizesstrides相同,即[4, 8, 16, 32, 64]。对于每个基础尺寸,调用gen_single_level_base_anchors函数生成该层级的基础锚点。
  3. gen_single_level_base_anchors函数执行过程:

    • 以基础尺寸为 4 为例:

      • 初始化w = 4h = 4,因为centerNone,所以计算出x_center = self.center_offset * w = 0y_center = self.center_offset * h = 0
      • h_ratios = torch.sqrt(ratios),即计算三种高宽比的平方根,得到tensor([0.7071, 1.0000, 1.4142])
      • w_ratios = 1 / h_ratios,得到tensor([1.4142, 1.0000, 0.7071])
      • 由于只有一个缩放比例 8,且假设scale_major为真,计算过程如下:
        • ws = (w * w_ratios[:, None] * scales[None, :]).view(-1),即4 * tensor([1.4142, 1.0000, 0.7071])[:, None] * tensor([8.])[None, :],得到tensor([45.2548, 32.0000, 22.6274])
        • hs = (h * h_ratios[:, None] * scales[None, :]).view(-1),即4 * tensor([0.7071, 1.0000, 1.4142])[:, None] * tensor([8.])[None, :],得到tensor([22.6274, 32.0000, 45.2548])
      • 生成基础锚点:
        • base_anchors = [x_center - 0.5 * ws, y_center - 0.5 * hs, x_center + 0.5 * ws, y_center + 0.5 * hs],得到[tensor([-22.6274, -16.0000, -11.3137]), tensor([-11.3137, -16.0000, -22.6274]), tensor([22.6274, 16.0000, 11.3137]), tensor([11.3137, 16.0000, 22.6274])]
        • base_anchors = torch.stack(base_anchors, dim=-1),得到最终的锚点张量tensor([[-22.6274, -11.3137, 22.6274, 11.3137], [-16.0000, -16.0000, 16.0000, 16.0000], [-11.3137, -22.6274, 11.3137, 22.6274]])
    • 对于其他基础尺寸(8、16、32、64),执行类似的计算过程,只是基础尺寸不同,会得到不同大小的锚点。

2. 生成基本锚点函数

def gen_base_anchors(self) -> List[Tensor]:
    multi_level_base_anchors = []
    for i, base_size in enumerate(self.base_sizes):
        center = None
        if self.centers is not None:
            center = self.centers[i]
        multi_level_base_anchors.append(
            self.gen_single_level_base_anchors(
                base_size,
                scales=self.scales,
                ratios=self.ratios,
                center=center))
    return multi_level_base_anchors

def gen_single_level_base_anchors(self,
                                      base_size: Union[int, float],
                                      scales: Tensor,
                                      ratios: Tensor,
                                      center: Optional[Tuple[float]] = None) \
            -> Tensor:
    w = base_size
    h = base_size
    if center is None:
        x_center = self.center_offset * w
        y_center = self.center_offset * h
    else:
        x_center, y_center = center
    h_ratios = torch.sqrt(ratios)
    w_ratios = 1 / h_ratios
    if self.scale_major:
        ws = (w * w_ratios[:, None] * scales[None, :]).view(-1)
        hs = (h * h_ratios[:, None] * scales[None, :]).view(-1)
    else:
        ws = (w * scales[:, None] * w_ratios[None, :]).view(-1)
        hs = (h * scales[:, None] * h_ratios[None, :]).view(-1)
    base_anchors = [
        x_center - 0.5 * ws, y_center - 0.5 * hs, x_center + 0.5 * ws,
        y_center + 0.5 * hs
    ]
    base_anchors = torch.stack(base_anchors, dim=-1)
    return base_anchors

gen_base_anchors函数生成多个级别的基本锚点列表,通过调用gen_single_level_base_anchors函数生成每个级别的基本锚点。gen_single_level_base_anchors函数根据给定的基本尺寸、尺度和比例,生成单个级别的基本锚点。

3. 生成网格锚点函数

def grid_priors(self,
                    featmap_sizes: List[Tuple],
                    dtype: torch.dtype = torch.float32,
                    device: DeviceType = 'cuda') -> List[Tensor]:
    assert self.num_levels == len(featmap_sizes)
    multi_level_anchors = []
    for i in range(self.num_levels):
        anchors = self.single_level_grid_priors(
            featmap_sizes[i], level_idx=i, dtype=dtype, device=device)
        multi_level_anchors.append(anchors)
    return multi_level_anchors

def single_level_grid_priors(self,
                                 featmap_size: Tuple[int, int],
                                 level_idx: int,
                                 dtype: torch.dtype = torch.float32,
                                 device: DeviceType = 'cuda') -> Tensor:
    base_anchors = self.base_anchors[level_idx].to(device).to(dtype)
    feat_h, feat_w = featmap_size
    stride_w, stride_h = self.strides[level_idx]
    shift_x = torch.arange(0, feat_w, device=device).to(dtype) * stride_w
    shift_y = torch.arange(0, feat_h, device=device).to(dtype) * stride_h
    shift_xx, shift_yy = self._meshgrid(shift_x, shift_y)
    shifts = torch.stack([shift_xx, shift_yy, shift_xx, shift_yy], dim=-1)
    all_anchors = base_anchors[None, :, :] + shifts[:, None, :]
    all_anchors = all_anchors.view(-1, 4)
    if self.use_box_type:
        all_anchors = HorizontalBoxes(all_anchors)
    return all_anchors

grid_priors函数生成多个级别的网格锚点列表,通过调用single_level_grid_priors函数生成每个级别的网格锚点。single_level_grid_priors函数根据给定的特征图大小、级别索引和数据类型,生成单个级别的网格锚点。

以下是对这两个函数的详细解析:

3.1 grid_priors函数
  1. 函数功能

    • 这个函数用于在多个特征级别上生成网格锚点。它遍历每个特征级别,调用single_level_grid_priors函数生成该级别的网格锚点,并将结果收集到一个列表中返回。
  2. 参数解释

    • featmap_sizesList[Tuple]):一个包含多个元组的列表,每个元组表示一个特征图的大小,通常是(高度,宽度)。
    • dtypetorch.dtype):锚点的数据类型,默认为torch.float32
    • deviceDeviceType):锚点将被放置的设备,可以是字符串表示的设备名称(如’cuda’)或torch.device对象。
  3. 函数执行过程

    • 参数检查
      • assert self.num_levels == len(featmap_sizes):检查锚点生成器的级别数量是否与输入的特征图大小列表的长度相等。
    • 生成多级锚点
      • multi_level_anchors = []:创建一个空列表,用于存储多个级别的锚点。
      • for i in range(self.num_levels):遍历每个特征级别。
      • anchors = self.single_level_grid_priors(featmap_sizes[i], level_idx=i, dtype=dtype, device=device):调用single_level_grid_priors函数生成当前级别的网格锚点。
      • multi_level_anchors.append(anchors):将当前级别的锚点添加到列表中。
    • 返回结果
      • return multi_level_anchors:返回包含多个级别锚点的列表。
3.2single_level_grid_priors函数
  1. 函数功能

    • 这个函数用于生成单个特征级别上的网格锚点。它根据输入的特征图大小、级别索引、数据类型和设备,生成该级别上的所有锚点。
  2. 参数解释

    • featmap_sizeTuple[int, int]):当前特征图的大小,是一个元组(高度,宽度)。
    • level_idxint):当前特征图的级别索引。
    • dtypetorch.dtype):锚点的数据类型,默认为torch.float32
    • deviceDeviceType):锚点将被放置的设备,可以是字符串表示的设备名称(如’cuda’)或torch.device对象。
  3. 函数执行过程

    • 获取基本锚点
      • base_anchors = self.base_anchors[level_idx].to(device).to(dtype):从锚点生成器的基本锚点列表中获取当前级别的基本锚点,并将其移动到指定的设备和数据类型。
    • 获取特征图尺寸和步长
      • feat_h, feat_w = featmap_size:解包输入的特征图大小,得到高度和宽度。
      • stride_w, stride_h = self.strides[level_idx]:获取当前级别的步长。
    • 生成位移张量
      • shift_x = torch.arange(0, feat_w, device=device).to(dtype) * stride_w:生成在 x 方向上的位移张量,范围从 0 到特征图宽度,步长为当前级别的 x 方向步长,并转换为指定的数据类型和设备。
      • shift_y = torch.arange(0, feat_h, device=device).to(dtype) * stride_h:生成在 y 方向上的位移张量,范围从 0 到特征图高度,步长为当前级别的 y 方向步长,并转换为指定的数据类型和设备。
    • 生成网格
      • shift_xx, shift_yy = self._meshgrid(shift_x, shift_y):使用_meshgrid函数生成二维网格的 x 和 y 坐标。
      • shifts = torch.stack([shift_xx, shift_yy, shift_xx, shift_yy], dim=-1):将 x 和 y 坐标堆叠成一个形状为(网格点数,4)的张量,表示四个角的位移。
    • 生成所有锚点
      • all_anchors = base_anchors[None, :, :] + shifts[:, None, :]:将基本锚点广播到与位移张量相同的形状,然后将它们相加,得到所有可能位置的锚点。
      • all_anchors = all_anchors.view(-1, 4):将锚点张量重塑为形状为(网格点数 * 基本锚点数,4)的张量。
    • 应用框类型(可选)
      • 如果self.use_box_type为真,将锚点张量转换为特定的框类型。
    • 返回结果
      • return all_anchors:返回当前特征级别上的所有锚点张量。

4. 生成稀疏锚点函数

def sparse_priors(self,
                  prior_idxs: Tensor,
                  featmap_size: Tuple[int, int],
                  level_idx: int,
                  dtype: torch.dtype = torch.float32,
                  device: DeviceType = 'cuda') -> Tensor:
    height, width = featmap_size
    num_base_anchors = self.num_base_anchors[level_idx]
    base_anchor_id = prior_idxs % num_base_anchors
    x = (prior_idxs //
         num_base_anchors) % width * self.strides[level_idx][0]
    y = (prior_idxs // width //
         num_base_anchors) % height * self.strides[level_idx][1]
    priors = torch.stack([x, y, x, y], 1).to(dtype).to(device) + \
        self.base_anchors[level_idx][base_anchor_id, :].to(device)
    return priors

sparse_priors函数根据给定的索引、特征图大小和级别索引,生成稀疏锚点。

5. 生成有效标志函数

def valid_flags(self,
                featmap_sizes: List[Tuple[int, int]],
                pad_shape: Tuple,
                device: DeviceType = 'cuda') -> List[Tensor]:
    assert self.num_levels == len(featmap_sizes)
    multi_level_flags = []
    for i in range(self.num_levels):
        anchor_stride = self.strides[i]
        feat_h, feat_w = featmap_sizes[i]
        h, w = pad_shape[:2]
        valid_feat_h = min(int(np.ceil(h / anchor_stride[1])), feat_h)
        valid_feat_w = min(int(np.ceil(w / anchor_stride[0])), feat_w)
        flags = self.single_level_valid_flags((feat_h, feat_w),
                                              (valid_feat_h, valid_feat_w),
                                              self.num_base_anchors[i],
                                              device=device)
        multi_level_flags.append(flags)
    return multi_level_flags

def single_level_valid_flags(self,
                                 featmap_size: Tuple[int, int],
                                 valid_size: Tuple[int, int],
                                 num_base_anchors: int,
                                 device: DeviceType = 'cuda') -> Tensor:
    feat_h, feat_w = featmap_size
    valid_h, valid_w = valid_size
    assert valid_h <= feat_h and valid_w <= feat_w
    valid_x = torch.zeros(feat_w, dtype=torch.bool, device=device)
    valid_y = torch.zeros(feat_h, dtype=torch.bool, device=device)
    valid_x[:valid_w] = 1
    valid_y[:valid_h] = 1
    valid_xx, valid_yy = self._meshgrid(valid_x, valid_y)
    valid = valid_xx & valid_yy
    valid = valid[:, None].expand(valid.size(0),
                                  num_base_anchors).contiguous().view(-1)
    return valid

valid_flags函数生成多个级别的有效标志列表,通过调用single_level_valid_flags函数生成每个级别的有效标志。single_level_valid_flags函数根据给定的特征图大小、有效大小和基本锚点数量,生成单个级别的有效标志。

以下是对这两个函数的详细解析:

5.1 valid_flags函数
  1. 函数功能

    • 这个函数用于生成多个特征级别上锚点的有效标志列表。它遍历每个特征级别,调用single_level_valid_flags函数生成该级别的有效标志,并将结果收集到一个列表中返回。
  2. 参数解释

    • featmap_sizesList[Tuple[int, int]]):一个包含多个元组的列表,每个元组表示一个特征图的大小,通常是(高度,宽度)。
    • pad_shapeTuple):图像的填充形状,通常是(高度,宽度,…)。
    • deviceDeviceType):有效标志将被放置的设备,可以是字符串表示的设备名称(如’cuda’)或torch.device对象。
  3. 函数执行过程

    • 参数检查
      • assert self.num_levels == len(featmap_sizes):检查锚点生成器的级别数量是否与输入的特征图大小列表的长度相等。
    • 生成多级有效标志
      • multi_level_flags = []:创建一个空列表,用于存储多个级别的有效标志。
      • for i in range(self.num_levels):遍历每个特征级别。
      • anchor_stride = self.strides[i]:获取当前级别的步长。
      • feat_h, feat_w = featmap_sizes[i]:解包当前特征图的大小,得到高度和宽度。
      • h, w = pad_shape[:2]:解包图像的填充形状,获取高度和宽度。
      • valid_feat_h = min(int(np.ceil(h / anchor_stride[1])), feat_h):计算当前级别上在高度方向上的有效特征图高度,取图像高度除以 y 方向步长的向上取整结果与当前特征图高度的较小值。
      • valid_feat_w = min(int(np.ceil(w / anchor_stride[0])), feat_w):计算当前级别上在宽度方向上的有效特征图宽度,取图像宽度除以 x 方向步长的向上取整结果与当前特征图宽度的较小值。
      • flags = self.single_level_valid_flags((feat_h, feat_w), (valid_feat_h, valid_feat_w), self.num_base_anchors[i], device=device):调用single_level_valid_flags函数生成当前级别的有效标志。
      • multi_level_flags.append(flags):将当前级别的有效标志添加到列表中。
    • 返回结果
      • return multi_level_flags:返回包含多个级别有效标志的列表。
5.2 single_level_valid_flags函数
  1. 函数功能

    • 这个函数用于生成单个特征图上锚点的有效标志。它根据输入的特征图大小、有效大小、基本锚点数量和设备,确定每个锚点在特征图上是否有效,并返回一个布尔张量表示有效标志。
  2. 参数解释

    • featmap_sizeTuple[int, int]):特征图的大小,是一个元组(高度,宽度)。
    • valid_sizeTuple[int, int]):特征图的有效大小,是一个元组(有效高度,有效宽度)。
    • num_base_anchorsint):基本锚点的数量。
    • deviceDeviceType):有效标志将被放置的设备,可以是字符串表示的设备名称(如’cuda’)或torch.device对象。
  3. 函数执行过程

    • 获取特征图和有效大小
      • feat_h, feat_w = featmap_size:解包输入的特征图大小,得到高度和宽度。
      • valid_h, valid_w = valid_size:解包输入的有效大小,得到有效高度和有效宽度。
      • assert valid_h <= feat_h and valid_w <= feat_w:确保有效大小不超过特征图大小。
    • 生成 x 和 y 方向的有效标志张量
      • valid_x = torch.zeros(feat_w, dtype=torch.bool, device=device):创建一个长度为特征图宽度的全零布尔张量,表示 x 方向的有效标志。
      • valid_y = torch.zeros(feat_h, dtype=torch.bool, device=device):创建一个长度为特征图高度的全零布尔张量,表示 y 方向的有效标志。
      • valid_x[:valid_w] = 1:将 x 方向有效标志张量的前有效宽度个元素设置为 1,表示这些位置是有效的。
      • valid_y[:valid_h] = 1:将 y 方向有效标志张量的前有效高度个元素设置为 1,表示这些位置是有效的。
    • 生成二维有效标志
      • valid_xx, valid_yy = self._meshgrid(valid_x, valid_y):使用_meshgrid函数生成二维网格的有效标志。
      • valid = valid_xx & valid_yy:对 x 和 y 方向的有效标志进行逻辑与操作,得到二维有效标志。
    • 扩展有效标志
      • valid = valid[:, None].expand(valid.size(0), num_base_anchors).contiguous().view(-1):将二维有效标志在第二个维度上扩展基本锚点数量倍,然后重塑为一维张量,表示每个锚点的有效标志。
    • 返回结果
      • return valid:返回单个特征级别上每个锚点的有效标志张量。

6. 字符串表示函数

def __repr__(self) -> str:
    indent_str = '    '
    repr_str = self.__class__.__name__ + '(\n'
    repr_str += f'{indent_str}strides={self.strides},\n'
    repr_str += f'{indent_str}ratios={self.ratios},\n'
    repr_str += f'{indent_str}scales={self.scales},\n'
    repr_str += f'{indent_str}base_sizes={self.base_sizes},\n'
    repr_str += f'{indent_str}scale_major={self.scale_major},\n'
    repr_str += f'{indent_str}octave_base_scale='
    repr_str += f'{self.octave_base_scale},\n'
    repr_str += f'{indent_str}scales_per_octave='
    repr_str += f'{self.scales_per_octave},\n'
    repr_str += f'{indent_str}num_levels={self.num_levels}\n'
    repr_str += f'{indent_str}centers={self.centers},\n'
    repr_str += f'{indent_str}center_offset={self.center_offset})'
    return repr_str

__repr__函数返回一个字符串,表示AnchorGenerator对象的参数。

三、结语

AnchorGenerator类是 MMDetection 中用于生成锚点的重要工具。它可以根据不同的参数生成不同尺度、比例和位置的锚点,并可以在多个特征级别上生成锚点网格和有效标志。通过深入理解这个类的代码,我们可以更好地掌握 MMDetection 中锚点生成的原理和方法,为目标检测任务提供更好的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值