ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kornia RandomTransplantation 的 MPS 后端空轴过滤 Bug 修复解析(4160)

Kornia RandomTransplantation 的 MPS 后端空轴过滤 Bug 修复解析(4160) 计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载导读本文围绕 Kornia 版本迁移记录 changelog.d/migration-101.fixed.md 展开深入解析一个与 Apple MPS 后端直接相关的数据增强缺陷RandomTransplantation与RandomTransplantation3D在未指定excluded_labels时会在 MPS 设备上移植失败——输出完全等于输入。读完本文你将掌握该 Bug 的根因PyTorch MPS 后端对空轴all()的未定义求值、官方修复策略无物可排除时跳过过滤以及如何通过源码与测试用例验证修复行为。一、Bug 现象与影响范围1.1 现象描述根据 changelog.d/migration-101.fixed.md 的原始记录RandomTransplantationandRandomTransplantation3Dtransplanted nothing on MPS when noexcluded_labelswere given.也就是说在 Apple MPSMetal Performance Shaders后端上只要用户没有显式传入excluded_labels参数移植transplantation增强就会静默失效本应把批次中某张图的某个语义标签对应的像素区域复制粘贴到另一张图上结果输出与输入完全一致增强形同虚设。1.2 影响对象涉及两个公开 API均已在 kornia/augmentation/init.py 的__all__中导出RandomTransplantation、RandomTransplantation3D见 kornia/augmentation/init.pyRandomTransplantation2D 版本定义于 kornia/augmentation/_2d/mix/transplantation.py继承自MixAugmentationBaseV2RandomTransplantation3D3D 版本定义于 kornia/augmentation/_3d/mix/transplantation.py多重继承RandomTransplantation与AugmentationBase3D用于在AugmentationSequential容器内处理(B, C, D, H, W)体积数据。两者共享同一套核心逻辑因此 Bug 同时影响 2D 与 3D 场景。该增强算法源自论文《Semantic segmentation of surgical hyperspectral images under geometric domain shifts》sellner2023semantic常用于医学影像等需要跨样本语义对象复制的场景。二、RandomTransplantation 的工作原理回顾要理解这个 Bug先要理解移植增强的算法流程。根据 kornia/augmentation/_2d/mix/transplantation.py 的文档字符串其工作方式分为三步选定受体acceptor根据概率参数p从批次中挑选若干图像作为受体确定供体donor每个受体的供体是批次中位于其下方的一张图通过循环取模规则i - 1 mod B得到即donor_indices (acceptor_indices - 1) % batch_size见 params_from_input随机移植从供体的语义分割掩码中随机选取一个标签label把供体上该标签对应的图像特征与分割掩码区域整体复制到受体对应位置。移植由批次中第一个mask输入驱动可同时作用于图像DataKey.INPUT形状(B, C, *spatial)与掩码DataKey.MASK形状(B, *spatial)。数据键的默认顺序为[DataKey.INPUT, DataKey.MASK]见init。2.1 excluded_labels 参数的作用excluded_labels是移植增强的黑名单sequence of labels which should not be transplanted from a donor. This can be useful if only parts of the image are annotated and the non-annotated regions (with a specific label index) should be excluded from the augmentation.它常用于图像只有部分区域被标注的场景——例如标签 0 代表未标注区域此时应把标签 0 排除在可移植标签之外避免把无标注区域复制到其他样本上。构造函数中该参数默认值为None会被归一化为空列表再转为空张量见initif excluded_labels is None: excluded_labels [] if not isinstance(excluded_labels, torch.Tensor): excluded_labels torch.tensor(excluded_labels) self.excluded_labels: torch.Tensor excluded_labels2.2 标签筛选的底层实现在 params_from_input 中供体掩码的唯一标签会与excluded_labels做差集过滤if selected_labels not in params and selection not in params: if self.excluded_labels.device ! mask.device: self.excluded_labels self.excluded_labels.to(mask.device) donor_labels: list[torch.Tensor] [] eligible: list[int] [] for d in range(len(params[donor_indices])): current_mask mask[params[donor_indices][d]] labels current_mask.unique() if self.excluded_labels.numel() 0: labels labels[(labels.view(1, -1) ! self.excluded_labels.view(-1, 1)).all(dim0)] ...关键逻辑在于labels.view(1, -1) ! self.excluded_labels.view(-1, 1)这行它构造一个标签 × 排除项的布尔矩阵随后沿排除项轴dim0做.all()归约从而筛选出不等于任何排除标签的候选标签。三、Bug 根因MPS 后端对空轴all()的未定义求值3.1 为什么默认情况下会触发由于excluded_labels默认为空numel() 0当用户不传该参数时布尔矩阵的排除项维度大小为 0。此时沿空轴做all()归约在 CPU 与 CUDA 后端上会返回True数学上空集的全称命题为真即全标签都保留但在PyTorch 的 MPS 后端PyTorch 2.9上对空轴的all()求值结果是未定义的通常返回False。返回值一旦是False就意味着每一个供体标签都会被过滤掉labels被清空为长度为 0 的张量len(labels) 0判断失败该供体被判定为无合格标签其对应的受体从acceptor_indices中被剔除params_from_inputbatch_prob对应项被清零结果就是所有受体都不再是受体输出等于输入。这正是迁移记录中描述的transplanted nothing的完整机制。需要注意此处all()的语义是沿排除项这一空轴归约而非沿标签轴因此修复不能简单地替换all()的调用方式。3.2 为什么这是一个隐蔽的跨后端一致性问题同类归约在 CPU/CUDA 与 MPS 上的行为不一致属于典型的**后端语义差异backend semantic divergence**问题。同样的代码在 Linux/CUDA 环境测试通过一旦迁移到 Apple Silicon 的 MPS 环境增强器会静默失效且不抛任何异常——这对训练管线极具迷惑性因为增强无效果不会导致报错只会降低数据多样性、影响模型泛化且极难定位。四、官方修复方案无物可排除时跳过过滤4.1 修复后的源码修复的核心思路非常直接当excluded_labels为空时完全跳过差集过滤步骤不做空轴all()归约。修复后的代码在 kornia/augmentation/_2d/mix/transplantation.py 中体现为# Remove any label which is part of the excluded labels. Skip the reduction when there is nothing # to exclude: on MPS (PyTorch 2.9) all over an empty axis yields an undefined result, usually # False, where CPU and CUDA return True, and the filter would then discard every label. if self.excluded_labels.numel() 0: labels labels[(labels.view(1, -1) ! self.excluded_labels.view(-1, 1)).all(dim0)]修复后空排除表场景下labels直接保留current_mask.unique()的全部结果标签抽取labels[torch.randperm(len(labels))[0]]得以正常进行移植逻辑恢复可用。4.2 修复的边界影响需要特别指出的是该修复没有改变以下既有行为这些行为仍由 kornia/augmentation/_2d/mix/transplantation.py 中的逻辑保证当供体掩码本身没有任何标签如全空掩码时len(labels) 0依旧为假该供体仍会被判为无物可给其受体照常被剔除——这是算法设计的预期行为与排除表无关当excluded_labels非空、但恰好排除了供体的全部标签时过滤逻辑正常运行此时归约轴非空MPS 行为确定受体同样会被剔除标签抽取仍基于全局 CPU 随机生成器的torch.randperm测试test_convention_label_draw_uses_the_cpu_generator_whatever_the_device验证了这一点无论掩码位于何种设备随机状态不受影响。五、测试用例如何验证修复修复并非孤立的代码改动而是伴随一套可执行测试用于固化约定并防止回归。围绕移植增强的约定测试集中在 tests/augmentation/test_conventions_transplantation.py 与 tests/augmentation/test_conventions_3d.py 中相关变更记录见 changelog.d/4695.added.mdDocument the conventions ofRandomTransplantationandRandomTransplantation3D... with executable tests。与本文 Bug 直接相关的测试覆盖点包括默认空排除表的行为例如test_convention_transplant_follows_the_device_and_dtype_of_its_inputstests/augmentation/test_conventions_transplantation.py在构造RandomTransplantation(p1.0, excluded_labels[0])时明确注释 the exclusion list starts on the CPU验证排除列表会随输入迁移到目标设备且移植结果等于整行滚动image.roll(1, dims0)空掩码的边界情况测试注释明确 An empty mask has no label at all, so nothing is eligible: empty in, empty out, no raise见 tests/augmentation/test_conventions_transplantation.py说明空供体掩码的无合格标签路径与空排除表的路径是两条独立逻辑前者仍按设计剔除受体供体无需是受体test_convention_donor_need_not_be_an_acceptor验证供体取完整批次中的前驱(i - 1) mod B即使该前驱本身未被选中为受体也照常充当供体tests/augmentation/test_conventions_transplantation.py3D 类的容器行为tests/augmentation/test_conventions_3d.py 枚举 3D 子类确认RandomTransplantation3D是容器中唯一携带 mixinverse抛RuntimeError的 3D 增强并验证p_batch0.0时完全跳过。这些测试同时锁定了_params中batch_prob、acceptor_indices、donor_indices、selected_labels、selection等字段的契约确保后续任何后端相关的改动不会破坏参数重放replay语义。六、对使用者的实操建议结合本次修复在实际使用RandomTransplantation/RandomTransplantation3D时有几点值得注意升级即修复该修复随 migration-101 合入当前仓库主干。若你在 Apple Silicon MPS 环境下使用 Kornia且观察到移植增强无效输出等于输入升级到包含 #4160 修复的版本即可解决默认参数是安全的修复后不传excluded_labels即默认空表在 MPS、CPU、CUDA 上行为一致无需为了规避 Bug 而刻意传入空列表或占位排除项显式排除表的语义不变如果你用excluded_labels排除未标注区域如标签 0请确保排除列表确实与掩码中的标签值对应一旦供体掩码中剩余标签为空对应受体仍会被剔除这是设计行为见 params_from_input批次其余部分照常移植注意容器中的排名约束在AugmentationSequential中使用时2D 图像用RandomTransplantation、5D 体积用RandomTransplantation3D且移植类在容器中只能作为第一步——一旦其他增强运行过容器会把掩码递进为(B, 1, H, W)移植类会因排名规则拒绝处理详见 kornia/augmentation/_2d/mix/transplantation.py 的约定说明与 issue #4707跨设备迁移注意excluded_labels张量初始创建在 CPU构造函数中torch.tensor(excluded_labels)会在params_from_input中自动迁移到掩码所在设备kornia/augmentation/_2d/mix/transplantation.py无需手动干预。七、总结本次 #4160 修复是典型的后端语义差异导致的静默失效案例PyTorch MPS 后端2.9对空轴all()返回未定义值通常False而 CPU/CUDA 返回True导致RandomTransplantation/RandomTransplantation3D在默认无excluded_labels时过滤掉全部供体标签输出等于输入。修复方案简单而精准——无物可排除时跳过过滤归约配合 tests/augmentation/test_conventions_transplantation.py 与 tests/augmentation/test_conventions_3d.py 中的可执行约定测试保证了跨后端行为的一致性。对于在 Apple Silicon 上做语义分割数据增强的开发者这一修复直接关系到移植增强是否真正生效值得纳入升级清单。赞分享计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载相关推荐Kornia 修复 RandomTransplantation 在 MPS 上的移植失效空 excluded_labels 触发的 all() 归约陷阱与规避方案Kornia 修复 RandomTransplantation 在 MPS 上的移植失效空 excluded_labels 触发的 all 归约陷阱与规避方案计算机视觉深度学习人工智能图像处理Kornia 修复 Apple MPS 后端 SVD 8192 元素上限_torch_svd_cast 的 CPU 回退机制解析Kornia 修复 Apple MPS 后端 SVD 8192 元素上限 _torch_svd_cast 的 CPU 回退机制解析 导读 本文围绕 Korni计算机视觉人工智能深度学习图像处理Kornia 修复 MPS 等加速器后端的空张量转换YUV420/YUV422 空输入语义与 reshape 歧义问题深度解析Kornia 修复 MPS 等加速器后端的空张量转换YUV420/YUV422 空输入语义与 reshape 歧义问题深度解析 导读 本文围绕 Kornia计算机视觉深度学习人工智能图像处理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表