以下内容覆盖张量创建、基础属性、核心操作、Numpy互转四大模块,所有代码均可直接运行。
一、张量创建:5个核心函数
张量(Tensor)是Pytorch的基础数据结构,可理解为多维数组,对标Numpy的ndarray,但支持GPU加速与自动求导。
1.torch.tensor():从数据直接创建
最通用的创建方式,可从列表、NumPy数组等生成张量。
python
import torch
import numpy as np
# 从列表创建
a = torch.tensor([1, 2, 3])
print("从列表创建:", a) # tensor([1, 2, 3])
# 创建二维张量
b = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print("二维张量:\n", b)
# 从numpy数组创建(后续会讲内存共享区别)
np_arr = np.array([1, 2, 3])
c = torch.tensor(np_arr) # 会拷贝数据,不共享内存
输出如下:

注意:torch.tensor()默认会拷贝原始数据;若数据类型不指定,整数默认int64,浮点数默认float32。
2.torch.zeros():创建全0张量
python
import torch
# 形状为 (2, 3) 的全0张量
zeros = torch.zeros(2, 3)
print("全0张量:\n", zeros)
# 指定数据类型和设备
zeros_gpu = torch.zeros(2, 3, dtype=torch.float64, device='cuda')
输出如下:

3.torch.ones():创建全1张量
python
import torch
# 形状为 (3, 4) 的全1张量
ones = torch.ones(3, 4)
print("全1张量:\n", ones)
输出如下:

4.torch.randn():创建标准正态分布随机张量
数值服从均值为0、方差为1的正态分布,常用于模型权重初始化。
python
import torch
# 形状为 (2, 2) 的随机张量
randn = torch.randn(2, 2)
print("正态随机张量:\n", randn)
输出如下:

5.torch.arange():创建等差序列张量
对标Python的range和Numpy的np.arange。
python
import torch
# 0 到 9 的等差序列(左闭右开)
arange_1 = torch.arange(10)
print("等差序列:", arange_1) # tensor([0, 1, 2, ..., 9])
# 指定起点、终点、步长
arange_2 = torch.arange(2, 10, 2)
print("指定步长:", arange_2) # tensor([2, 4, 6, 8])
输出如下:

二、张量基础三要素:shape、dtype、device
这三个属性是张量的核心标识,也是90%报错的根源(维度不匹配、类型不统一、设备不统一)。

代码示例:
python
import torch
x = torch.randn(2, 3, device='cuda')
# 1. 形状
print("形状:", x.shape) # torch.Size([2, 3])
print("形状:", x.size()) # 与 shape 等价
# 2. 数据类型
print("数据类型:", x.dtype) # torch.float32
# 转换为 float64
x_double = x.to(dtype=torch.float64)
# 3. 设备
print("所在设备:", x.device) # device(type='cuda', index=0)
# 转移到 CPU
x_cpu = x.cpu()
# 转移回 GPU
x_gpu = x_cpu.cuda()
踩坑提醒:运算的两个张量必须在同一设备上,CPU张量和GPU张量无法直接计算,会报错。
三、核心常用操作
1.索引与切片
用法和NumPy高度一致,支持多维索引、步长、布尔索引。
python
import torch
x = torch.arange(12).reshape(3, 4)
print("原始张量:\n", x)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 取第 0 行
print("第0行:", x[0])
# 取第 1 列
print("第1列:", x[:, 1])
# 取前 2 行,第 1-3 列
print("切片结果:\n", x[:2, 1:4])
# 布尔索引:取大于 5 的元素
print("大于5的元素:", x[x > 5])
输出结果如下:

2.维度重塑:reshape vs view
两者都能改变张量形状,是最常用的操作,但底层有本质区别:
- view:仅适用于连续张量 (is_contiguous()为True),操作后与原张量共享内存,属于轻量级操作,修改一个另一个会变。
- reshape:不要求张量连续,底层优先尝试view,不满足时自动拷贝数据,兼容性更强,日常开发优先用reshape。
python
import torch
x = torch.arange(12)
# reshape 变形为 3行4列
x_reshape = x.reshape(3, 4)
print("reshape 结果形状:", x_reshape.shape) # torch.Size([3, 4])
# view 变形
x_view = x.view(3, 4)
print("view 结果形状:", x_view.shape)
# 验证内存共享:修改原张量,view 结果同步变化
x[0] = 100
print("原张量修改后,view结果第0个元素:", x_view[0, 0].item()) # 100
输出如下:

