【深度学习】神经网络实战分类与回归任务
第一步 读取数据
①导入torch
import torch
②使用魔法命令,使它使得生成的图形直接嵌入到 Notebook 的单元格输出中,而不是弹出新的窗口来显示图形
%matplotlib inline
③读取文件
from pathlib import Path
import requests
DATA_PATH=Path("data")
PATH = DATA_PATH/"mnist"
PATH.mkdir(parents=True,exist_ok=True)
URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"
if not (PATH/FILENAME).exists():
content = requests.get(URL+FILENAME).content
(PATH/FILENAME).open("wb").write(content)
④使用 gzip
和 pickle
模块加载一个压缩的 pickle 文件 (mnist.pkl.gz
)
(PATH / FILENAME).as_posix()
:将 Path
对象转换为 POSIX 路径字符串,适用于跨平台环境。
import pickle
import gzip
with gzip.open((PATH/FILENAME).as_posix(),"rb") as f:
((x_train,y_train),(x_valid,y_valid),_) = pickle.load(f,encoding="latin-1")
第二步 主体部分
①自定义神经网络模型
import torch.nn.functional as F
from torch import nn
class Mnist_NN(nn.Module):
def __init__(self):
super().__init__()
self.hidden1 = nn.Linear(784,128)
self.hidden2 = nn.Linear(128,256)
self.out = nn.Linear(256,10)
def forward(self,x):
x = F.relu(self.hidden1(x))
x = F.relu(self.hidden2(x))
x = self.out(x)
return x
②定义获取数据的方法
shuffle代表洗牌
def get_data(train_ds,valid_ds,bs):
return (
DataLoader(train_ds,batch_size=bs,shuffle=True),
DataLoader(valid_ds,batch_size=bs*2)
)
③定义获取模型的方法
torch.optim
是 PyTorch 中用于定义各种优化算法的模块
from torch import optim
def get_model():
model = Mnist_NN()
return model,optim.Adam(model.parameters(),lr=0.001)
④定义损失函数
注1:调用model(xb)时会自动进行前向计算(forward pass)
这是因为PyTorch的nn.Module类(即所有神经网络模型的基类)内部实现了对__call__方法的重载。当通过实例化一个继承自nn.Module的类来创建对象时,并调用该对象(如果model(xb)),实际上是调用了这个对象的__call__方法。而__cacll__方法负责调用forward方法
注2:F.entropy是PyTorch中用于计算交叉熵损失的函数,位于torch.nn.functional模块中
它结合了log_softmax和nll_loss(负对数似然损失),使得在分类任务中可以直接使用,而无需显示地应用log_softmax
F提供了很多用于构建神经网络的方法,包括激活函数、损失函数、卷积操作、池化操作等
注3:
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()代码段解析
这一段用于优化模型。它包含了反向传播(计算梯度)和参数更新的过程,是模型训练的核心步骤。
loss.backward()
反向传播:调用backward()方法会根据损失函数对模型参数进行自动求导,计算每个参数的梯度,这些梯度将被存储在对应的参数张量的.grad属性中
反向传播是基于链式法则自动计算所有参数相对于损失的偏导数的过程
这一步骤对于更新模型参数至关重要,因为它提供了调整参数所需的方向信息
opt.step()
参数更新:调用step()方法会使用之前计算的梯度来更新模型参数。具体的更新规则取决于所使用的优化算法(如SGD、Adam等),并且可能涉及到学习率、动量等超参数
opt.zero_grad()
清除梯度:调用zero_grad()方法会将所有参数的梯度重置为零。这是必要的,因为PyTorch默认会累积梯度,而不是每次前向传播后自动清除它们。
如果不重置梯度,旧的梯度将会与新的梯度相加,导致不正确的梯度值,进而影响参数更新的效果。
通常在每次迭代结束时调用此方法以确保下一次前向传播时梯度是从零开始计算的。
loss_func = F.cross_entropy
def loss_batch(model,loss_func,xb,yb,opt=None):
loss = loss_func(model(xb),yb)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(),len(xb)
⑤定义训练函数
import numpy as np
def fit(steps,model,loss_func,opt,train_dl,valid_dl):
for step in range(steps):
model.train()
for xb,yb in train_dl:
loss_batch(model,loss_func,xb,yb,opt)
model.eval()
with torch.no_grad():
losses,nums = zip(
*[loss_batch(model,loss_func,xb,yb) for xb,yb in valid_dl]
)
val_loss = np.sum(np.multiply(losses,nums))/np.sum(nums)
print("当前step:"+str(step)+",验证集损失:"+str(val_loss))
第三步 运行
①使用 Python 的内置 map()
函数,结合 PyTorch 的 torch.tensor
方法,将 x_train
, y_train
, x_valid
, 和 y_valid
转换为 PyTorch 张量。这一步骤是数据预处理的一部分,确保所有数据都以张量的形式存储,从而可以直接用于 PyTorch 模型的训练和评估。
②加载数据集和数据
③加载模型
④训练,评估
x_train,y_train,x_valid,y_valid = map(torch.tensor,(x_train,y_train,x_valid,y_valid))
train_ds = TensorDataset(x_train,y_train)
valid_ds = TensorDataset(x_valid,y_valid)
bs=64
train_dl,valid_dl = get_data(train_ds,valid_ds,bs)
model,opt = get_model()
fit(25,model,loss_func,opt,train_dl,valid_dl)
运行结果:
测试训练精度:
correct = 0
total = 0
for xb,yb in valid_dl:
outputs = model(xb)
_,predicted = torch.max(outputs.data,1)
total += yb.size(0)
correct += (predicted==yb).sum().item()
print("准确率为: %d %%" % (100*correct/total))
至此,该实战完成!