【DataWhales】深入浅出Pytorch-第三章/第四章
第三章: Pytorch 的主要组成模块
3.1 神经网络学习机制和深度学习在实现上的特殊性
3.1.1 神经网络学习机制
一般分为:
- 数据预处理
- 模型设计
- 损失函数和优化方案设计
- 前向传播
- 反向传播
- 更新参数
3.1.2 深度学习在实现上的特殊性
- 样本量大,通常需要 分批(batch)加载 \color{blue}\textbf{分批(batch)加载} 分批(batch)加载
- 逐层、模块化搭建网络(卷积层、全连接层、LSTM等)多样化的 损失函数和优化器设计 \color{blue}\textbf{损失函数和优化器设计} 损失函数和优化器设计
- GPU的使用
- 以上各个模块之间的配合
3.2 PyTorch深度学习模块
- 将PyTorch完成深度学习的步骤拆解为几个主要模块
- 实际使用根据自身需求修改对应模块即可
- 深度学习 ⇒ 搭积木 \textbf{深度学习}\Rightarrow\textbf{搭积木} 深度学习⇒搭积木.,分为: 基本配置 \color{blue}\textbf{基本配置} 基本配置, 数据读入 \color{blue}\textbf{数据读入} 数据读入, 模型构建 \color{blue}\textbf{模型构建} 模型构建, 损失函数 \color{blue}\textbf{损失函数} 损失函数, 优化器 \color{blue}\textbf{优化器} 优化器, 训练与评估 \color{blue}\textbf{训练与评估} 训练与评估
- 任务:FashionMNIST时装分类数据简介∶
- 10类图片
- 每张图 32 × 32 32\times32 32×32px
第四章 基础实战——FashionMNIST时装分类
4.1 基本配置
- 导入必要的
packages
os, numpy, pandas, torch, torch.nn, torch.optim, torch.utils.data
- 配置训练过程的超参数
batch size
,learning rate
,max_epochs
,num_workers
- 配置训练用的硬件设备
CPU or GPU
,which GPU(s)
代码演示
4.1.1 导入必要的包
import os
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
4.1.2 配置训练环境
# 配置GPU,这里有两种方式
## 方案一:使用os.environ, 后续往GPU中添加数据使用***.cuda()
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
# 方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可;
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
- 使用
os.environ
, 后续往GPU中添加数据使用***.cuda()
- 使用
“device”
,后续对要使用GPU的变量用.to(device)
即可;
4.1.3 配置超参数
## 配置其他超参数,如batch_size, num_workers, learning rate, 以及总的epochs
batch_size = 256
num_workers = 4
lr = 1e-4
epochs = 20
4.2 数据读入
- 如何读取格式不定的本地数据:
Dataset
__init__
: 用于向类中传入外部参数,同时定义样本集__getitem__
: 用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据__len__
: 用于返回数据集的样本数
- 如何将数据加载以供模型输入:
DataLoader
batch_size
,num_workders
,shuffle
,drop_last
,pin_memory
这些变换可以很方便地借助
torchvision
包来完成,这是PyTorch官方用于图像处理的工具库,上面提到的使用内置数据集的方式也要用到。PyTorch的一大方便之处就在于它是一整套“生态”。
4.2.1 读取方式一:使用torchvision自带数据集
使用torchvision 自带的数据集处理,
from torchvision import datasets
train_data = datasets.FashionMNIST(root = './', train= True, download=True, transform = data_transform)
test_data = datasets.FashionMNIST(root='./', train=False, download=True, transform = data_transform)
4.2.2 读取方式二:读入csv格式的数据,自行构建Dataset类
class FMDataset(Dataset):
def __init__(self, df, transform=None):
self.df = df
self.transform = transform
self.images = df.iloc[:,1:].values.astype(np.uint8)
self.labels = df.iloc[:,0].values
def __len__(self):
return len(self.images)
def __getitem__(self, idx):
image = self.images[idx].reshape(image_size, image_size, 1)
label = int(self.labels[idx])
if self.transform is not None:
image = self.transform(images)
else:
image = torch.tensor(image/255. , dtype=torch.float)
label = torch.tensor(label, dtype=torch.long)
return image, label
train_df = pd.read_csv("./fashion-mnist_train.csv")
test_df = pd.read_csv("./fashion-mnist_test.csv")
train_data = FMDataset(train_df, data_transform)
test_data = FMDataset(test_df, data_transform)
注意
iloc
的使用。
4.2.3 使用DataLoader类加载数据
- DataLoader加载数据
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=num_workers, drop_last=True) test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=num_workers)
- 数据可视化
4.3 模型构建
- 神经网络的构造∶基于
nn.Module
__init__
,forward
- 神经网络是通过“层定义+层顺序”的方式构建起来的·神经网络常见层
nn.Conv2d, nn.MaxPool2d, nn.Linear, nn.ReLU
4.3.1 模型建立
- 按次序导入
Sequential
,定义前向传播函数
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 32, 5),
nn.ReLU(),
nn.MaxPool2d(2, stride=2),
nn.Dropout(0.3),
nn.Conv2d(32, 64, 5),
nn.ReLU(),
nn.MaxPool2d(2, stride=2),
nn.Dropout(0.3)
)
self.fc = nn.Sequential(
nn.Linear(64*4*4, 512),
nn.ReLU(),
nn.Linear(512, 10)
)
def forward(self, x):
x = self.conv(x)
x = x.view(-1, 64*4*4)
x = self.fc(x)
# x = nn.functional.normalize(x)
return x
model = Net()
model = model.cuda()
# model = nn.DataParallel(model).cuda()
4.3.2 定义损失函数
-
使用
torch.nn
模块自带的CrossEntropy
损失- PyTorch会自动把整数型的label转为one-hot型,用于计算CE loss
- 这里需要确保label是从0开始的,同时模型不加softmax层(使用logits计算),这也说明了PyTorch训练中各个部分不是独立的,需要通盘考虑
criterion = nn.CrossEntropyLoss() # criterion = nn.CrossEntropyLoss(weight=[1,1,1,1,3,1,1,1,1,1])
-
可以加权重
criterion = nn.CrossEntropyLoss(weight=[1,1,1,1,3,1,1,1,1,1])
4.3.3 优化器
- torch.optim提供了多种预定义的优化器
- 可以自己定义优化器
- 根据实际需求选用对应的优化器
- 优化器常用操作∶
step()
,zero_grad()
,load_state_dict()
, …
optimizer = optim.Adam(model.parameters(), lr=0.001)
4.4 训练与评估
- 模型状态设置
model.train()
,model.eval()
- 训练流程︰ 读取、转换、梯度清零、输入、计算损失、反向传播、参数更新 \color{blue}\textbf{读取、转换、梯度清零、输入、计算损失、反向传播、参数更新} 读取、转换、梯度清零、输入、计算损失、反向传播、参数更新。
- 验证流程: 读取、转换、输入、计算损失、计算指标 \color{blue}\textbf{读取、转换、输入、计算损失、计算指标} 读取、转换、输入、计算损失、计算指标
4.4.1 训练
def train(epoch):
model.train()
train_loss = 0
for data, label in train_loader:
data, label = data.cuda(), label.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(output, label)
loss.backward()
optimizer.step()
train_loss += loss.item()*data.size(0)
train_loss = train_loss/len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))
4.4.2 测试
def val(epoch):
model.eval()
val_loss = 0
gt_labels = []
pred_labels = []
with torch.no_grad():
for data, label in test_loader:
data, label = data.cuda(), label.cuda()
output = model(data)
preds = torch.argmax(output, 1)
gt_labels.append(label.cpu().data.numpy())
pred_labels.append(preds.cpu().data.numpy())
loss = criterion(output, label)
val_loss += loss.item()*data.size(0)
val_loss = val_loss/len(test_loader.dataset)
gt_labels, pred_labels = np.concatenate(gt_labels), np.concatenate(pred_labels)
acc = np.sum(gt_labels==pred_labels)/len(pred_labels)
print('Epoch: {} \tValidation Loss: {:.6f}, Accuracy: {:6f}'.format(epoch, val_loss, acc))
4.5 模型保存
save_path = "./FahionModel.pkl"
torch.save(model, save_path)