一、PyTorch 环境准备(前置条件)
确保已完成 Anaconda 虚拟环境和 GPU 环境配置(参考前文),激活环境后安装 PyTorch:
bash
# 激活虚拟环境
conda activate ai-dev
# 安装 PyTorch(GPU 版本,自动适配 CUDA,国内镜像加速)
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia -c conda-forge
# 验证安装(终端执行 Python 代码)
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"
# 输出示例:2.2.0 + True(True 表示 GPU 可用)
二、核心模块 1:张量(Tensor)操作(PyTorch 基础)
张量是 PyTorch 的核心数据结构,类比 NumPy 数组,但支持 GPU 加速和自动求导,是模型输入、参数存储的基础。
1. 张量创建(常用方式)
bash
import torch
import numpy as np
# 1. 从 Python 列表/元组创建
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32) # 2×3 张量,float32 节省显存
print("列表创建张量:\n", tensor1, "\n形状:", tensor1.shape, "\n数据类型:", tensor1.dtype)
# 2. 从 NumPy 数组创建(共享内存,高效转换)
np_arr = np.array([[0.1, 0.2], [0.3, 0.4]])
tensor2 = torch.from_numpy(np_arr)
print("\nNumPy 转换张量:\n", tensor2, "\nNumPy 数组修改后张量变化:")
np_arr[0,0] = 10.0 # 修改 NumPy 数组
print(tensor2) # 张量同步变化(如需独立,用 tensor2 = torch.tensor(np_arr))
# 3. 创建特殊张量(实战高频)
tensor3 = torch.zeros((3, 4)) # 3×4 全0张量
tensor4 = torch.ones((2, 2, 3)) # 2×2×3 全1张量(3维,适配批量数据)
tensor5 = torch.randn((3, 3)) # 3×3 正态分布张量(均值0,方差1,模型初始化常用)
tensor6 = torch.arange(0, 10, step=2) # 0-10 步长2:[0,2,4,6,8]
print("\n全0张量:\n", tensor3, "\n3维全1张量:\n", tensor4, "\n正态分布张量:\n", tensor5)
2. 张量核心操作(实战必备)
bash
# 1. 形状操作(适配模型输入输出维度)
tensor = torch.randn(2, 3) # 2×3 张量
print("原始张量:\n", tensor)
# 重塑形状(需保持元素总数一致)
tensor_reshape = tensor.reshape(3, 2) # 3×2
# 展平(模型全连接层输入常用)
tensor_flatten = tensor.flatten() # 1维张量:[x1,x2,x3,x4,x5,x6]
# 增加维度(批量维度,实战高频:(C,H,W)→(1,C,H,W))
tensor_unsqueeze = tensor.unsqueeze(0) # 1×2×3(第0维增加批量维度)
print("\n重塑后:\n", tensor_reshape, "\n展平后:\n", tensor_flatten, "\n增加批量维度后:\n", tensor_unsqueeze.shape)
# 2. 索引与切片(数据筛选)
tensor = torch.tensor([[1,2,3],[4,5,6],[7,8,9]], dtype=torch.float32)
# 取第0行
row0 = tensor[0, :]
# 取第1列
col1 = tensor[:, 1]
# 取前2行、后2列(切片左闭右开)
slice_tensor = tensor[:2, 1:]
print("\n第0行:", row0, "\n第1列:", col1, "\n切片结果:\n", slice_tensor)
# 3. 数学运算(模型计算核心)
a = torch.tensor([1, 2, 3], dtype=torch.float32)
b = torch.tensor([4, 5, 6], dtype=torch.float32)
# 元素-wise 运算
add = a + b # 等价于 torch.add(a,b)
mul = a * b # 等价于 torch.mul(a,b)
pow = a ** 2 # 平方
# 矩阵乘法(模型权重与特征计算)
mat_a = torch.randn(2, 3)
mat_b = torch.randn(3, 4)
mat_mul = torch.matmul(mat_a, mat_b) # 2×4 矩阵乘法,等价于 mat_a @ mat_b
print("\n元素加法:", add, "\n元素乘法:", mul, "\n矩阵乘法形状:", mat_mul.shape)
# 4. 设备迁移(CPU ↔ GPU,加速关键)
tensor_cpu = torch.randn(3, 3)
if torch.cuda.is_available():
tensor_gpu = tensor_cpu.cuda() # 迁移到 GPU
tensor_back_cpu = tensor_gpu.cpu() # 迁回 CPU
print("\nGPU 张量设备:", tensor_gpu.device, "\n迁回 CPU 后:", tensor_back_cpu.device)
else:
print("\nGPU 不可用,使用 CPU 训练")
# 5. 自动求导(模型训练核心)
x = torch.tensor([2.0], requires_grad=True) # 开启自动求导
y = x ** 2 + 3 * x + 1 # 计算图:y = x² + 3x +1
y.backward() # 反向传播求导
print("\nx 的梯度(dy/dx = 2x+3,x=2 时为7):", x.grad) # 输出:tensor([7.])
3. 张量与 NumPy 互转(数据处理兼容)
bash
# 张量 → NumPy
tensor = torch.tensor([[1,2],[3,4]], dtype=torch.float32)
np_arr = tensor.numpy()
print("张量转 NumPy:\n", np_arr, "\n类型:", type(np_arr))
# NumPy → 张量(独立内存,避免同步修改)
np_arr2 = np.array([[5,6],[7,8]])
tensor2 = torch.tensor(np_arr2) # 独立内存,修改 np_arr2 不影响 tensor2
np_arr2[0,0] = 100
print("\nNumPy 转张量(独立内存):\n", tensor2)
三、核心模块 2:数据加载器(DataLoader)(实战输入核心)
PyTorch 提供 torch.utils.data 模块,用于批量加载、预处理数据,适配大规模训练场景,核心是 Dataset(数据集定义)和 DataLoader(批量加载)。
1. 自定义数据集(Dataset 类)
以 "模拟回归任务数据" 为例,自定义数据集类(实战中可替换为 CSV / 图片数据):
bash
import torch
from torch.utils.data import Dataset, DataLoader
# 自定义数据集类(必须继承 Dataset,重写 __len__ 和 __getitem__)
class MyRegressionDataset(Dataset):
def __init__(self, data_size=1000, transform=None):
"""
Args:
data_size: 数据集大小
transform: 数据预处理函数(可选)
"""
# 生成模拟数据:y = 2x1 + 3x2 + 0.5(带噪声)
self.x = torch.randn(data_size, 2) # 特征:x1, x2(1000个样本)
self.y = 2 * self.x[:, 0] + 3 * self.x[:, 1] + 0.5 + torch.randn(data_size) * 0.1 # 标签(含噪声)
self.transform = transform
def __len__(self):
# 返回数据集总样本数(DataLoader 需用到)
return len(self.x)
def __getitem__(self, idx):
# 根据索引返回单个样本((特征, 标签))
sample = (self.x[idx], self.y[idx])
if self.transform:
sample = self.transform(sample)
return sample
# 实例化数据集
dataset = MyRegressionDataset(data_size=1000)
print("数据集大小:", len(dataset))
print("第0个样本(特征, 标签):", dataset[0])
2. 批量加载数据(DataLoader 类)
DataLoader 封装数据集,支持批量加载、打乱数据、多线程读取,是训练时的核心数据输入工具:
bash
# 定义 DataLoader
dataloader = DataLoader(
dataset,
batch_size=32, # 每次加载32个样本(批量大小,根据GPU显存调整)
shuffle=True, # 训练时打乱数据(提升泛化能力)
num_workers=2 # 多线程读取(加速,根据CPU核心数调整)
)
# 迭代 DataLoader(训练时循环读取)
for batch_idx, (batch_x, batch_y) in enumerate(dataloader):
print(f"第 {batch_idx+1} 个批次:")
print(f"批量特征形状:{batch_x.shape}(32个样本,每个2个特征)")
print(f"批量标签形状:{batch_y.shape}(32个标签)")
# 模拟训练步骤(后续模型搭建后替换)
if batch_idx == 2: # 仅打印前3个批次
break
3. 数据预处理(Transform)
通过自定义 Transform 对数据进行标准化、归一化等预处理(实战必备,提升模型训练稳定性):
bash
# 定义预处理函数(标准化:(x - 均值) / 标准差)
class StandardizeTransform:
def __init__(self, mean, std):
self.mean = mean
self.std = std
def __call__(self, sample):
x, y = sample
x = (x - self.mean) / self.std # 特征标准化
return (x, y)
# 计算特征均值和标准差(基于整个数据集)
feature_mean = dataset.x.mean(dim=0) # 按列(特征维度)计算均值
feature_std = dataset.x.std(dim=0) # 按列计算标准差
print("特征均值:", feature_mean)
print("特征标准差:", feature_std)
# 实例化预处理类,创建带预处理的数据集
transformed_dataset = MyRegressionDataset(
data_size=1000,
transform=StandardizeTransform(mean=feature_mean, std=feature_std)
)
# 带预处理的 DataLoader
transformed_dataloader = DataLoader(
transformed_dataset,
batch_size=32,
shuffle=True,
num_workers=2
)
# 验证预处理效果
for batch_x, batch_y in transformed_dataloader:
print("预处理后批量特征均值(接近0):", batch_x.mean(dim=0))
print("预处理后批量特征标准差(接近1):", batch_x.std(dim=0))
break
四、核心模块 3:模型搭建(nn.Module 类)
PyTorch 用 torch.nn 模块构建神经网络,所有模型需继承 nn.Module,重写 __init__(定义层)和 forward(前向传播,计算输出)。
1. 搭建简单回归模型(全连接网络)
以 "预测上述自定义数据集标签" 为例,搭建 2 层全连接网络:
bash
import torch
import torch.nn as nn
# 定义回归模型(继承 nn.Module)
class SimpleRegressionModel(nn.Module):
def __init__(self, input_dim=2, hidden_dim=16, output_dim=1):
"""
Args:
input_dim: 输入特征维度(本文数据集为2)
hidden_dim: 隐藏层神经元数(可调参数)
output_dim: 输出维度(回归任务为1)
"""
super(SimpleRegressionModel, self).__init__() # 必须调用父类初始化
# 定义网络层(nn.Linear 为全连接层)
self.fc1 = nn.Linear(input_dim, hidden_dim) # 输入层→隐藏层:2→16
self.relu = nn.ReLU() # 激活函数(引入非线性,提升模型表达能力)
self.fc2 = nn.Linear(hidden_dim, output_dim) # 隐藏层→输出层:16→1
def forward(self, x):
"""前向传播(模型计算逻辑,必须重写)"""
x = self.fc1(x) # 第一层全连接
x = self.relu(x) # 激活函数
output = self.fc2(x) # 第二层全连接(输出预测值)
return output
# 实例化模型
model = SimpleRegressionModel(input_dim=2, hidden_dim=16, output_dim=1)
print("回归模型结构:")
print(model) # 打印模型层结构
# 验证模型输出(输入批量特征,查看输出形状)
batch_x, _ = next(iter(transformed_dataloader)) # 从 DataLoader 取一个批次特征
model_output = model(batch_x)
print(f"\n模型输入形状:{batch_x.shape}")
print(f"模型输出形状:{model_output.shape}") # 输出:torch.Size([32, 1])(32个样本,每个1个预测值)
2. 搭建简单分类模型(CNN 示例)
以 "MNIST 手写数字分类" 为例,搭建简单 CNN 模型(拓展实战,理解卷积层用法):
bash
class SimpleCNN(nn.Module):
def __init__(self, input_channels=1, num_classes=10):
super(SimpleCNN, self).__init__()
# 卷积层(提取空间特征)
self.conv1 = nn.Conv2d(input_channels, 32, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2) # 下采样,减少参数
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
# 全连接层(分类)
self.fc1 = nn.Linear(64 * 7 * 7, 128) # MNIST图片28×28,经过两次池化后7×7
self.fc2 = nn.Linear(128, num_classes)
def forward(self, x):
# 卷积→激活→池化
x = self.conv1(x)
x = self.relu(x)
x = self.pool(x) # 输出:(batch_size, 32, 14, 14)
# 第二次卷积→激活→池化
x = self.conv2(x)
x = self.relu(x)
x = self.pool(x) # 输出:(batch_size, 64, 7, 7)
# 展平(卷积层输出→全连接层输入)
x = x.view(-1, 64 * 7 * 7) # 输出:(batch_size, 64*7*7)
# 全连接层分类
x = self.fc1(x)
x = self.relu(x)
output = self.fc2(x) # 输出:(batch_size, 10)(10个类别概率)
return output
# 实例化 CNN 模型
cnn_model = SimpleCNN(input_channels=1, num_classes=10)
print("CNN 模型结构:")
print(cnn_model)
# 验证输入输出(MNIST 图片形状:(batch_size, 1, 28, 28))
dummy_input = torch.randn(32, 1, 28, 28) # 模拟32个MNIST样本
cnn_output = cnn_model(dummy_input)
print(f"\nCNN 输入形状:{dummy_input.shape}")
print(f"CNN 输出形状:{cnn_output.shape}") # 输出:torch.Size([32, 10])
3. 模型参数与设备迁移
bash
# 查看模型参数(训练时需优化的权重/偏置)
print("模型参数列表:")
for name, param in model.named_parameters():
print(f"参数名:{name},形状:{param.shape},是否需要梯度:{param.requires_grad}")
# 模型迁移到 GPU(加速训练)
if torch.cuda.is_available():
model = model.cuda() # 模型权重迁移到 GPU
batch_x = batch_x.cuda() # 输入数据也需迁移到 GPU
model_output = model(batch_x)
print(f"\nGPU 训练:模型设备={next(model.parameters()).device},输出设备={model_output.device}")
五、实战总结与后续拓展
1. 核心要点回顾
- 张量:PyTorch 基础数据结构,支持 GPU 加速和自动求导,核心操作需掌握 "形状调整、设备迁移、自动求导";
DataLoader:批量加载数据的核心工具,需配合Dataset自定义数据集,预处理(标准化)是提升模型效果的关键;- 模型搭建:继承
nn.Module,重写__init__(定义层)和forward(前向传播),激活函数(ReLU)和池化层(CNN)是提升模型能力的重要组件。
2. 后续实战拓展
- 模型训练:结合损失函数(nn.MSELoss 回归 /
nn.CrossEntropyLoss分类)和优化器(torch.optim.Adam),实现完整训练循环; - 数据加载进阶:加载真实数据集(如 CSV 表格数据、图片数据),使用
torchvision.datasets加载公开数据集(MNIST、CIFAR-10); - 模型保存与加载:训练完成后保存模型权重(
torch.save(model.state_dict(), "model.pth")),后续复用训练结果。