前言
深度学习作为机器学习的一个子集,也是现在的最火的方向,它以神经网络为基础,通过一个一个神经元结点来提取数据之间的特征,具有不可解释性,所以也被大家称为"黑盒模型",被广泛应用于NLP,CV,推荐系统之中。
PyTorch框架简介
PyTorch一个基于Python语言的深度学习框架,它将数据封装成张量(Tensor)来进行处理。
PyTorch提供了灵活且高效的工具,用于构建、训练和部署机器学习和深度学习模型。
PyTorch广泛应用于学术研究和工业界,特别是在计算机视觉、自然语言处理、强化学习等领域。
下载链接:
cmd
pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple
张量基础
1. 什么是张量(Tensor)
PyTorch 中的张量就是元素为同一种数据类型的多维矩阵。类似于 NumPy 数组,但支持 GPU 加速。
- 0维:标量
- 1维:向量
- 2维:矩阵
- 多维:高维张量
2. 张量的创建
python
import torch
# 1. torch.tensor() - 根据指定数据创建张量
data = torch.tensor(10) # 标量
data = torch.tensor([[10., 20.], [40., 50.]]) # 列表
# 2. torch.Tensor() - 根据形状创建张量(未初始化)
data = torch.Tensor(2, 3) # 2行3列,默认float32
# 3. 创建指定类型的张量
data = torch.IntTensor(2, 3) # int32
data = torch.FloatTensor(2, 3) # float32
data = torch.LongTensor(2, 3) # int64
3. 线性与随机张量
python
# 线性张量
data = torch.arange(0, 10, 2) # [0, 2, 4, 6, 8],步长为2
data = torch.linspace(0, 11, 10) # 均匀分布,包含首尾
# 随机张量
data = torch.rand(2, 3) # 0~1均匀分布
data = torch.randn(2, 3) # 标准正态分布 N(0,1)
data = torch.randint(0, 10, (2, 3)) # 整数随机张量
# 随机种子
torch.manual_seed(100) # 设置随机种子
print(torch.initial_seed()) # 查看随机种子
4. 0、1、指定值张量
python
# 全0 / 全1张量
data = torch.zeros(2, 3)
data = torch.ones(2, 3)
data = torch.zeros_like(data) # 根据形状创建
data = torch.ones_like(data)
# 全指定值张量
data = torch.full((2, 3), 10) # 全部填充10
data = torch.full_like(data, 20)
张量类型转换
python
# 方式1:使用 .type()
data = torch.full([2, 3], 10)
data = data.type(torch.FloatTensor) # 转float32
data = data.type(torch.DoubleTensor) # 转float64
data = data.type(torch.IntTensor) # 转int32
# 方式2:使用转换方法
data = data.float() # float32
data = data.double() # float64
data = data.int() # int32
data = data.long() # int64
data = data.half() # float16
张量与 NumPy 互转
python
import numpy as np
# 张量 → NumPy
data_tensor = torch.tensor([2, 3, 4])
data_numpy = data_tensor.numpy() # 共享内存!
data_numpy = data_tensor.numpy().copy() # 不共享内存
# NumPy → 张量
data_numpy = np.array([2, 3, 4])
data_tensor = torch.from_numpy(data_numpy) # 共享内存
data_tensor = torch.tensor(data_numpy) # 不共享内存
# 标量张量提取值
data = torch.tensor(30)
print(data.item()) # 30
张量基本运算
1. 四则运算
python
data = torch.randint(0, 10, [2, 3])
# 不修改原数据
new_data = data.add(10) # data + 10
new_data = data.sub(10) # data - 10
new_data = data.mul(10) # data * 10
new_data = data.div(10) # data / 10
new_data = data.neg() # -data
# 就地修改(带下划线)
data.add_(10) # data += 10,直接修改原数据
2. 逐点乘法(Hadamard积)
python
data1 = torch.tensor([[1, 2], [3, 4]])
data2 = torch.tensor([[5, 6], [7, 8]])
data = torch.mul(data1, data2) # 方式1
data = data1 * data2 # 方式2
# 结果: tensor([[ 5, 12], [21, 32]])
3. 矩阵乘法
python
data1 = torch.tensor([[1, 2], [3, 4], [5, 6]]) # (3, 2)
data2 = torch.tensor([[5, 6], [7, 8]]) # (2, 2)
data = data1 @ data2 # 运算符@
data = torch.matmul(data1, data2) # 函数
# 结果: (3, 2) @ (2, 2) = (3, 2)
# tensor([[19, 22], [43, 50], [67, 78]])
4. 常见数学函数
python
data = torch.randint(0, 10, [2, 3], dtype=torch.float64)
data.mean() # 均值
data.mean(dim=0) # 按列求均值
data.mean(dim=1) # 按行求均值
data.sum() # 求和
data.sqrt() # 平方根
torch.pow(data, 2) # 幂运算
data.exp() # 指数运算 e^n
data.log() # 对数运算(自然对数)
data.log2()
data.log10()
张量索引操作
python
data = torch.randint(0, 10, [4, 5])
# 简单行列索引
data[0] # 第1行所有元素
data[:, 0] # 第1列所有元素
# 列表索引
data[[0, 1], [1, 2]] # (0,1)和(1,2)位置元素
data[[[0], [1]], [1, 2]] # 广播机制
# 范围索引
data[:3, :2] # 前3行前2列
data[2:, :2] # 第3行到最后的前2列
# 布尔索引
data[data[:, 2] > 5, :] # 第3列>5的整行
data[:, data[1, :] > 5] # 第2行>5的整列
# 多维索引(以3D张量为例)
data = torch.randint(0, 10, [3, 4, 5])
data[0, :, :] # 0轴第1个数据
data[:, 0, :] # 1轴第1个数据
data[:, :, 0] # 2轴第1个数据
张量形状操作
1. reshape 与 flatten
python
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
new_data = data.reshape(1, 6) # 改变形状
new_data = data.reshape(-1, 1) # -1自动推断
data.flatten() # 展平为1维
2. squeeze 与 unsqueeze
python
mydata = torch.tensor([1, 2, 3, 4, 5]) # (5,)
mydata2 = mydata.unsqueeze(dim=0) # (1, 5)
mydata3 = mydata.unsqueeze(dim=1) # (5, 1)
mydata4 = mydata.unsqueeze(dim=-1) # (5, 1)
mydata5 = mydata4.squeeze() # (5,),压缩维度
3. transpose 与 permute
python
data = torch.randint(0, 10, [3, 4, 5])
# 交换维度
mydata = torch.transpose(data, 1, 2) # (3, 5, 4)
# 一次交换多个维度
mydata = torch.permute(data, [1, 2, 0]) # (4, 5, 3)
mydata = data.permute(1, 2, 0)
4. view 与 contiguous
python
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
# view要求张量必须连续
mydata = data.view(3, 2) # (3, 2)
mydata = data.view(-1, 1) # 自动推断
# 非连续张量需先转连续
mydata3 = torch.transpose(data, 0, 1)
mydata4 = mydata3.contiguous().view(2, 3)
张量拼接操作
1. torch.cat()
python
data1 = torch.randint(0, 10, [1, 2, 3])
data2 = torch.randint(0, 10, [1, 2, 3])
# 按维度拼接(不增加新维度)
new_data = torch.cat([data1, data2], dim=0) # (2, 2, 3)
new_data = torch.cat([data1, data2], dim=1) # (1, 4, 3)
new_data = torch.cat([data1, data2], dim=2) # (1, 2, 6)
2. torch.stack()
python
data1 = torch.randint(0, 10, [2, 3])
data2 = torch.randint(0, 10, [2, 3])
# 在新维度上拼接(增加新维度)
new_data = torch.stack([data1, data2], dim=0) # (2, 2, 3)
new_data = torch.stack([data1, data2], dim=1) # (2, 2, 3)
new_data = torch.stack([data1, data2], dim=2) # (2, 3, 2)
3. torch.flip()
4. torch.chunk()
自动微分模块
1. 梯度基本计算
python
import torch
# 定义需要求梯度的张量(必须为浮点型)
w = torch.tensor(10., requires_grad=True, dtype=torch.float32)
# 定义计算图
y = 2 * w ** 2
print(y) # tensor(200., grad_fn=<MulBackward0>)
# 反向传播求梯度
y.sum().backward() # 向量需转标量
# 获取梯度
print(w.grad) # tensor(40.)
2. 梯度下降法示例
python
# 求 y = x^2 + 20 的极小值点
x = torch.tensor(10., requires_grad=True, dtype=torch.float32)
lr = 0.01
for i in range(1000):
y = x ** 2 + 20
# 梯度清零(防止累加)
if x.grad is not None:
x.grad.zero_()
# 反向传播
y.backward()
# 梯度更新
x.data = x.data - lr * x.grad
print(f"最优解: x = {x.item():.6f}, y = {y.item():.6f}")
# 输出: 最优解: x ≈ 0, y ≈ 20
3. 梯度计算注意点
python
# 不能对requires_grad的张量直接调用.numpy()
x1 = torch.tensor([10., 20.], requires_grad=True)
# 报错:RuntimeError
# print(x1.numpy())
# 使用detach()分离计算图
x2 = x1.detach() # 新张量,不追踪梯度
print(x2.numpy()) # [10. 20.]
线性回归实战
1. PyTorch 模型训练四步骤
准备训练集数据 → 构建模型 → 设置损失函数和优化器 → 模型训练
2. 完整代码
python
import torch
from torch.utils.data import TensorDataset, DataLoader
from torch import nn, optim
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
# ==================== 1. 准备数据集 ====================
def create_dataset():
x, y, coef = make_regression(
n_samples=100, # 100个样本
n_features=1, # 1个特征
noise=10, # 噪声标准差
coef=True, # 返回系数
bias=14.5, # 截距
random_state=0
)
# 转张量(注意类型匹配)
x = torch.tensor(x, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)
return x, y, coef
x, y, coef = create_dataset()
# ==================== 2. 构建模型 ====================
# 构造数据集对象
dataset = TensorDataset(x, y)
# 构造数据加载器
dataloader = DataLoader(
dataset=dataset,
batch_size=16, # 每批样本数
shuffle=True, # 打乱顺序
drop_last=False # 是否丢弃多余样本
)
# 构造模型(线性回归:y = wx + b)
model = nn.Linear(in_features=1, out_features=1)
# ==================== 3. 设置损失函数和优化器 ====================
criterion = nn.MSELoss() # 均方误差损失
optimizer = optim.SGD(model.parameters(), lr=1e-2) # 随机梯度下降
# ==================== 4. 模型训练 ====================
epochs = 100
epoch_loss = []
for epoch in range(epochs):
total_loss = 0.0
train_sample = 0
for train_x, train_y in dataloader:
# 正向传播
y_pred = model(train_x.reshape(-1, 1))
# 计算损失
loss = criterion(y_pred, train_y.reshape(-1, 1))
# 梯度清零
optimizer.zero_grad()
# 反向传播
loss.backward()
# 更新参数
optimizer.step()
total_loss += loss.item()
train_sample += 1
epoch_loss.append(total_loss / train_sample)
if (epoch + 1) % 20 == 0:
print(f"Epoch {epoch+1}/{epochs}, Loss: {epoch_loss[-1]:.4f}")
# ==================== 绘制结果 ====================
# 损失曲线
plt.plot(range(epochs), epoch_loss)
plt.title('Loss Curve')
plt.grid()
plt.show()
# 拟合效果
plt.scatter(x, y, label='Data')
x_line = torch.linspace(x.min(), x.max(), 1000)
y_line = model(x_line.reshape(-1, 1)).detach()
plt.plot(x_line, y_line, label='Fitted', color='red')
plt.legend()
plt.grid()
plt.show()
3. 训练流程口诀(2244)
第一个2:定义数据集对象 + 定义数据加载器
第一个4:定义模型 + 定义损失函数 + 定义学习率 + 定义优化器
第二个2:外层循环(轮数)+ 内层循环(批次数)
第二个4:梯度清零 + 计算loss + 反向传播 + 参数更新
2244口诀
第一个2:
定义数据集对象
定义数据加载器 dataloader
第二个2 :
两个循环:
训练多少轮? 对轮数进行循环
每轮有几个数据批次?对每轮的批次循环
第一个4
定义模型、loss函数、优化器 、设定学习率
第二个4:
训练4个步骤
在每一批次的训练时:
梯度清零(如果不需要累加的话)
计算loss,并反向传播求梯度(自动微分)
模型的参数更新
当一个轮次训练完之后,判断学习率是否要调整。
零碎:
每隔多少轮次后,进行模型保存 或 者跑一次验证集样本
以及更新 loss 曲线下降的图, 等等
GPU 加速
python
# 判断GPU是否可用
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 创建张量到GPU
tensor = torch.tensor([1, 2, 3]).to(device)
# 模型移动到GPU
model = model.to(device)
PyTorch 特点总结
| 特点 | 说明 |
|---|---|
| 类NumPy操作 | 语法与NumPy相似,易上手 |
| GPU加速 | 支持CUDA,训练速度更快 |
| 动态计算图 | 网络结构可变,调试方便 |
| 自动微分 | 内置autograd模块,自动求导 |
| 广泛应用 | CV、NLP、强化学习等 |
安装命令:
pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple