跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在Python中对PyTorch张量进行切片操作_掌握索引与Mask过滤技巧

PyTorch张量切片是否共享内存及支持梯度,取决于索引方式:基础方括号切片(如x[1:3, :, 0])通常返回视图、可微;高级索引(如x[[0,2], :, 0])触发拷贝、不可微;布尔索引需bool类型且同设备,结果为1D;index_select/gather用于可控采样;赋值仅视图支持,条件赋值用torch.where。 PyTorch张量切片本质是视图(view)或副本(copy)的生成,是否共享内存、是否可梯度回传,全由索引方式决定——直接用方括号
[...]
多数情况返回视图,而
torch.where
或布尔索引可能触发拷贝,且不支持梯度流向原始张量。 用基础方括号索引做高效视图切片 PyTorch的
[...]
语法默认返回原张量的视图(view),内存共享、支持反向传播。但前提是索引操作满足“连续内存块映射”条件,比如步长为1、无重复索引、维度未打散。
x[1:3, :, 0]
是安全视图;
x[[0,2], :, 0]
则强制拷贝(高级索引) 切片中混用
:
和列表索引(如
x[[0,1], 2:]
)会触发高级索引,结果不可微、不共享内存 避免写
x[0][1][2]
——这会链式调用三次
__getitem__
,每次返回新视图,效率低且易出错;改用
x[0, 1, 2]
负索引合法:
x[-1]
取最后一行,
x[:, -2:]
取最后两列 用布尔Mask过滤时必须注意梯度与设备一致性 布尔掩码(boolean mask)是最常用的条件筛选方式,但极易因类型或设备不匹配导致静默失败或梯度中断。 Mask必须是
torch.bool
类型,
x > 0.5
返回的就是
bool
;若用
(x > 0.5).float()
再转,就变成浮点掩码,
x[mask]
会报错 Mask和目标张量必须在同一个设备上:GPU张量不能用CPU上的mask索引,否则报
RuntimeError: Expected all tensors to be on the same device
布尔索引结果总是1维展平输出:
x[mask]
不管
x
是3D还是4D,返回的都是1D张量;需用
torch.nonzero(mask, as_tuple=True)
保留原始坐标结构 若需保持维度,优先考虑
torch.where
:例如
torch.where(mask, x, torch.zeros_like(x))
可实现掩码置零,且全程可导 用
torch.index_select
和
torch.gather
控制采样粒度 当需要按指定下标沿某维度稳定采样(尤其batch维度),
torch.index_select
比高级索引更可控;而
torch.gather
适合按每个样本独立选一个位置(如top-k预测)。 Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 立即学习 “ Python免费学习笔记(深入) ”;
torch.index_select(x, dim=0, index=torch.tensor([2,0,2]))
沿第0维取第2、第0、第2行,结果形状与
index
一致,且是视图(若
dim
连续)
torch.gather
要求
index
与输入同维,常用于分类任务:例如
logits.gather(1, labels.unsqueeze(1))
提取每个样本的真实类得分
torch.gather
的结果不可导到
index
(索引本身不参与梯度),但可导到
input
;若需索引可导,得换用
torch.softmax
加权求和 所有
index
张量必须是
torch.long
,传
int32
numpy数组或
torch.int32
会报
Expected dtype torch.int64
切片后修改值:
tensor[...] = value
的隐含规则 赋值操作看似简单,但PyTorch对左值切片有严格校验——它不仅检查形状兼容性,还判断是否能将梯度正确回传。 仅视图切片(非高级索引)支持原地赋值:
x[1:3] = 0
合法;
x[[0,2]] = 0
会报
IndexError: shape mismatch
赋值右值若为标量(如
0
或
1.0
),自动广播;若为张量,必须满足广播规则,且不能跨设备 在
torch.no_grad()
上下文外对切片赋值,梯度仍正常流动——但只流回被修改的视图对应位置,其余位置梯度为0 想实现“条件赋值”,别用
mask
直接索引左值(不支持),改用
torch.where
:例如
x = torch.where(mask, new_value, x)
最常被忽略的一点:切片操作是否产生视图,不取决于你写了什么符号,而取决于PyTorch内部的内存连续性判定逻辑。调试时可用
x.data_ptr() == x[1:].data_ptr()
验证是否共享内存,比查文档更快。

相关文章