pytorch学习笔记(三)
一、模型保存
用pathlib库中的方法来保存模型参数
1)保存模型参数
from pathlib import Path
MODEL_PATH = Path("models") #Path更好表示路径
# parents表示当前路径是否存在多级嵌套,exist_ok表示当前文件夹存在也不影响
MODEL_PATH.mkdir(parents = True, exist_ok = True)
MODEL_NAME = "02_pytorch_workflow_model_0.pth" # pth文件用于保存模型参数
MODEL_SAVE_PATH = MODEL_PATH / MODEL_NAME # 总路径,合并
#PosixPath('models/02_pytorch_workflow_model_0.pth')
# 将模型参数保存到此路径
# obj:我要保存的模型参数,f:保存到的路径
torch.save(obj = model_0.state_dict(), f = MODEL_SAVE_PATH)
2)调用已保存的模型
loaded_model_0 = LinearRegressionModel() # 建立一个线性回归模型,并初始化参数
# 加载训练好的参数到loaded_model_0
# load_state_dict( )里面的参数不要直接写路径,用torch.load()转一下
loaded_model_0.load_state_dict(torch.load(f = MODEL_SAVE_PATH))
二、分类任务的处理(从头到尾处理整个分类任务)
from sklearn.datasets import make_circles
n_samples = 1000
# noise模拟自然界真实的扰动,random_state指定随机种子,确保每次运行代码时生成的数据集相同
X,y = make_circles(n_samples, noise = 0.03, random_state = 666)
#可以把数据映射成pandas的表格的形式更好看
import pandas as pd
circles = pd.DataFrame({"X1":X[:0], "X2":X[:1], "label":y})
circels.head(10) # 显示表中前10行数据
circles.label.value_counts() # 统计每个类中有多少个
# 将样本点可视化看一下
import matplotlib.pyplot as plt
# plt.cm.RdYlBu做一个色彩映射,更好看
# c = y 根据y的值映射到预定义色彩空间RdYlBu上
plt.scatter(x=X[:,0], y = X[:,1], c = y, cmap = plt.cm.RdYlBu)
import torch
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
# 把一个numpy转成tensor时候一定要加.type(torch.float) 由于他们两个float默认精度不一样
划分数据集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 666)
建立分类模型
import torch
from torch import nn
device = "cuda" if torch.cuda.is_available() else "cpu"
# 上述是通用的
class CircleModelV0(nn.module):
def __init__(self):
super().__init()
# self
self.layer_1 = nn.Linear(in_features = 2, out_features = 5)
self.layer_2 = nn.Linear(in_features = 5 out_features = 1)
self.relu = nn.ReLU()
def forward(self, x):
return self.layer_2(self.relu(self.layer_1(x)))
model_0 = CircleModelV0().to(device)
# 二分类交叉熵损失BCE
torch.nn.BCELoss()
torch.nn.BCEWithLogitsLoss()
#logits回归,把原始值经过logits函数压缩到0,1这个区间
loss_fn = torch.nn.BCEWithLogitsLoss()
optimizer = torch.optim.SGD(params = model_0.parameters(), lr = 0.1)
# sigmoid 1 / (1 + e^-x)
y_logits = model_0(X_test.to(device))
y_pred_prob = torch.sigmoid(y_logits) # 把元素数据压缩到0,1范围内
y_pred_labels = torch.round(y_pred_prob) # 把大于0.5记作1,小于0.5记为0
y_pred_labels = y_pred_labels.squeeze() # 从[200,1]压缩到[200]‘
# 统计准确率
def accuracy_fn(y_true, y_pred):
correct = torch.sum(y_true == y_pred).item()
acc = (correct / len(y_true)) * 100
return acc
# 训练模型
torch.manual_seed(666)
epochs = 200
X_train, y_train = X_train.to(device), y_train.to(device)
X_test, y_test = X_test.to(device), y_test.to(device)
for epoch in range(epochs):
model_0.train() # 先把模型调到训练模式
y_logits = model_0(X_train).squeeze()
y_pred = torch.round(torch.sigmoid(y_logits)) # 预测结果用0、1表示
# 计算损失函数用y_logits而不用y_pred,因为定义的损失函数loss_fn是BCEWithLogitsLoss带logits
loss = loss_fn(y_logits, y_train)
acc = accuracy_fn(y_train, y_pred)
# 每次反向传播之前要删除上一次的梯度
# 第一次反向传播后,梯度为grad1。第二次反向传播后,梯度会变为grad1+grad2,而不是我们期望的 grad2
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 评估模式
model_0.eval()
with torch.inference_mode():
test_logits = model_0(X_test).squeeze()
test_pred = torch.round(torch.sigmoid(test_logits))
test_loss = loss_fn(test_logits, y_test)
test_acc = accuracy_fn(y_test, test_pred)
print(f"{epoch} | Loss:{loss} | acc:{acc} | Test Loss:{test_loss} | Test Acc:{test_acc}")
三、流程总结
1. 从某个数据集中拿数据,最原始不经过处理的数据(这里用的是sklearn的circle数据集)
2. 看看数据什么样,用各种可视化的方法
3. 将最原始的数据转成tensor
4. 选取合适的模型并构建模型
5. 数据集划分(训练集和测试集)
6.开始训练:每个epoch得到预测值和实际值的差,计算loss,梯度下降,回传(每个模型都是一样的)
7.测试:打印Acc和loss
8.找个地方把模型存下来