张量 (Tensor)
张量(Tensor)是 PyTorch 的核心数据结构,它是多维数组的泛化形式。理解张量及其操作是学习 PyTorch 的第一步,也是深度学习的基础。
什么是张量?
在数学中,张量是一个描述标量、向量、矩阵在各个参考系之间变换的线性代数对象。在 PyTorch 和深度学习中,张量通常指多维数组——一种可以在 GPU 上高效计算、支持自动微分的数据结构。
张量的维度
张量按维度分类:
| 维度 | 数学名称 | 示例 | 常见用途 |
|---|---|---|---|
| 0 维 | 标量 (Scalar) | tensor(3.14) | 损失值、偏置 |
| 1 维 | 向量 (Vector) | tensor([1, 2, 3]) | 特征向量、偏置向量 |
| 2 维 | 矩阵 (Matrix) | tensor([[1,2],[3,4]]) | 权重矩阵、灰度图像 |
| 3 维 | 3D 张量 | 形状 (C, H, W) | RGB 图像 |
| 4 维 | 4D 张量 | 形状 (N, C, H, W) | 批量图像 |
| N 维 | N 维张量 | ... | 视频、高维数据 |
张量 vs NumPy 数组
PyTorch 张量与 NumPy 数组非常相似,但有两个关键区别:
- GPU 加速:张量可以在 GPU 上运行,利用并行计算能力大幅提升速度
- 自动微分:张量支持自动计算梯度(
requires_grad),是深度学习训练的基础
此外,张量与 NumPy 数组可以共享底层内存,无需复制数据即可相互转换。
import torch
import numpy as np
# NumPy 数组
np_array = np.array([1, 2, 3, 4])
# 转换为 PyTorch 张量(共享内存)
tensor = torch.from_numpy(np_array)
print(f"PyTorch 张量: {tensor}")
# 修改 NumPy 数组会影响张量
np_array[0] = 999
print(f"修改后张量: {tensor}") # tensor([999, 2, 3, 4])
创建张量
PyTorch 提供了多种创建张量的方法,可以根据不同场景选择。
从 Python 数据创建
最直接的方式是使用 torch.tensor() 从 Python 列表或元组创建:
import torch
# 从列表创建
data = [[1, 2], [3, 4]]
x = torch.tensor(data)
print(x)
# tensor([[1, 2],
# [3, 4]])
# 指定数据类型
x_float = torch.tensor(data, dtype=torch.float32)
print(x_float.dtype) # torch.float32
# 强制指定设备
x_gpu = torch.tensor(data, device='cuda:0')
print(x_gpu.device) # cuda:0
torch.tensor() 会复制数据。如果希望避免复制,可以使用 torch.as_tensor():
import numpy as np
np_array = np.array([1, 2, 3])
# 复制数据
x1 = torch.tensor(np_array)
# 共享内存(修改会影响原数组)
x2 = torch.as_tensor(np_array)
np_array[0] = 999
print(x2) # tensor([999, 2, 3])
使用工厂函数创建
PyTorch 提供了多种"工厂函数"来创建特定形状和内容的张量:
import torch
# 创建未初始化张量(值不确定,仅分配内存)
empty = torch.empty(2, 3)
print(f"未初始化:\n{empty}")
# 创建全零张量
zeros = torch.zeros(2, 3)
print(f"全零:\n{zeros}")
# 创建全一张量
ones = torch.ones(2, 3)
print(f"全一:\n{ones}")
# 创建填充特定值的张量
full = torch.full((2, 3), fill_value=7)
print(f"填充7:\n{full}")
# 创建单位矩阵
eye = torch.eye(3)
print(f"单位矩阵:\n{eye}")
创建随机张量
随机张量在深度学习中非常重要,常用于初始化模型权重:
import torch
# 设置随机种子(确保可重复性)
torch.manual_seed(42)
# [0, 1) 均匀分布
rand = torch.rand(2, 3)
print(f"均匀分布:\n{rand}")
# 标准正态分布 N(0, 1)
randn = torch.randn(2, 3)
print(f"正态分布:\n{randn}")
# 随机整数 [low, high)
randint = torch.randint(0, 10, (2, 3))
print(f"随机整数:\n{randint}")
# 随机排列
perm = torch.randperm(5)
print(f"随机排列: {perm}") # 如 tensor([2, 4, 0, 1, 3])
创建序列张量
import torch
# 类似 Python range
arange = torch.arange(0, 10, 2) # [start, end), step=2
print(f"arange: {arange}") # tensor([0, 2, 4, 6, 8])
# 等间隔张量
linspace = torch.linspace(0, 1, 5) # [start, end], 5个点
print(f"linspace: {linspace}") # tensor([0.00, 0.25, 0.50, 0.75, 1.00])
# 对数间隔
logspace = torch.logspace(0, 2, 5) # 10^0 到 10^2
print(f"logspace: {logspace}") # tensor([1., 3.16, 10., 31.62, 100.])
基于现有张量创建
*_like 系列函数可以创建与现有张量形状相同的新张量:
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 相同形状的全零张量
zeros_like = torch.zeros_like(x)
print(f"zeros_like:\n{zeros_like}")
# 相同形状的全一张量
ones_like = torch.ones_like(x)
print(f"ones_like:\n{ones_like}")
# 相同形状的随机张量(可覆盖 dtype)
rand_like = torch.rand_like(x, dtype=torch.float32)
print(f"rand_like:\n{rand_like}")
# 相同形状的未初始化张量
empty_like = torch.empty_like(x)
张量属性
每个 PyTorch 张量都有几个重要属性,描述其形状、数据类型和存储设备:
import torch
x = torch.randn(3, 4, 5)
# 形状
print(f"形状: {x.shape}") # torch.Size([3, 4, 5])
print(f"形状: {x.size()}") # torch.Size([3, 4, 5])
# 维度数
print(f"维度数: {x.dim()}") # 3(也可用 x.ndim)
# 元素总数
print(f"元素总数: {x.numel()}") # 3*4*5 = 60
# 数据类型
print(f"数据类型: {x.dtype}") # torch.float32
# 存储设备
print(f"设备: {x.device}") # cpu 或 cuda:0
数据类型
PyTorch 支持多种数据类型,最常用的是 float32 和 int64:
| 类型 | 说明 | 字节数 |
|---|---|---|
torch.float32 / torch.float | 32位浮点数(默认) | 4 |
torch.float64 / torch.double | 64位浮点数 | 8 |
torch.float16 / torch.half | 16位浮点数 | 2 |
torch.bfloat16 | Brain Float16 | 2 |
torch.int8 | 8位有符号整数 | 1 |
torch.int16 / torch.short | 16位整数 | 2 |
torch.int32 / torch.int | 32位整数 | 4 |
torch.int64 / torch.long | 64位整数(默认整数) | 8 |
torch.uint8 | 8位无符号整数 | 1 |
torch.bool | 布尔类型 | 1 |
类型转换:
import torch
x = torch.tensor([1, 2, 3])
print(x.dtype) # torch.int64
# 方法1:调用类型方法
x_float = x.float() # 或 x.to(torch.float32)
x_long = x_float.long() # 或 x.to(torch.int64)
# 方法2:使用 to 方法
x_half = x.to(torch.float16)
print(x_float.dtype) # torch.float32
print(x_half.dtype) # torch.float16
索引与切片
PyTorch 张量支持与 NumPy 类似的索引和切片操作。
基本索引
import torch
x = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 访问单个元素
print(x[0, 0]) # tensor(1) - 第一行第一列
print(x[1, 2]) # tensor(6) - 第二行第三列
# 访问整行
print(x[0]) # tensor([1, 2, 3])
print(x[0, :]) # tensor([1, 2, 3])
# 访问整列
print(x[:, 0]) # tensor([1, 4, 7])
print(x[:, -1]) # tensor([3, 6, 9]) - 最后一列
切片操作
import torch
x = torch.arange(12).reshape(3, 4)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 切片: [起始:结束:步长]
print(x[0:2]) # 前两行
# tensor([[0, 1, 2, 3],
# [4, 5, 6, 7]])
print(x[:, 1:3]) # 第2-3列
# tensor([[ 1, 2],
# [ 5, 6],
# [ 9, 10]])
print(x[::2, ::2]) # 步长为2
# tensor([[0, 2],
# [8, 10]])
高级索引
import torch
x = torch.arange(12).reshape(3, 4)
# 布尔索引
mask = x > 5
print(mask)
# tensor([[False, False, False, False],
# [False, False, True, True],
# [True, True, True, True]])
print(x[mask]) # tensor([6, 7, 8, 9, 10, 11])
# 条件筛选
print(x[x > 5]) # tensor([6, 7, 8, 9, 10, 11])
# 整数索引
rows = torch.tensor([0, 2])
cols = torch.tensor([1, 3])
print(x[rows, cols]) # tensor([1, 11])
# torch.index_select
indices = torch.tensor([0, 2])
print(torch.index_select(x, dim=0, index=indices))
# tensor([[ 0, 1, 2, 3],
# [ 8, 9, 10, 11]])
修改张量
import torch
x = torch.zeros(2, 3)
# 修改单个元素
x[0, 0] = 1
print(x)
# 修改一行
x[1, :] = torch.tensor([4, 5, 6])
print(x)
# 条件修改
x[x == 0] = -1
print(x)
# scatter_ 方法(常用於 one-hot 编码)
x = torch.zeros(3, 5)
indices = torch.tensor([0, 2, 4])
x.scatter_(1, indices.unsqueeze(1), 1)
print(x)
# tensor([[1., 0., 0., 0., 0.],
# [0., 0., 1., 0., 0.],
# [0., 0., 0., 0., 1.]])
张量运算
PyTorch 提供了丰富的张量运算,涵盖数学运算、线性代数、聚合操作等。
算术运算
import torch
x = torch.tensor([1.0, 2.0, 3.0])
y = torch.tensor([4.0, 5.0, 6.0])
# 四则运算
print(x + y) # tensor([5., 7., 9.])
print(x - y) # tensor([-3., -3., -3.])
print(x * y) # tensor([4., 10., 18.]) - 逐元素乘法
print(x / y) # tensor([0.25, 0.40, 0.50])
# 幂运算
print(x ** 2) # tensor([1., 4., 9.])
print(torch.sqrt(x)) # tensor([1.00, 1.41, 1.73])
# 指数和对数
print(torch.exp(x)) # e^x
print(torch.log(x)) # ln(x)
# 整除和取余
print(torch.div(y, x, rounding_mode='floor')) # 整除
print(torch.remainder(y, x)) # 取余
矩阵运算
import torch
A = torch.tensor([[1, 2], [3, 4]], dtype=torch.float)
B = torch.tensor([[5, 6], [7, 8]], dtype=torch.float)
# 矩阵乘法
print(torch.matmul(A, B)) # 或 A @ B 或 A.mm(B)
# tensor([[19., 22.],
# [43., 50.]])
# 向量点积
v1 = torch.tensor([1., 2., 3.])
v2 = torch.tensor([4., 5., 6.])
print(torch.dot(v1, v2)) # tensor(32.)
# 批量矩阵乘法
A_batch = torch.randn(10, 3, 4)
B_batch = torch.randn(10, 4, 5)
C_batch = torch.bmm(A_batch, B_batch) # (10, 3, 5)
# 转置
print(A.T)
print(A.transpose(0, 1))
# 逆矩阵
print(torch.inverse(A))
# 行列式
print(torch.det(A)) # tensor(-2.0000)
聚合运算
聚合运算将张量缩减为标量或更低维度的张量:
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float)
# 全局聚合
print(f"求和: {torch.sum(x)}") # tensor(21.)
print(f"均值: {torch.mean(x)}") # tensor(3.5000)
print(f"最大值: {torch.max(x)}") # tensor(6.)
print(f"最小值: {torch.min(x)}") # tensor(1.)
print(f"标准差: {torch.std(x)}") # tensor(1.8708)
print(f"方差: {torch.var(x)}") # tensor(3.5000)
print(f"乘积: {torch.prod(x)}") # tensor(720.)
print(f"L2范数: {torch.norm(x)}") # tensor(9.5394)
# 沿维度聚合
print(f"按列求和: {torch.sum(x, dim=0)}") # tensor([5., 7., 9.])
print(f"按行求和: {torch.sum(x, dim=1)}") # tensor([6., 15.])
# 返回值和索引
values, indices = torch.max(x, dim=1)
print(f"最大值: {values}") # tensor([3., 6.])
print(f"索引: {indices}") # tensor([2, 2])
# argmax / argmin
print(torch.argmax(x)) # 全局最大值索引
print(torch.argmax(x, dim=1)) # 每行最大值索引
比较运算
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 逐元素比较(返回布尔张量)
print(x > 3)
# tensor([[False, False, False],
# [ True, True, True]])
print(x == 3)
# tensor([[False, False, True],
# [False, False, False]])
# 相等判断
y = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(torch.equal(x, y)) # True
print(torch.eq(x, y)) # 逐元素比较,返回布尔张量
# 条件选择
result = torch.where(x > 3, x, torch.zeros_like(x))
print(result)
# tensor([[0, 0, 0],
# [4, 5, 6]])
广播机制
当两个张量形状不同时,PyTorch 会自动进行广播(Broadcasting):
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6]]) # (2, 3)
y = torch.tensor([10, 20, 30]) # (3,)
# 广播后 y 变成 (2, 3)
print(x + y)
# tensor([[11, 22, 33],
# [14, 25, 36]])
广播规则:
- 从右向左比较维度
- 维度相等,或其中一个为 1,或维度不存在
- 缺失的维度视为 1
# 广播示例
a = torch.ones(4, 3, 2)
b = torch.rand(3, 2) # 维度匹配:(3,2) 与 (3,2)
c = torch.rand(3, 1) # 可以广播:最后一个维度为1
d = torch.rand(1, 2) # 可以广播:倒数第二维为1
print((a * b).shape) # torch.Size([4, 3, 2])
print((a * c).shape) # torch.Size([4, 3, 2])
print((a * d).shape) # torch.Size([4, 3, 2])
形状操作
深度学习中经常需要改变张量的形状。
改变形状
import torch
x = torch.arange(12)
# reshape(返回新张量,可能共享内存)
y = x.reshape(3, 4)
print(f"reshape: {y.shape}") # torch.Size([3, 4])
# view(返回视图,共享内存,要求连续)
z = x.view(2, 6)
print(f"view: {z.shape}") # torch.Size([2, 6])
# view 要求张量在内存中连续
x_t = x.reshape(3, 4).t() # 转置后不连续
# z = x_t.view(2, 6) # 报错!
z = x_t.contiguous().view(2, 6) # 正确
# 展平
x = torch.randn(2, 3, 4)
y = x.flatten() # (24,)
y = x.flatten(1) # (2, 12) - 从第1维开始展平
# 自适应展平
y = torch.flatten(x, start_dim=1)
增减维度
import torch
# unsqueeze:增加维度
x = torch.tensor([1, 2, 3]) # (3,)
y = x.unsqueeze(0) # (1, 3)
z = x.unsqueeze(1) # (3, 1)
print(y.shape) # torch.Size([1, 3])
print(z.shape) # torch.Size([3, 1])
# squeeze:移除大小为1的维度
x = torch.randn(1, 3, 1, 4)
y = x.squeeze() # (3, 4) - 移除所有大小为1的维度
z = x.squeeze(0) # (3, 1, 4) - 只移除第0维
w = x.squeeze(2) # (1, 3, 4) - 只移除第2维
# 实际应用:添加 batch 维度
image = torch.randn(3, 224, 224) # 单张图像
batch = image.unsqueeze(0) # (1, 3, 224, 224) - 批量
拼接与分割
import torch
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5, 6], [7, 8]])
# cat:拼接(不增加维度)
z = torch.cat([x, y], dim=0) # 按行拼接 -> (4, 2)
print(z)
# tensor([[1, 2],
# [3, 4],
# [5, 6],
# [7, 8]])
z = torch.cat([x, y], dim=1) # 按列拼接 -> (2, 4)
print(z)
# tensor([[1, 2, 5, 6],
# [3, 4, 7, 8]])
# stack:堆叠(增加新维度)
z = torch.stack([x, y], dim=0) # (2, 2, 2)
print(z.shape)
# split:分割
x = torch.arange(10)
a, b, c = torch.split(x, [3, 3, 4]) # 按指定大小分割
print(a, b, c) # tensor([0, 1, 2]) tensor([3, 4, 5]) tensor([6, 7, 8, 9])
# chunk:均匀分割
x = torch.arange(12).reshape(3, 4)
chunks = torch.chunk(x, 2, dim=1) # 分成2份
print(chunks[0].shape, chunks[1].shape)
转置与置换
import torch
x = torch.arange(24).reshape(2, 3, 4)
# 转置(仅适用于 2D)
x_2d = torch.arange(6).reshape(2, 3)
print(x_2d.t())
# tensor([[0, 3],
# [1, 4],
# [2, 5]])
# transpose:交换两个维度
print(x.transpose(0, 1).shape) # torch.Size([3, 2, 4])
# permute:重新排列所有维度
print(x.permute(2, 0, 1).shape) # torch.Size([4, 2, 3])
GPU 加速
GPU 是深度学习的关键硬件。PyTorch 可以轻松将张量移动到 GPU 上计算。
检查 GPU 可用性
import torch
# 检查 CUDA 是否可用
print(f"CUDA 可用: {torch.cuda.is_available()}")
# 获取 GPU 数量
print(f"GPU 数量: {torch.cuda.device_count()}")
# 获取当前 GPU
if torch.cuda.is_available():
print(f"当前 GPU: {torch.cuda.current_device()}")
print(f"GPU 名称: {torch.cuda.get_device_name(0)}")
设备管理
import torch
# 推荐方式:自动选择设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备: {device}")
# 创建张量时指定设备
x = torch.tensor([1, 2, 3], device=device)
# 或
x = torch.tensor([1, 2, 3]).to(device)
# 移动现有张量
x_cpu = torch.randn(3, 4)
x_gpu = x_cpu.to('cuda')
# 或
x_gpu = x_cpu.cuda()
x_gpu = x_cpu.to('cuda:0') # 指定 GPU 编号
# 移回 CPU
x_cpu2 = x_gpu.cpu()
x_cpu2 = x_gpu.to('cpu')
# 查看张量所在设备
print(x_cpu.device) # cpu
print(x_gpu.device) # cuda:0
GPU 计算示例
import torch
import time
# 创建大矩阵
size = 5000
a_cpu = torch.randn(size, size)
b_cpu = torch.randn(size, size)
# CPU 计算
start = time.time()
for _ in range(10):
c_cpu = torch.mm(a_cpu, b_cpu)
cpu_time = time.time() - start
print(f"CPU 时间: {cpu_time:.3f}s")
# GPU 计算
if torch.cuda.is_available():
a_gpu = a_cpu.cuda()
b_gpu = b_cpu.cuda()
# 预热
_ = torch.mm(a_gpu, b_gpu)
torch.cuda.synchronize()
start = time.time()
for _ in range(10):
c_gpu = torch.mm(a_gpu, b_gpu)
torch.cuda.synchronize() # 等待 GPU 完成
gpu_time = time.time() - start
print(f"GPU 时间: {gpu_time:.3f}s")
print(f"加速比: {cpu_time/gpu_time:.1f}x")
不同设备上的张量不能直接运算:
x = torch.tensor([1, 2]) # CPU
y = torch.tensor([1, 2], device='cuda') # GPU
# z = x + y # 错误!
z = x.cuda() + y # 正确
原地操作
以 _ 结尾的操作是原地操作(In-place Operation),直接修改张量本身:
import torch
x = torch.tensor([1.0, 2.0, 3.0])
# 非原地操作:返回新张量,原张量不变
y = x.add(1)
print(x) # tensor([1., 2., 3.])
# 原地操作:直接修改 x
x.add_(1)
print(x) # tensor([2., 3., 4.])
# 常见原地操作
x.zero_() # 置零
x.fill_(5) # 填充
x.mul_(2) # 乘法
x.div_(2) # 除法
x.scatter_() # 散射
x.copy_(y) # 复制
原地操作会丢失梯度信息,在自动求导时需谨慎使用。PyTorch 官方不推荐在需要梯度计算的场景下使用原地操作。
克隆与复制
理解张量的复制机制对于避免意外修改至关重要。
赋值 vs 克隆
import torch
# 赋值:只是创建新标签,指向同一对象
a = torch.tensor([1, 2, 3])
b = a
b[0] = 999
print(a) # tensor([999, 2, 3]) - a 也被修改了!
# clone:创建数据副本
a = torch.tensor([1, 2, 3])
b = a.clone()
b[0] = 999
print(a) # tensor([1, 2, 3]) - a 未被修改
clone 与 detach
clone() 和 detach() 的组合使用:
import torch
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
# clone():复制数据,保留梯度追踪
y = x.clone()
print(y.requires_grad) # True
# detach():分离梯度追踪,共享数据
z = x.detach()
print(z.requires_grad) # False
# detach().clone():完全不相关的副本
w = x.detach().clone()
# 常用于将张量移出计算图
内存模型
理解张量的内存模型有助于编写高效的代码。
连续性
import torch
x = torch.randn(3, 4)
# 检查是否连续
print(x.is_contiguous()) # True
# transpose 创建非连续张量
y = x.transpose(0, 1)
print(y.is_contiguous()) # False
# 使张量连续
y_cont = y.contiguous()
print(y_cont.is_contiguous()) # True
# 非连续张量无法使用 view
# y.view(12) # 报错
y_cont.view(12) # 正确
存储偏移和步长
import torch
x = torch.arange(12).reshape(3, 4)
# 存储偏移
print(f"存储偏移: {x.storage_offset()}") # 0
# 步长(每个维度移动需要的步数)
print(f"步长: {x.stride()}") # (4, 1)
# 转置后的步长
y = x.transpose(0, 1)
print(f"转置后步长: {y.stride()}") # (1, 4)
与 NumPy 互转
PyTorch 张量与 NumPy 数组可以高效互转,通常共享底层内存。
张量转 NumPy
import torch
import numpy as np
tensor = torch.randn(3, 4)
# 转换为 NumPy 数组(共享内存)
np_array = tensor.numpy()
# 修改会影响原张量
np_array[0, 0] = 999
print(tensor[0, 0]) # tensor(999.)
# GPU 张量需要先移到 CPU
if tensor.is_cuda:
np_array = tensor.cpu().numpy()
NumPy 转张量
import torch
import numpy as np
np_array = np.array([[1, 2, 3], [4, 5, 6]])
# 转换为张量(共享内存)
tensor = torch.from_numpy(np_array)
# 修改会影响原数组
tensor[0, 0] = 999
print(np_array[0, 0]) # 999
# 使用 torch.tensor() 会复制数据
tensor_copy = torch.tensor(np_array)
tensor_copy[0, 0] = 888
print(np_array[0, 0]) # 仍然是 999
常用技巧
随机种子
为了结果可复现:
import torch
import numpy as np
import random
def set_seed(seed=42):
"""设置所有随机种子"""
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
np.random.seed(seed)
random.seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
set_seed(42)
x = torch.randn(2, 3)
梯度控制
import torch
x = torch.randn(3, 4, requires_grad=True)
# 禁用梯度追踪
with torch.no_grad():
y = x * 2
print(y.requires_grad) # False
# 分离梯度
z = x.detach()
print(z.requires_grad) # False
类型转换快捷方式
import torch
x = torch.randn(3, 4)
# 快捷类型转换
x_float = x.float()
x_double = x.double()
x_half = x.half()
x_int = x.int()
x_long = x.long()
小结
本章我们系统学习了 PyTorch 张量的核心知识:
- 张量概念:多维数组的泛化,支持 GPU 加速和自动微分
- 创建张量:从数据、工厂函数、随机数、NumPy 等多种方式
- 张量属性:形状、数据类型、设备、维度数等
- 索引切片:基本索引、高级索引、布尔索引
- 张量运算:算术、矩阵、聚合、比较运算,以及广播机制
- 形状操作:reshape、view、squeeze、unsqueeze、拼接分割
- GPU 加速:设备管理、数据移动、性能对比
- 内存模型:连续性、原地操作、克隆与复制
- NumPy 互转:共享内存的高效转换
张量是 PyTorch 的基础数据结构。下一章我们将学习 PyTorch 的自动微分系统(Autograd),这是深度学习训练的核心机制。