PyTorch 中contiguous函数使用详解和代码演示

在 PyTorch 中,contiguous() 是一个用于 张量内存布局优化 的函数。它的作用是在需要时返回一个内存布局为连续(contiguous)的张量,常用于 transpose、permute 等操作后。


一、为什么需要 contiguous()

PyTorch 的张量是以 行优先(row-major)顺序 存储的。当你对张量使用 transpose()、permute() 等操作时,虽然张量的维度看起来改变了 ,但底层的内存并没有重新排列,只是修改了索引方式。

一些 PyTorch 函数(如 .view())要求输入张量必须是 连续的内存块,否则就会报错。


二、函数定义与用法

python 复制代码
Tensor.contiguous(memory_format=torch.contiguous_format) → Tensor

返回值:

返回一个与当前张量具有相同数据但在内存中 连续排列 的副本。如果当前张量已经是连续的,就直接返回自身。


三、典型使用场景

1. view() 前需要 .contiguous()

python 复制代码
x = torch.randn(2, 3, 4)
y = x.permute(1, 0, 2)  # 改变维度顺序
z = y.contiguous().view(3, 8)  # 安全 reshape

如果不加 .contiguous():

python 复制代码
z = y.view(3, 8)  # ⚠️ 报错:RuntimeError: view size is not compatible with input tensor's size and stride

2. 使用 transpose() 后需要 .contiguous() 参与后续操作

python 复制代码
a = torch.randn(10, 20)
b = a.transpose(0, 1)  # Not contiguous now
b = b.contiguous()     # 重新在内存中复制数据为连续块

四、查看是否是连续的

python 复制代码
x.is_contiguous()

五、底层原理简要

PyTorch 张量有 .stride() 属性定义每一维的跳步。连续的张量满足:

python 复制代码
x.stride()[i] = product(x.shape[i+1:])

一旦 .transpose() / .permute() 修改了维度顺序,这个规则就被破坏,因此 .contiguous() 会重新分配内存来确保是连续的。


六、contiguous()项目演示

下面是一个完整的 PyTorch 小项目,演示 .contiguous() 的必要性与作用。将看到在对张量进行 permute() 后,使用 .view() reshape 会失败,只有 .contiguous() 可以解决问题。

项目内容:张量维度变换与 .contiguous() 对比演示

项目结构:

复制代码
contiguous_demo/
├── main.py
└── requirements.txt

requirements.txt

txt 复制代码
torch>=2.0

main.py

python 复制代码
import torch

def describe_tensor(tensor, name):
    print(f"{name}: shape={tensor.shape}, strides={tensor.stride()}, is_contiguous={tensor.is_contiguous()}")

def main():
    print("=== 创建张量 ===")
    x = torch.randn(2, 3, 4)  # 原始张量 shape [2, 3, 4]
    describe_tensor(x, "x")

    print("\n=== 进行 permute 操作(交换维度) ===")
    y = x.permute(1, 0, 2)  # shape: [3, 2, 4]
    describe_tensor(y, "y (after permute)")

    print("\n尝试 view reshape 到 [3, 8](不使用 contiguous)")
    try:
        z = y.view(3, 8)  # ⚠️ 报错:因为 y 的内存不是连续的
    except RuntimeError as e:
        print(f"RuntimeError: {e}")

    print("\n=== 使用 .contiguous() 后 reshape ===")
    y_contig = y.contiguous()
    describe_tensor(y_contig, "y_contig (after .contiguous())")

    z = y_contig.view(3, 8)
    describe_tensor(z, "z (reshaped)")

    print("\n✅ reshape 成功,结果如下:")
    print(z)

if __name__ == "__main__":
    main()

运行方法

  1. 安装依赖:
bash 复制代码
pip install -r requirements.txt
  1. 运行程序:
bash 复制代码
python main.py

运行结果概览

将看到:

  • 原始张量是连续的;
  • permute() 后变成非连续;
  • 使用 .view() 报错;
  • .contiguous() 修复内存后成功 reshape。

小总结要点

操作 是否连续 能否 .view()
原始张量 ✅ 是 ✅ 是
permute() 后 ❌ 否 ❌ 报错
.contiguous() 后 ✅ 是 ✅ 是

总结记忆:

操作 是否影响连续性? 是否需要 .contiguous()
view() ❗ 需要连续 ✅ 是
permute() / transpose() 破坏连续性 ✅ 是
reshape() 自动处理 ❌ 不需要(内部处理)
相关推荐
benchmark_cc12 分钟前
用 QuantDash 读取美股行情:AAPL.US 的运行前检查、排错顺序与数据校验清单
python·数据分析·pandas·量化交易·股票数据·quantdash
陈嘿萌26 分钟前
TIP 2026 | 不再混成一张! RealFusion从模态不变性重想图像融合
图像处理·人工智能·深度学习·计算机视觉·学术研究与理论基础
正在走向自律1 小时前
AI Agent 落地这一年:从“能跑起来”到“敢放出去”
大数据·人工智能·ai agent·智能体·mcp·a2a
不惑_2 小时前
理解启元,从论文开始,RT-2 55B 只有 1~3Hz,OpenVLA 7B 反而高 16.5%——三代 VLA 论文解读,动作表示才是分水岭
人工智能·论文解读
IT_陈寒2 小时前
Redis内存暴涨,没想到是AOF重写捣的鬼
前端·人工智能·后端
楚山之石2 小时前
【JCO】mpMRI 先行替代 TURBT 初始分期:BladderPath 随机试验让 MIBC 患者提前 45 天得到正确治疗
人工智能·学习·mri·医学影像
AI视频工具指南2 小时前
用 AI 能做哪些视频?按想交付的作品选做法
人工智能·aigc·音视频
武天旭2 小时前
AI安全--AI大模型的对抗样本攻击与防御解析
人工智能·深度学习·安全·机器学习
shijuejianceliu3 小时前
传统规则视觉与嵌入式AI智能相机的技术差异
人工智能·嵌入式硬件·视觉检测·相机
goujunwe3 小时前
GEO 内容的“可摘录性”打磨技巧:段落、表格、小标题怎么写,方便大模型提取独立答案块
大数据·人工智能