一、张量核心概念解析
1.1 张量本质剖析
张量是PyTorch的核心数据结构,是具有统一数据类型(dtype)的多维矩阵,其数学定义可表示为:
T ∈ R d 1 × d 2 × ⋯ × d n T \in \mathbb{R}^{d_1 \times d_2 \times \cdots \times d_n} T∈Rd1×d2×⋯×dn
其中 d i d_i di 表示第i个维度的长度。与NumPy数组相比,张量具有两大核心优势:
- GPU加速计算能力
- 自动微分支持(Autograd)
1.2 张量元信息三要素
t = torch.randn(3, 4, 5)
print(f"形状: {
t.shape}") # torch.Size([3, 4, 5])
print(f"数据类型: {
t.dtype}") # torch.float32
print(f"存储设备: {
t.device}") # cpu/cuda:0
二、张量创建全方法详解
2.1 直接构造法
# 从Python列表创建(自动推断类型)
t1 = torch.tensor([[1., 2], [3, 4]])
# 显式指定参数创建
t2 = torch.tensor([1, 2, 3],
dtype=torch.float64,
device='cuda',
requires_grad=True)
# 特殊矩阵生成
diag_tensor = torch.diag(torch.tensor([1,2,3])) # 对角矩阵
linspace_t = torch.linspace(0, 10, 5) # 线性空间采样
2.2 工厂函数创建法
函数 | 功能描述 | 数学原理 |
---|---|---|
torch.empty(3,3) |
未初始化矩阵 | 分配内存但不设置初始值 |
torch.zeros_like(x) |
创建与x同形的全0张量 | T i j = 0 T_{ij} = 0 Tij=0 |
torch.randperm(10) |
生成随机排列 | Fisher-Yates洗牌算法 |
torch.logspace() |
对数均分采样 | 1 0 s t a r t ∼ 1 0 e n d 10^{start} \sim 10^{end} 10start∼10end |
2.3 NumPy互操作进阶
# 内存共享验证实验
np_arr = np.array([1, 2, 3])
t = torch.from_numpy(np_arr)
np_arr[0] = 999
print(t) # 输出tensor([999, 2, 3])
# 阻断内存共享的方法
t_independent = torch.tensor(np_arr) # 数据拷贝
三、数学运算深度解析
3.1 逐元素运算
a = torch.tensor([1, 2, 3], dtype=torch.float32)
b = torch.tensor([4, 5, 6], dtype=torch.float32)
# 基本运算
add = a + b # tensor([5., 7., 9.])
mul = a * b # tensor([4., 10., 18.])
pow = a ** 2 # tensor([1., 4., 9.])
# 超越函数
sin_a = torch.sin(a) # 计算正弦
log_b = torch.log(b) # 自然对数
3.2 矩阵运算专题
3.2.1 矩阵乘法家族
mat1 = torch.randn(2, 3)
mat2 = torch.randn(3, 4)
# 标准矩阵乘法
mm_result = torch.mm(mat1, mat2) # 2x4
# 批量矩阵乘法(支持广播)
batch1 = torch.randn(5, 2, 3)
batch2 = torch.randn(5, 3, 4)
bmm_result = torch.bmm(batch1, batch2) # 5x2x4
# 向量内积
vec1 = torch.randn(3)
vec2 = torch.randn(3)
dot_product = torch.dot(vec1, vec2) # 标量结果
3.2.2 矩阵分解操作
# 特征分解
A = torch.randn(3, 3)
eigenvals, eigenvecs = torch.linalg.eig(A)
# SVD分解
U, S, V = torch.svd(A)
3.3 广播机制全规则
广播三定律:
- 维度对齐:从右向左对齐
- 维度扩展:缺失维度视为1
- 单维度扩展:将size=1的维度复制扩展
复杂案例解析:
A = torch.rand(3, 1, 4, 1) # shape (3,1,4,1)
B = torch.rand( 2, 1, 5) # shape ( 2,1,5)
# 广播过程:
# Step1: 对齐维度 → (3,1,4,1) vs (1,2,1,5)
# Step2: 扩展维度 → (3,2,4,5)
result = A + B # 最终形状 (3,2,4,5)
四、形状变换高阶技巧
4.1 维度操作大全
t = torch.arange(24).reshape(2,3,4)
# 转置操作
t1 = t.permute(2,0,1) # 维度顺序变为(4,2,3)
# 轴交换
t2 = t.transpose(1, 2) # 交换1、2轴 → (2,4,3)
# 拼接与分割
cat_t = torch.cat([t, t], dim=0) # 沿dim=0拼接
split_list = torch.split(t, 2, dim=1) # 沿dim=1分割
4.2 内存连续性原理
original = torch.randn(2,3).t() # 转置后不连续
print(original.is_contiguous()) # False
# 恢复连续性方法
contiguous_tensor = original.contiguous()
内存布局对比:
原始存储(2x3):
[[0, 1, 2],
[3, 4, 5]]
转置后(3x2)内存布局:
[0, 3, 1, 4, 2, 5]
4.3 高级索引技巧
t = torch.arange(12).view(3,4)
# 布尔掩码索引
mask = t > 5
print(t[mask]) # tensor([6,7,8,9,10,11])
# 多维索引
indices = torch.tensor([0, 2])
print(t[:, indices]) # 选取第0列和第2列
五、设备管理指南
5.1 多设备协同计算
# 多GPU环境操作
if torch.cuda.device_count() > 1:
# 数据并行
tensor = tensor.to('cuda:0')
model = nn.DataParallel(model)
# 设备间数据传输
cpu_tensor = tensor.cpu()
gpu_tensor = cpu_tensor.to('cuda', non_blocking=True) # 异步传输
5.2 设备选择策略
场景 | 推荐方案 | 原理说明 |
---|---|---|
小规模数据 | CPU计算 | 避免GPU内存传输开销 |
大规模矩阵运算 | GPU计算 | 利用并行计算优势 |
多设备流水线 | 使用pin_memory | 加速CPU到GPU的数据传输 |
六、性能优化实战
6.1 原地操作加速
x = torch.randn(3,3)
y = torch.randn(3,3)
# 非原地操作(内存开销大)
x = x + y # 分配新内存
# 原地操作(节省内存)
x.add_(y) # 后缀_表示原地操作
6.2 自动混合精度
scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
output = model(input)
loss = loss_fn(output, target)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
七、综合应用案例
7.1 图像处理流水线
# 加载图像为NumPy数组
image_np = np.random.rand(256,256,3)
# 转换为张量并预处理
image_tensor = torch.from_numpy(image_np).permute(2,0,1) # HWC→CHW
image_tensor = image_tensor.unsqueeze(0) # 添加batch维度
image_tensor = image_tensor.to('cuda')
# 应用卷积滤波器
conv = torch.nn.Conv2d(3, 16, kernel_size=3)
output = conv(image_tensor)
7.2 神经网络计算示例
# 定义全连接层
W = torch.randn(784, 256, requires_grad=True)
b = torch.zeros(256, requires_grad=True)
# 前向传播
x = torch.randn(32, 784) # batch_size=32
z = torch.matmul(x, W) + b
a = torch.relu(z)
# 计算损失
loss = a.sum()
loss.backward() # 自动计算梯度
八、调试与错误排查
8.1 常见错误类型
-
形状不匹配:矩阵乘法时维度未对齐
# 错误案例 torch.mm(torch.randn(2,3), torch.randn(2,3)) # 应改为3x2
-
设备不一致:张量位于不同设备
# 解决方案 tensor = tensor.to('cuda')
-
梯度丢失:未设置requires_grad=True
param = torch.randn(3,3, requires_grad=True)
8.2 调试工具推荐
# 梯度检查
print(tensor.requires_grad) # 查看梯度状态
# 设备检查
print(tensor.device) # 确认设备位置
# 数值分析
print(tensor.mean(), tensor.std()) # 统计数值特征