expand不分配新内存,仅通过修改stride和shape创建原Tensor的视图,共享同一data_ptr;只能扩展size=1的维度,-1表示保持原维大小,适用于广播场景;repeat则真实复制数据,显存随重复次数线性增长。

expand 不分配新内存,只改 stride 和 shape
expand 本质是返回原 Tensor 的一个视图(view),它不复制任何数据,只是修改了张量的 shape 和 stride。底层仍指向同一块内存地址,data_ptr() 与原张量一致。这意味着无论你 expand(1000, 1000) 还是 expand(10**6, 10**6),只要原始张量小,显存占用几乎不变。
repeat 真实复制数据,显存随维度线性增长
repeat 每次调用都会申请新内存,并把原始数据按指定次数完整拷贝进去。比如 x = torch.ones(3)(3 个 float32,共 12 字节),执行 x.repeat(1000, 1000) 后,实际生成的是含 3×10⁶ 个元素的新 Tensor,显存占用约 12 MB —— 是原来的百万倍。
- 参数
*sizes表示「每个维度上重复几次」,不是目标 shape;repeat(2, 3)是先在 dim0 复制 2 份,再对每份在 dim1 复制 3 份 - 即使只重复 1 次(如
repeat(1, 4)),也会触发完整拷贝,无法跳过内存分配 - 对大张量误用
repeat容易触发RuntimeError: CUDA out of memory
expand 的限制:只能作用于 size=1 的维度
这不是设计缺陷,而是广播机制的硬性前提。比如 x = torch.randn(1, 512) 可以 expand(64, 512)(因为第 0 维是 1),但 x = torch.randn(3, 512) 直接调 expand(64, 512) 会报错 RuntimeError: The expanded size ... must match the existing size ... at non-singleton dimension。
- 常见补救方式:先
unsqueeze(0)或view(1, 3, 512)创造 singleton 维,再expand -
expand(-1, 4)中的-1表示“保持该维原大小”,不是“自动推断”,它只允许出现在原本就合法的维度上 - 若需要绕过 singleton 限制又不想爆显存,可考虑
torch.broadcast_to(行为类似expand,但更严格校验广播规则)
真实场景中选哪个?看你要的是“共享值”还是“独立副本”
两者语义不同,不能简单说谁“更好”。关键判断点在于:后续操作是否要修改其中某一部分,且不希望影响其他部分。
立即学习“Python免费学习笔记(深入)”;
- 要用广播做 batch 计算(如
logits + bias.expand_as(logits)),选expand—— 安全、轻量、符合 PyTorch 广播逻辑 - 要做数据增强(如把一张图复制 5 次进 dataloader)、构造 tile 模式输入(如 patch 重复拼接),必须用
repeat—— 因为每个副本需独立参与梯度更新或变换 - 一个典型陷阱:
a = nn.Parameter(torch.ones(1, 10)); b = a.expand(100, 10); b[0] = 0会同时改掉a和所有b[i],因为它们共享内存;而c = a.repeat(100, 10); c[0] = 0只影响第 0 行
expand 一个 Parameter,它不会增加显存压力,但如果你误写成 repeat,哪怕只多一次,就可能让 batch size 被迫降到 1。


















