深度学习-PyTorch基本使用
一、PyTorch 概述与安装
PyTorch 是 Facebook 开发的深度学习框架,使用动态计算图机制,特别适合研究和原型开发。
安装命令
# 使用清华镜像源加速安装
pip install torch===1.10.0 torchvision===0.11.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
解释:
torch
:核心库torchvision
:计算机视觉扩展库-i
参数指定镜像源加速下载- 版本号确保环境一致性
二、张量基础操作
1. 张量创建
import torch
import numpy as np# 创建标量(0维张量)
scalar = torch.tensor(5)
print("标量:", scalar, "形状:", scalar.shape)# 从列表创建张量
list_tensor = torch.tensor([[1, 2], [3, 4]])
print("从列表创建:\n", list_tensor)# 从NumPy数组创建
np_array = np.array([[5, 6], [7, 8]])
np_tensor = torch.tensor(np_array)
print("从NumPy创建:\n", np_tensor)# 创建全零张量
zeros = torch.zeros(2, 3)
print("全零张量:\n", zeros)# 创建全一张量
ones = torch.ones(2, 3)
print("全一张量:\n", ones)# 创建随机张量
torch.manual_seed(42) # 固定随机种子
rand_tensor = torch.rand(2, 3)
print("随机张量:\n", rand_tensor)# 创建等差数列
range_tensor = torch.arange(0, 10, 2)
print("等差数列:", range_tensor)# 创建等间距数列
linspace_tensor = torch.linspace(0, 1, 5)
print("等间距数列:", linspace_tensor)
代码解释:
torch.tensor()
是创建张量的主要方法shape
属性查看张量维度torch.zeros()/ones()
创建特定形状的填充张量torch.manual_seed()
确保随机结果可复现arange()
生成固定步长的序列linspace()
生成固定点数的序列
2. 张量属性
# 创建示例张量
tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]])print("数据类型:", tensor.dtype) # torch.float32
print("设备位置:", tensor.device) # cpu
print("维度形状:", tensor.shape) # torch.Size([2, 2])
print("维度数量:", tensor.ndim) # 2
print("元素总数:", tensor.numel()) # 4
属性说明:
dtype
:数据类型(float32, int64等)device
:存储位置(CPU/GPU)shape
:维度大小元组ndim
:维度数量numel
:元素总数
三、张量运算与操作
1. 基本数学运算
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])# 加法
add_result = a + b # 等价于 torch.add(a, b)
print("加法:\n", add_result)# 减法
sub_result = a - b
print("减法:\n", sub_result)# 点乘(逐元素相乘)
mul_result = a * b # 等价于 torch.mul(a, b)
print("点乘:\n", mul_result)# 矩阵乘法
matmul_result = a @ b # 等价于 torch.matmul(a, b)
print("矩阵乘法:\n", matmul_result)# 指数运算
exp_result = torch.exp(a.float())
print("指数运算:\n", exp_result)# 对数运算
log_result = torch.log(a.float())
print("自然对数:\n", log_result)
运算说明:
+
、-
、*
执行逐元素操作@
执行矩阵乘法- 数学函数需注意数据类型(如log需要浮点数)
2. 统计运算
data = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])# 全局平均值
mean_all = data.mean()
print("全局平均:", mean_all.item())# 按列求平均
mean_col = data.mean(dim=0)
print("列平均:", mean_col)# 按行求和
sum_row = data.sum(dim=1)
print("行求和:", sum_row)# 最大值及其位置
max_val, max_idx = data.max()
print("最大值:", max_val.item(), "位置:", max_idx.item())# 标准差
std_dev = data.std()
print("标准差:", std_dev.item())
维度参数:
dim=0
:按列操作dim=1
:按行操作- 不指定dim:全局操作
3. 索引与切片
tensor = torch.tensor([[1, 2, 3],[4, 5, 6],[7, 8, 9]])# 获取单个元素
element = tensor[1, 2] # 第2行第3列
print("单个元素:", element.item())# 切片操作
row_slice = tensor[1, :] # 第2行所有列
col_slice = tensor[:, 1] # 所有行第2列
sub_tensor = tensor[0:2, 1:3] # 第1-2行,2-3列# 高级索引
indices = torch.tensor([0, 2])
selected = tensor[:, indices] # 所有行的第1和第3列# 布尔索引
mask = tensor > 5
filtered = tensor[mask] # 所有大于5的元素
索引技巧:
- Python式切片语法
[start:stop:step]
- 逗号分隔不同维度
- 布尔索引用于条件筛选
4. 形状操作
# 原始张量
tensor = torch.arange(1, 7) # [1,2,3,4,5,6]
print("原始形状:", tensor.shape)# 改变形状
reshaped = tensor.reshape(2, 3) # 2×3矩阵
print("reshape后:\n", reshaped)# 转置操作
transposed = reshaped.T # 3×2矩阵
print("转置后:\n", transposed)# 增加维度
unsqueezed = tensor.unsqueeze(0) # 添加批次维度
print("增加维度后:", unsqueezed.shape)# 减少维度
squeezed = unsqueezed.squeeze()
print("减少维度后:", squeezed.shape)# 维度重排
data_3d = torch.rand(2, 3, 4) # 批次×行×列
permuted = data_3d.permute(1, 2, 0) # 行×列×批次
print("重排后形状:", permuted.shape)
形状操作要点:
reshape
不改变数据只改变视图T
适用于2D矩阵转置unsqueeze
/squeeze
增减维度permute
灵活重排维度顺序
5. 张量拼接
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])# 垂直拼接 (沿行方向)
v_stack = torch.cat([a, b], dim=0)
print("垂直拼接:\n", v_stack)# 水平拼接 (沿列方向)
h_stack = torch.cat([a, b], dim=1)
print("水平拼接:\n", h_stack)# 深度拼接 (增加新维度)
d_stack = torch.stack([a, b])
print("深度拼接:\n", d_stack)
拼接区别:
cat
:在现有维度上扩展stack
:创建新维度组合张量
四、自动微分机制
PyTorch 的核心特性是自动微分(autograd),用于神经网络梯度计算。
1. 基本微分
# 创建需要计算梯度的张量
x = torch.tensor(2.0, requires_grad=True)
w = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)# 构建计算图
y = w * x + b # 线性方程
z = y**2 # 二次函数# 计算梯度
z.backward()# 查看梯度
print("dz/dx:", x.grad) # 2*w*x*2 = 2 * 3 * 2 * 2 = 24
print("dz/dw:", w.grad) # 2*x*x*2 = 2 * 2 * 2 * 2 = 16
print("dz/db:", b.grad) # 2*y = 2*(6+1) = 14
关键概念:
requires_grad=True
:标记需要计算梯度的变量.backward()
:反向传播计算梯度.grad
:存储梯度值- 梯度计算基于链式法则
2. 梯度清零
# 创建参数
param = torch.tensor([1.0, 2.0], requires_grad=True)# 第一次计算
output = (param ** 2).sum()
output.backward()
print("第一次梯度:", param.grad)# 第二次计算(不清零)
output2 = (param ** 3).sum()
output2.backward()
print("第二次梯度(累积):", param.grad)# 手动清零梯度
param.grad.zero_()# 第三次计算
output3 = (param ** 4).sum()
output3.backward()
print("第三次梯度(清零后):", param.grad)
梯度管理:
- 梯度默认会累积
.zero_()
清零梯度(注意下划线表示原地操作)- 训练循环中每次迭代前需要清零梯度
五、线性回归完整案例
1. 数据准备
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression# 生成数据集
X, y, coef = make_regression(n_samples=100, # 样本数量n_features=1, # 特征数量noise=8, # 噪声大小bias=4.0, # 偏置项random_state=42 # 随机种子
)# 转换为PyTorch张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)# 可视化数据
plt.scatter(X, y, alpha=0.6)
plt.title("回归数据集")
plt.xlabel("特征值")
plt.ylabel("目标值")
plt.grid(True)
plt.show()
数据说明:
- 生成100个样本的线性数据集
- 添加噪声模拟真实情况
- 可视化帮助理解数据分布
2. 模型定义
class LinearRegressionModel(torch.nn.Module):def __init__(self):super().__init__()# 单输入单输出的线性层self.linear = torch.nn.Linear(1, 1)def forward(self, x):# 定义前向传播return self.linear(x)# 实例化模型
model = LinearRegressionModel()# 查看模型参数
print("初始权重:", model.linear.weight)
print("初始偏置:", model.linear.bias)
模型结构:
- 继承
nn.Module
基类 __init__
定义网络层forward
定义数据流向- 线性层自动初始化参数
3. 训练配置
# 损失函数 - 均方误差
loss_fn = torch.nn.MSELoss()# 优化器 - 随机梯度下降
optimizer = torch.optim.SGD(model.parameters(), # 要优化的参数lr=0.01, # 学习率momentum=0.9 # 动量项
)# 训练轮数
num_epochs = 200
训练组件:
MSELoss
:回归任务常用损失函数SGD
:基础优化器lr
:控制参数更新步长momentum
:加速收敛,减少震荡
4. 训练循环
# 存储损失历史
loss_history = []for epoch in range(num_epochs):# 前向传播predictions = model(X_tensor)# 计算损失loss = loss_fn(predictions, y_tensor)# 反向传播optimizer.zero_grad() # 清零梯度loss.backward() # 计算梯度optimizer.step() # 更新参数# 记录损失loss_history.append(loss.item())# 每20轮打印进度if (epoch+1) % 20 == 0:print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')# 绘制损失曲线
plt.plot(loss_history)
plt.title("训练损失曲线")
plt.xlabel("训练轮次")
plt.ylabel("MSE损失")
plt.grid(True)
plt.show()
训练步骤:
- 前向传播计算预测值
- 计算预测值与真实值的损失
- 清零历史梯度
- 反向传播计算新梯度
- 优化器更新参数
- 记录损失观察收敛情况
5. 结果评估
# 获取最终参数
final_weight = model.linear.weight.item()
final_bias = model.linear.bias.item()
print(f"训练结果: y = {final_weight:.2f}x + {final_bias:.2f}")# 可视化拟合直线
plt.scatter(X, y, alpha=0.6, label='数据点')
plt.plot(X, final_weight * X + final_bias, 'r-', linewidth=3, label='拟合直线')# 添加真实关系线(仅演示时可用)
real_slope = coef
real_intercept = 4.0
plt.plot(X, real_slope * X + real_intercept, 'g--', label='真实关系')plt.title("线性回归结果")
plt.xlabel("特征值")
plt.ylabel("目标值")
plt.legend()
plt.grid(True)
plt.show()# 模型预测
test_value = torch.tensor([[0.5]], dtype=torch.float32)
prediction = model(test_value)
print(f"特征值 0.5 的预测结果: {prediction.item():.2f}")
结果分析:
- 对比拟合直线与真实关系
- 预测新数据点
- 评估模型性能
- 在实际应用中,应使用测试集评估
六、关键概念总结
1. 张量核心概念
- 张量:PyTorch 的基本数据结构,类似 NumPy 数组
- 设备:数据可存储在 CPU 或 GPU 上(
.to(device)
) - 梯度:
requires_grad=True
启用自动微分 - 视图:多数操作不复制数据,只创建新视图
2. 神经网络组件
- nn.Module:所有模型的基类
- 层(Layer):如 Linear, Conv2d, LSTM
- 损失函数:如 MSE, CrossEntropy
- 优化器:如 SGD, Adam, RMSprop
3. 训练流程
- 数据准备 → 2. 模型定义 → 3. 损失函数选择
- 优化器配置 → 5. 训练循环 → 6. 模型评估
4. 最佳实践
- 使用
torch.no_grad()
上下文禁用梯度计算 - 使用
DataLoader
批量加载数据 - 定期保存模型检查点(
torch.save()
) - 使用 GPU 加速(
model.to('cuda')
)