torch.tensor() 直接转 list 慢是因为默认执行深拷贝、类型推断和内存连续化,尤其对嵌套 list 需递归解析 Python 对象,无法利用底层连续内存;用 numpy.array() 中转再 torch.from_numpy() 可大幅提升速度。

为什么 torch.tensor() 直接转 list 会慢?
因为 torch.tensor() 默认执行深拷贝 + 类型推断 + 内存连续化,尤其当输入是嵌套 list(比如 [[1,2],[3,4]])时,它得逐层递归解析 Python 对象,无法利用底层 C/Fortran 连续内存。实测 10k×10k 的 int list 转换可能耗时 300ms+,而同样数据用 NumPy 中转只要 20ms。
用 numpy.array() 中转再转 torch.Tensor
这是最常用且稳定的提速路径:先让 NumPy 处理 Python list 的解析和内存布局,再用 torch.from_numpy() 零拷贝接管内存(前提是 dtype 匹配且内存连续)。
- 确保 list 元素类型统一,否则
numpy.array()会降级为objectdtype,后续torch.from_numpy()会报错:TypeError: can't convert numpy.ndarray of type object to torch.Tensor - 加
dtype参数强制指定,比如np.array(data, dtype=np.float32),避免 NumPy 自动选float64导致后续 tensor 占用翻倍 -
torch.from_numpy()返回的 tensor 是非可梯度、共享内存的,如需梯度,必须显式调用.clone().requires_grad_(True)
示例:
import torch import numpy as np <p>data = [[i+j for j in range(1000)] for i in range(1000)]</p><h1>慢:t = torch.tensor(data)</h1><h1>快:</h1><p>arr = np.array(data, dtype=np.float32) t = torch.from_numpy(arr) # 零拷贝
提前预分配 + 填充,避开 list 构造
如果原始数据本就来自循环生成(比如逐行读 CSV 或模型逐 token 输出),不要先攒成 list 再转,直接初始化 tensor 后索引赋值。
立即学习“Python免费学习笔记(深入)”;
- 用
torch.empty()或torch.zeros()预分配,比torch.tensor()快一个数量级 - 注意索引顺序:Python list 是 row-major,
tensor[i][j]和tensor[i, j]等价,但后者更快(避免多次 __getitem__ 调用) - 避免在循环里反复调用
torch.cat()或torch.stack(),它们每次都会新建 tensor 并拷贝数据
示例:
# 错误习惯(慢)
rows = []
for i in range(1000):
row = [i * j for j in range(500)]
rows.append(row)
t = torch.tensor(rows)
<h1>正确做法(快)</h1><p>t = torch.empty(1000, 500)
for i in range(1000):
t[i] = torch.arange(500) * i # 直接写入
检查是否真需要 CPU tensor —— 有些场景可绕过转换
如果你最终要把 tensor 移到 GPU 上训练,而原始 list 来自 CPU 侧预处理,那不如把 list 转 NumPy → GPU tensor 一步到位(用 torch.as_tensor(..., device='cuda')),省去中间 CPU tensor 分配。
-
torch.as_tensor()不拷贝内存(如果输入是 NumPy array 且 dtype 兼容),比torch.tensor()更轻量 - 但注意:
torch.as_tensor(np_array, device='cuda')仍会触发 host-to-device 传输,不能跳过;只是省了 CPU tensor 创建开销 - 如果 list 是小规模(torch.tensor() 可读性优先,性能差异可忽略
真正卡顿往往出现在批量构造(比如 dataloader 中每 batch 把上百个 list 转 tensor),这时候中转 NumPy 或预分配才是关键。



















