- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】mmcv
OpenMMLab Computer Vision Foundation
导读
本文围绕 OpenMMLab 系列算法库的公共基础设施 MMCV 展开,系统讲解其数据变换(data transform)机制:从统一基类BaseTransform的字典式输入输出约定,到由多个变换类首尾相接组成的数据流水线(data pipeline),再到字段映射、随机选择、多目标扩展等高级变换包装。读完本文,你将掌握在配置文件中编排一套完整 pipeline 的方法、如何自定义数据变换类,以及如何借助KeyMapper、TransformBroadcaster等包装实现跨字段、多目标、共享随机参数等复杂数据增强需求。
在 OpenMMLab 算法库中,数据集的构建和数据的准备是相互解耦的。通常,数据集的构建只对数据集进行解析,记录每个样本的基本信息;而数据的准备则是通过一系列的数据变换,根据样本的基本信息进行数据加载、预处理、格式化等操作。MMCV 正是承载这一"数据准备"环节的核心模块,全部实现位于 mmcv/transforms 目录下。
数据变换的设计:一切皆字典
在 MMCV 中,我们使用各种可调用的数据变换类来进行数据的操作。这些数据变换类可以接受若干配置参数进行实例化,之后通过调用的方式对输入的数据字典进行处理。同时,我们约定所有数据变换都接受一个字典作为输入,并将处理后的数据输出为一个字典。一个简单的例子如下:
>>> import numpy as np >>> from mmcv.transforms import Resize >>> >>> transform = Resize(scale=(224, 224)) >>> data_dict = {'img': np.random.rand(256, 256, 3)} >>> data_dict = transform(data_dict) >>> print(data_dict['img'].shape) (224, 224, 3)数据变换类会读取输入字典的某些字段,并且可能添加、或者更新某些字段。这些字段的键大部分情况下是固定的,如Resize会固定地读取输入字典中的"img"等字段。我们可以在对应类的文档中了解对输入输出字段的约定。在源码中,这种约定通常以 "Required Keys / Modified Keys / Added Keys" 三段式 docstring 呈现,例如 mmcv/transforms/loading.py 中的LoadImageFromFile明确写着:
- Required Keys:
img_path - Modified Keys:
img、img_shape、ori_shape
在编写或阅读数据变换时,先看这类字段约定,可以快速判断某个变换在 pipeline 中的位置是否合适。
尺寸顺序的约定
默认情况下,在需要图像尺寸作为初始化参数的数据变换(如Resize、Pad)中,图像尺寸的顺序均为(width, height)。而在数据变换返回的字典中,图像相关的尺寸,如img_shape、ori_shape、pad_shape等,均为(height, width)。这一点在拼接 pipeline 时尤其容易踩坑:例如Resize(scale=(224, 224))初始化参数表示宽高均为 224,而变换后字典里的img_shape则存储为(224, 224)的 (H, W) 形式。
统一基类 BaseTransform
MMCV 为所有的数据变换类提供了一个统一的基类BaseTransform,其定义位于 mmcv/transforms/base.py:
class BaseTransform(metaclass=ABCMeta): def __call__(self, results: dict) -> dict: return self.transform(results) @abstractmethod def transform(self, results: dict) -> dict: pass所有的数据变换类都需要继承BaseTransform,并实现transform方法。transform方法的输入和输出均为一个字典。通过__call__转发到transform,数据变换对象天然成为可调用对象(callable),可以直接以transform(data_dict)的方式使用。在自定义数据变换类一节中,我们会更详细地介绍如何实现一个数据变换类。
从源码结构看,BaseTransform通过ABCMeta元类将transform声明为抽象方法,这意味着任何遗漏transform实现的子类在实例化时都会直接报错,从机制上保证了所有变换都遵循统一的字典协议。
数据流水线(Data Pipeline)
如上所述,所有数据变换的输入和输出都是一个字典,而且根据 OpenMMLab 中有关数据集的约定,数据集中每个样本的基本信息也是一个字典。这样一来,我们可以将所有的数据变换操作首尾相接,组合成为一条数据流水线(data pipeline),输入数据集中样本的信息字典,输出完成一系列处理后的信息字典。
在配置文件中,数据流水线是一个若干数据变换配置字典组成的列表,每个数据集都需要设置参数pipeline来定义该数据集需要进行的数据准备操作。以分类任务为例,一个典型的数据流水线在配置文件中的配置如下:
pipeline = [ dict(type='LoadImageFromFile'), dict(type='Resize', size=256, keep_ratio=True), dict(type='CenterCrop', crop_size=224), dict(type='Normalize', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375]), dict(type='ClsFormatBundle') ] dataset = dict( ... pipeline=pipeline, ... )对每个样本,数据集中保存的基本信息是一个字典;之后每经过一个数据变换操作,数据字典中都会加入新的字段或更新现有的字段。上述 pipeline 的执行逻辑可以概括为:
LoadImageFromFile:根据img_path加载图像,写入img,并记录img_shape与ori_shape;Resize:将图像等比缩放到短边 256(keep_ratio=True);CenterCrop:居中裁剪出224×224的区域;Normalize:用 ImageNet 风格的 mean/std 做归一化,并记录img_norm_cfg;ClsFormatBundle:将数据整理成模型输入的格式(该变换属于算法库上层封装,分类任务常见)。
Compose:pipeline 的底层载体
配置文件中的 pipeline 列表在运行时由Compose类负责组织。Compose同样注册在TRANSFORMS中,定义于 mmcv/transforms/wrappers.py:它接收一个由 dict 配置或可调用对象组成的序列,将 dict 配置通过TRANSFORMS.build(transform)构建成真实变换对象,然后在transform方法中按顺序逐个调用:
def transform(self, results: Dict) -> Optional[Dict]: for t in self.transforms: results = t(results) if results is None: return None return results注意一个细节:如果某个变换返回None(例如加载空图且设置了ignore_empty=True),Compose会立即终止整条流水线并返回None。因此编写自定义变换时,如无特殊需要,应始终返回处理后的字典。
注册器 TRANSFORMS
配置中dict(type='LoadImageFromFile')之所以能被解析成对象,依赖的是 OpenMMLab 统一的注册器机制。MMCV 直接复用 mmengine 的TRANSFORMS注册器(见 mmcv/transforms/builder.py),所有内置变换类(LoadImageFromFile、Resize、Normalize等)都通过@TRANSFORMS.register_module()完成注册。这意味着你在自定义变换类时,同样只需用该装饰器注册,即可在配置文件中以type字段引用。
常用的数据变换类
按照功能,常用的数据变换类可以大致分为数据加载、数据预处理与增强、数据格式化三类。以下类均可从mmcv.transforms顶层导入(见 mmcv/transforms/init.py)。
数据加载
为了支持大规模数据集的加载,通常在Dataset初始化时不加载数据,只加载相应的路径。因此需要在数据流水线中进行具体数据的加载。
| class | 功能 |
|---|---|
LoadImageFromFile | 根据路径加载图像 |
LoadAnnotations | 加载和组织标注信息,如 bbox、语义分割图等 |
LoadImageFromFile(mmcv/transforms/loading.py)的核心参数包括:
to_float32(默认False):是否将加载的图像转为 float32 数组;为False时返回 uint8 数组;color_type(默认'color'):传给mmcv.imfrombytes的颜色读取标志;imdecode_backend(默认'cv2'):图像解码后端;ignore_empty(默认False):为True时允许加载空图或不存在路径(此时返回None,会使Compose提前终止);backend_args:用于指定文件后端(如本地磁盘、HTTP、ceph 等),是 v2.0.0rc4 之后推荐使用的参数,旧的file_client_args已被标记为将要废弃。
LoadAnnotations(mmcv/transforms/loading.py)负责把数据集原始的标注组织成统一格式:原始标注中instances列表包含bbox((x1, y1, x2, y2)顺序)、bbox_label、keypoints([x1, y1, v1, …, xn, yn, vn]格式)以及seg_map_path等;变换后输出为gt_bboxes(np.float32的(N, 4)数组)、gt_bboxes_labels(np.int64)、gt_seg_map(uint8 的(H, W)数组)、gt_keypoints(np.float32的(N, NK, 3)数组)等字段。
数据预处理及增强
数据预处理和增强通常是对图像本身进行变换,如裁剪、填充、缩放等。
| class | 功能 |
|---|---|
Pad | 填充图像边缘 |
CenterCrop | 居中裁剪 |
Normalize | 对图像进行归一化 |
Resize | 按照指定尺寸或比例缩放图像 |
RandomResize | 缩放图像至指定范围的随机尺寸 |
RandomMultiscaleResize | 缩放图像至多个尺寸中的随机一个尺寸 |
RandomGrayscale | 随机灰度化 |
RandomFlip | 图像随机翻转 |
MultiScaleFlipAug | 支持缩放和翻转的测试时数据增强 |
以上类均定义在 mmcv/transforms/processing.py(其中RandomMultiscaleResize即源码中的RandomChoiceResize,类声明位于第 1001 行附近)。这里挑选几个核心类展开:
Resize(mmcv/transforms/processing.py)通过scale或scale_factor指定目标,二者不能同时为None;同时会联动缩放 bbox、分割图与关键点,主要参数:
scale(int 或(w, h)元组):目标尺寸;传 int 时视为(scale, scale);scale_factor(float 或(w_scale, h_scale)元组):按比例缩放;keep_ratio(默认False):是否保持宽高比缩放(配合scale使用,相当于"短边对齐");clip_object_border(默认True):是否将越过图像边界的 bbox 裁剪回边界内(MOT 等数据集的 gt bbox 允许越界时可设为False);backend(默认'cv2'):'cv2'或'pillow',两种后端结果略有差异;interpolation(默认'bilinear'):插值方式;cv2 后端支持"nearest"、"bilinear"、"bicubic"、"area"、"lanczos",pillow 后端仅支持"nearest"、"bilinear"。
变换结束后,Resize会更新img_shape并写入scale、scale_factor、keep_ratio字段。
Normalize(mmcv/transforms/processing.py)参数为mean、std和to_rgb(默认True)。当to_rgb=True时,mean/std 应按 RGB 通道顺序给出(因为底层mmcv.imnormalize会先把 BGR 图像转为 RGB 再归一化);to_rgb=False时顺序与图像通道一致。归一化完成后,还会向字典写入img_norm_cfg(包含mean、std、to_rgb),便于推理阶段做反向统计或调试。
Pad提供三种填充模式:填充到固定尺寸、填充到可被某数整除的最小尺寸、填充为正方形,后两种可以同时使用,并会写入pad_shape、pad_fixed_size、pad_size_divisor字段。
RandomFlip(第 1112 行)与RandomResize(第 1381 行)都通过@cache_randomness装饰的随机方法产生随机变量(详见后文"装饰器 cache_randomness"),从而天然支持在TransformBroadcaster中共享随机参数。
MultiScaleFlipAug(第 721 行)与TestTimeAug(第 877 行)用于测试阶段:前者按多个尺度和翻转方向对图像做增强并收集所有结果(test-time augmentation),后者是更通用的测试时增强包装。
数据格式化
数据格式化操作通常是对数据进行的类型转换,这些类位于 mmcv/transforms/formatting.py。
| class | 功能 |
|---|---|
ToTensor | 将指定的数据转换为torch.Tensor |
ImageToTensor | 将图像转换为torch.Tensor |
ToTensor接收keys参数,逐个将指定字段转为张量;键名支持'a.b.c'的点分路径,用于定位嵌套字典中的字段。ImageToTensor则额外完成通道转置:输入图像维度顺序为(H, W, C),输出转换为(C, H, W);若输入只有(H, W)二维,则输出为(1, H, W)。底层类型转换由模块级函数to_tensor完成(mmcv/transforms/formatting.py),支持numpy.ndarray、torch.Tensor、Sequence、int、float等类型。注意ToTensor与ImageToTensor仅在安装 PyTorch 的环境下可用——从 mmcv/transforms/init.py 可以看到,导入torch失败时这两个类不会进入__all__。
自定义数据变换类
要实现一个新的数据变换类,需要继承BaseTransform,并实现transform方法。这里,我们使用一个简单的翻转变换(MyFlip)作为示例:
import random import mmcv from mmcv.transforms import BaseTransform, TRANSFORMS @TRANSFORMS.register_module() class MyFlip(BaseTransform): def __init__(self, direction: str): super().__init__() self.direction = direction def transform(self, results: dict) -> dict: img = results['img'] results['img'] = mmcv.imflip(img, direction=self.direction) return results从而,我们可以实例化一个MyFlip对象,并将之作为一个可调用对象,来处理我们的数据字典:
import numpy as np transform = MyFlip(direction='horizontal') data_dict = {'img': np.random.rand(224, 224, 3)} data_dict = transform(data_dict) processed_img = data_dict['img']又或者,在配置文件的 pipeline 中使用MyFlip变换:
pipeline = [ ... dict(type='MyFlip', direction='horizontal'), ... ]需要注意的是,如需在配置文件中使用,需要保证MyFlip类所在的文件在运行时能够被导入(例如在算法库的transforms模块__init__.py中完成导入,使注册动作在加载配置前生效)。
变换包装(Transform Wrapper)
变换包装是一种特殊的数据变换类,它们本身并不操作数据字典中的图像、标签等信息,而是对其中定义的数据变换的行为进行增强。全部包装类实现于 mmcv/transforms/wrappers.py,并通过TRANSFORMS注册,因此也可以直接出现在配置文件的 pipeline 中。
字段映射(KeyMapper)
字段映射包装(KeyMapper)用于对数据字典中的字段进行映射。例如,一般的图像处理变换都从数据字典中的"img"字段获得值。但有些时候,我们希望这些变换处理数据字典中其他字段中的图像,比如"gt_img"字段。
如果配合注册器和配置文件使用的话,在配置文件中数据集的pipeline中如下例使用字段映射包装:
pipeline = [ ... dict(type='KeyMapper', mapping={ 'img': 'gt_img', # 将 "gt_img" 字段映射至 "img" 字段 'mask': ..., # 不使用原始数据中的 "mask" 字段。即对于被包装的数据变换,数据中不包含 "mask" 字段 }, auto_remap=True, # 在完成变换后,将 "img" 重映射回 "gt_img" 字段 transforms=[ # 在 `RandomFlip` 变换类中,我们只需要操作 "img" 字段即可 dict(type='RandomFlip'), ]) ... ]利用字段映射包装,我们在实现数据变换类时,不需要考虑在transform方法中考虑各种可能的输入字段名,只需要处理默认的字段即可。
从实现上看(mmcv/transforms/wrappers.py),KeyMapper的处理分为三步:
_map_input:按mapping把外层字段(如gt_img)重命名为内层标准字段(img),映射值可以是字符串、列表/元组(聚合成序列)、嵌套 dict(结构化收集),...(Ellipsis)表示显式忽略该键(内部用哨兵对象IgnoreKey标记);_apply_transforms:对被包装的变换序列执行,期间IgnoreKey对内部变换不可见;_map_output:按remapping(auto_remap=True时自动取mapping的逆映射)把内层字段写回外层字段。
此外KeyMapper还提供allow_nonexist_keys参数(默认False):为False时映射的外层键必须存在于输入数据中,否则抛异常;为True时缺失键同样被标记为IgnoreKey,不参与内部变换。
随机选择(RandomChoice)和随机执行(RandomApply)
随机选择包装(RandomChoice)用于从一系列数据变换组合中随机应用一个数据变换组合。利用这一包装,我们可以简单地实现一些数据增强功能,比如 AutoAugment。
如果配合注册器和配置文件使用的话,在配置文件中数据集的pipeline中如下例使用随机选择包装:
pipeline = [ ... dict(type='RandomChoice', transforms=[ [ dict(type='Posterize', bits=4), dict(type='Rotate', angle=30.) ], # 第一种随机变化组合 [ dict(type='Equalize'), dict(type='Rotate', angle=30) ], # 第二种随机变换组合 ], prob=[0.4, 0.6] # 两种随机变换组合各自的选用概率 ) ... ]随机执行包装(RandomApply)用于以指定概率随机执行数据变换组合。例如:
pipeline = [ ... dict(type='RandomApply', transforms=[dict(type='Rotate', angle=30.)], prob=0.3) # 以 0.3 的概率执行被包装的数据变换 ... ]从源码看(mmcv/transforms/wrappers.py):RandomChoice在初始化时把每个候选组合分别构建为独立的Compose子流水线,其prob列表长度必须与组合数一致且总和为 1(不传则默认均匀分布);RandomApply的prob默认为 0.5。两者都用@cache_randomness装饰随机选择方法(random_pipeline_index/random_apply),因此当它们自身被TransformBroadcaster包装且开启随机共享时,多个目标会选中同一组合、执行同一随机策略。
多目标扩展(TransformBroadcaster)
通常,一个数据变换类只会从一个固定的字段读取操作目标。虽然我们也可以使用KeyMapper来改变读取的字段,但无法将变换一次性应用于多个字段的数据。为了实现这一功能,我们需要借助多目标扩展包装(TransformBroadcaster)。
多目标扩展包装(TransformBroadcaster)有两个用法,一是将数据变换作用于指定的多个字段,二是将数据变换作用于某个字段下的一组目标中。
1. 应用于多个字段
假设我们需要将数据变换应用于"lq"(low-quality)和"gt"(ground-truth)两个字段中的图像上。
pipeline = [ dict(type='TransformBroadcaster', # 分别应用于 "lq" 和 "gt" 两个字段,并将二者应设置 "img" 字段 mapping={'img': ['lq', 'gt']}, # 在完成变换后,将 "img" 字段重映射回原先的字段 auto_remap=True, # 是否在对各目标的变换中共享随机变量 # 更多介绍参加后续章节(随机变量共享) share_random_params=True, transforms=[ # 在 `RandomFlip` 变换类中,我们只需要操作 "img" 字段即可 dict(type='RandomFlip'), ]) ]在多目标扩展的mapping设置中,我们同样可以使用...来忽略指定的原始字段。如以下例子中,被包裹的RandomCrop会对字段"img"中的图像进行裁剪,并且在字段"img_shape"存在时更新剪裁后的图像大小。如果我们希望同时对两个图像字段"lq"和"gt"进行相同的随机裁剪,但只更新一次"img_shape"字段,可以通过例子中的方式实现:
pipeline = [ dict(type='TransformBroadcaster', mapping={ 'img': ['lq', 'gt'], 'img_shape': ['img_shape', ...], }, # 在完成变换后,将 "img" 和 "img_shape" 字段重映射回原先的字段 auto_remap=True, # 是否在对各目标的变换中共享随机变量 # 更多介绍参加后续章节(随机变量共享) share_random_params=True, transforms=[ # `RandomCrop` 类中会操作 "img" 和 "img_shape" 字段。若 "img_shape" 空缺, # 则只操作 "img" dict(type='RandomCrop'), ]) ]2. 应用于一个字段的一组目标
假设我们需要将数据变换应用于"images"字段,该字段为一个图像组成的 list。
pipeline = [ dict(type='TransformBroadcaster', # 将 "images" 字段下的每张图片映射至 "img" 字段 mapping={'img': 'images'}, # 在完成变换后,将 "img" 字段下的图片重映射回 "images" 字段的列表中 auto_remap=True, # 是否在对各目标的变换中共享随机变量 share_random_params=True, transforms=[ # 在 `RandomFlip` 变换类中,我们只需要操作 "img" 字段即可 dict(type='RandomFlip'), ]) ]TransformBroadcaster是KeyMapper的子类(mmcv/transforms/wrappers.py),其transform流程为:先按mapping做输入映射,再通过scatter_sequence把多个目标拆分为等长的输入列表(要求所有映射序列长度一致,否则抛ValueError),逐个_apply_transforms后按 key 重新聚合(collate)为 "dict of list",最后做输出重映射。当share_random_params=True时,会用上下文管理器cache_random_params包裹整个执行过程,使被包装变换中可缓存的随机变量只生成一次、对所有目标保持一致;反之则退化为nullcontext。
装饰器cache_randomness
在TransformBroadcaster中,我们提供了share_random_params选项来支持在多次数据变换中共享随机状态。例如,在超分辨率任务中,我们希望将随机变换同步作用于低分辨率图像和原始图像。如果我们希望在自定义的数据变换类中使用这一功能,需要在类中标注哪些随机变量是支持共享的。这可以通过装饰器cache_randomness来实现。
以上文中的MyFlip为例,我们希望以一定的概率随机执行翻转:
from mmcv.transforms.utils import cache_randomness @TRANSFORMS.register_module() class MyRandomFlip(BaseTransform): def __init__(self, prob: float, direction: str): super().__init__() self.prob = prob self.direction = direction @cache_randomness # 标注该方法的输出为可共享的随机变量 def do_flip(self): flip = True if random.random() > self.prob else False return flip def transform(self, results: dict) -> dict: img = results['img'] if self.do_flip(): results['img'] = mmcv.imflip(img, direction=self.direction) return results在上面的例子中,我们用cache_randomness装饰do_flip方法,即将该方法返回值flip标注为一个支持共享的随机变量。进而,在TransformBroadcaster对多个目标的变换中,这一变量的值都会保持一致。
其底层机制位于 mmcv/transforms/utils.py:装饰器通过__set_name__把被装饰方法名记录进类的_methods_with_randomness列表;在cache_random_params上下文(该上下文由TransformBroadcaster的share_random_params=True触发)内,实例的_cache_enabled标志被置真,被装饰方法首次调用时把返回值缓存进instance._cache,后续调用直接返回缓存值,从而保证"随机参数只生成一次、处处共享";同时上下文管理器还会统计每次处理样本过程中随机方法的调用次数,若超过一次会抛出RuntimeError,避免同一随机方法在一个样本内被多次消费导致语义混乱。
装饰器avoid_cache_randomness
在一些情况下,我们无法将数据变换中产生随机变量的过程单独放在类方法中。例如数据变换中使用的来自第三方库的模块,这些模块将随机变量相关的部分封装在了内部,导致无法将其抽出为数据变换的类方法。这样的数据变换无法通过装饰器cache_randomness标注支持共享的随机变量,进而无法在多目标扩展时共享随机变量。
为了避免在多目标扩展中误用此类数据变换,我们提供了另一个装饰器avoid_cache_randomness,用来对此类数据变换进行标记:
from mmcv.transforms.utils import avoid_cache_randomness @TRANSFORMS.register_module() @avoid_cache_randomness class MyRandomTransform(BaseTransform): def transform(self, results: dict) -> dict: ...用avoid_cache_randomness标记的数据变换类,当其实例被TransformBroadcaster包装且将参数share_random_params设置为 True 时,会抛出异常,以此提醒用户不能这样使用。具体来说(mmcv/transforms/utils.py),装饰器在类上挂载一个描述符avoid_cache_randomness;cache_random_params上下文管理器在_start_cache阶段检测到该标志后立即抛出RuntimeError。此外,若该类内同时存在用cache_randomness装饰的方法,装饰时也会直接抛错(两者语义互斥)。
在使用avoid_cache_randomness时需要注意以下几点:
avoid_cache_randomness只用于装饰数据变换类(BaseTransform的子类),而不能用于装饰其他一般的类、类方法或函数;- 被
avoid_cache_randomness修饰的数据变换作为基类时,其子类将不会继承这一特性。如果子类仍无法共享随机变量,则应再次使用avoid_cache_randomness修饰(源码通过读取objtype.__dict__而非属性查找实现"不继承"); - 只有当一个数据变换具有随机性,且无法共享随机参数时,才需要以
avoid_cache_randomness修饰。无随机性的数据变换不需要修饰。
实战验证:测试用例参考
想要快速理解这些机制的实际调用关系,可以直接阅读仓库中对应的单元测试:
- tests/test_transforms/test_transforms_wrapper.py 覆盖了
Compose、KeyMapper、TransformBroadcaster、RandomChoice、RandomApply等包装类的行为,包括auto_remap、...忽略键、share_random_params随机共享等关键场景; - tests/test_transforms/test_transforms_processing.py 覆盖了
Resize、Pad、Normalize、RandomFlip、RandomResize等预处理增强类; - tests/test_transforms/test_transforms_formatting.py 与 tests/test_transforms/test_transforms_loading.py 分别验证格式化类与加载类的字段约定。
阅读测试是理解"输入输出字段约定"最直观的方式:测试中构造的输入字典、断言的输出字段,与源码 docstring 中的 Required/Modified/Added Keys 一一对应。
小结
MMCV 的数据变换体系围绕"字典进、字典出"这一统一协议展开:
- 基础层:
BaseTransform定义了所有变换的接口契约,Compose负责把多个变换串成 pipeline; - 功能层:
LoadImageFromFile、LoadAnnotations负责加载,Resize、Pad、CenterCrop、Normalize、RandomFlip等负责预处理与增强,ToTensor、ImageToTensor负责格式化; - 组合层:
KeyMapper解决字段名差异,RandomChoice/RandomApply引入随机组合策略,TransformBroadcaster实现多目标同步变换,cache_randomness与avoid_cache_randomness一对装饰器则从机制上保证了随机变量共享的正确性与安全性。
掌握这套设计之后,无论是编排一个分类任务的分类 pipeline、超分辨率任务中对低分辨率与原始图像做同步增强,还是实现类似 AutoAugment 的随机策略搜索,都可以直接用配置表达,而不必为每种场景重写数据加载与预处理逻辑。
- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】mmcv
OpenMMLab Computer Vision Foundation
相关推荐
MMCV 数据变换(Data Transformation)完全指南:从 BaseTransform 到可共享随机状态的 Transform Wrapper
MMCV 数据变换(Data Transformation)完全指南:从 BaseTransform 到可共享随机状态的 Transform Wrapper 导
人工智能计算机视觉深度学习MMagic 数据变换(Data Transforms)设计指南:从流水线原理到自定义实现
MMagic 数据变换(Data Transforms)设计指南:从流水线原理到自定义实现 导读 本文基于 MMagic 官方文档《How to design
媒体生成计算机视觉深度学习人工智能大模型MMCV transforms 模块完全指南:数据加载、预处理与变换包装器的 API 详解
MMCV transforms 模块完全指南:数据加载、预处理与变换包装器的 API 详解 本文是 MMCV 计算机视觉基础库中 mmcv.transforms
人工智能计算机视觉深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考