3.张量拼接:cat vs stack
这里最容易混淆的一组操作,核心区别:
- torch.cat:在已有维度上拼接,拼接后维度总数不变。
- torch.stack:会新增一个维度再拼接,拼接后维度总数+1。
python
import torch
a = torch.zeros(2, 3)
b = torch.ones(2, 3)
# cat 拼接:dim=0 按行拼,dim=1 按列拼
cat0 = torch.cat([a, b], dim=0)
print("cat dim=0 形状:", cat0.shape) # torch.Size([4, 3])
cat1 = torch.cat([a, b], dim=1)
print("cat dim=1 形状:", cat1.shape) # torch.Size([2, 6])
# stack 拼接:新增维度
stack0 = torch.stack([a, b], dim=0)
print("stack dim=0 形状:", stack0.shape) # torch.Size([2, 2, 3])
stack1 = torch.stack([a, b], dim=1)
print("stack dim=1 形状:", stack1.shape) # torch.Size([2, 2, 3])
输出如下:

适用场景:cat常用于拼接数据集batch、特征;stack常用于将多个样本堆叠成batch。
4.维度增减:unsqueeze vs squeeze
- unsqueeze(dim):在指定位置新增一个维度(大小为1),常用于给单条数据加batch维度。
- squeeze(dim):删除指定位置大小为1的维度;不指定dim时删除所有大小为1的维度。
python
import torch
x = torch.randn(3, 4)
# 新增第 0 维:模拟 batch 维度
x_unsq = x.unsqueeze(0)
print("unsqueeze后形状:", x_unsq.shape) # torch.Size([1, 3, 4])
# 压缩第 0 维
x_sq = x_unsq.squeeze(0)
print("squeeze后形状:", x_sq.shape) # torch.Size([3, 4])
# squeeze 只能删除大小为 1 的维度,非 1 维度无影响
x_test = torch.randn(2, 1, 3, 1)
print("全压缩后形状:", x_test.squeeze().shape) # torch.Size([2, 3])
输出如下:

四、与NumPy的互转及内存共享机制
1.基础互转操作
python
import numpy as np
import torch
# 张量 → NumPy 数组
tensor_a = torch.ones(3)
np_a = tensor_a.numpy()
print("NumPy数组:", np_a)
# NumPy 数组 → 张量
np_b = np.array([1, 2, 3])
tensor_b = torch.from_numpy(np_b)
print("张量:", tensor_b)
输出如下:

2.核心:内存共享机制
CPU张量通过.numpy()和torch.from_numpy()转换时,默认共享底层内存,修改其中一个,另一个会同步变化。
python
import numpy as np
import torch
np_arr = np.array([1, 2, 3])
tensor_arr = torch.from_numpy(np_arr)
# 修改 numpy 数组,张量同步变化
np_arr[0] = 100
print("修改numpy后张量值:", tensor_arr[0].item()) # 100
# 修改张量,numpy 数组同步变化
tensor_arr[1] = 200
print("修改张量后numpy值:", np_arr[1]) # 200
输出如下:

3.不共存内存的场景
- GPU张量:.numpy()只能用于CPU张量,GPU张量必须先.cpu()再转换,且会拷贝数据。
- torch.tensor()创建:从NumPy数组用torch.tensor()创建时,会强制拷贝数据,不共享内存。
- 使用.clone():显式克隆张量,断开内存共享。
python
import numpy as np
import torch
# 断开内存共享的方式
np_arr = np.array([1, 2, 3])
tensor_clone = torch.from_numpy(np_arr).clone() # 克隆一份
np_arr[0] = 100
print("克隆后不受numpy影响:", tensor_clone[0].item()) # 1
输出如下:
