定义损失函数并以此训练和评估模型
F_D_Z 2024-07-16 16:07:04 阅读 82
基础神经网络模型搭建
【Pytorch】数据集的加载和处理(一)
【Pytorch】数据集的加载和处理(二)
损失函数计算模型输出和目标之间的距离。通过torch.nn 包可以定义一个负对数似然损失函数,负对数似然损失对于训练具有多个类的分类问题比较有效,负对数似然损失函数的输入为对数概率,而在模型搭建的输出层部分接触过log_softmax,它能从模型中获取对数概率
目录
基础模型搭建
数据集的加载和处理
定义损失函数
定义优化器
训练并评估模型
基础模型搭建
<code>import torch
from torch import nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
def forward(self, x):
pass
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5, 1)
self.conv2 = nn.Conv2d(20, 50, 5, 1)
self.fc1 = nn.Linear(4*4*50, 500)
self.fc2 = nn.Linear(500, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 4*4*50)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)
Net.__init__ = __init__
Net.forward = forward
model = Net()
检查搭建情况
print(model)
原位置为cpu
转移至所需CUDA设备
<code>device = torch.device("cuda:0")
model.to(device)
print(next(model.parameters()).device)
数据集的加载和处理
导入MNIST训练数据集和验证数据集并处理
from torch import nn
from torchvision import datasets
from torch.utils.data import TensorDataset
path2data="./data"code>
train_data=datasets.MNIST(path2data, train=True, download=True)
x_train, y_train=train_data.data,train_data.targets
val_data=datasets.MNIST(path2data, train=False, download=True)
x_val,y_val=val_data.data, val_data.targets
if len(x_train.shape)==3:
x_train=x_train.unsqueeze(1)
print(x_train.shape)
if len(x_val.shape)==3:
x_val=x_val.unsqueeze(1)
print(x_val.shape)
train_ds = TensorDataset(x_train, y_train)
val_ds = TensorDataset(x_val, y_val)
for x,y in train_ds:
print(x.shape,y.item())
break
from torch.utils.data import DataLoader
train_dl = DataLoader(train_ds, batch_size=8)
val_dl = DataLoader(val_ds, batch_size=8)
定义损失函数
损失函数计算模型输出和目标之间的距离。Pytorch 中的 optim 包提供了各种优化算法的实现,例如SGD、Adam、RMSprop 等。
通过torch.nn 包可以定义一个负对数似然损失函数,负对数似然损失对于训练具有多个类的分类问题比较有效,负对数似然损失函数的输入为对数概率,而在模型搭建的输出层部分接触过log_softmax,它能从模型中获取对数概率。
<code>loss_func = nn.NLLLoss(reduction="sum")code>
for xb, yb in train_dl:
# move batch to cuda device
xb=xb.type(torch.float).to(device)
yb=yb.to(device)
out=model(xb)
loss = loss_func(out, yb)
print (loss.item())
break
得到一个测试值
定义优化器
定义一个Adam优化器,优化器的输入是模型参数和学习率
<code>from torch import optim
opt = optim.Adam(model.parameters(), lr=1e-4)
通过opt .step()自动更新模型参数,同时需要注意计算下一批的梯度之前需将梯度归0
opt.step()
opt.zero_grad()
训练并评估模型
定义一个辅助函数 loss_batch来计算每个小批量的损失值。函数的 opt 参数引用优化器,如果给定,则计算梯度并按小批量更新模型参数。
def loss_batch(loss_func, xb, yb,yb_h, opt=None):
loss = loss_func(yb_h, yb)
metric_b = metrics_batch(yb,yb_h)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(),metric_b
定义一个辅助函数metrics_batch来计算每个小批量的性能指标,这里以准确率作为分类任务的性能指标,并使用 output.argmax 来获取概率最高的预测类
def metrics_batch(target, output):
pred = output.argmax(dim=1, keepdim=True)
corrects=pred.eq(target.view_as(pred)).sum().item()
return corrects
定义一个辅助函数loss_epoch来计算整个数据集的损失和指标值。使用数据加载器对象获取小批量,将它们提供给模型,并计算每个小批量的损失和指标,通过两个运行变量来分别添加损失值和指标值。
def loss_epoch(model,loss_func,dataset_dl,opt=None):
loss=0.0
metric=0.0
len_data=len(dataset_dl.dataset)
for xb, yb in dataset_dl:
xb=xb.type(torch.float).to(device)
yb=yb.to(device)
yb_h=model(xb)
loss_b,metric_b=loss_batch(loss_func, xb, yb,yb_h, opt)
loss+=loss_b
if metric_b is not None:
metric+=metric_b
loss/=len_data
metric/=len_data
return loss, metric
最后,定义一个辅助函数train_val来训练多个时期的模型。在每个时期使用验证数据集评估模型的性能。训练和评估需要分别使用 model.train()和 model.eval()模式。torch.no_grad()可以阻止 autograd 在评估期间计算梯度。
def train_val(epochs, model, loss_func, opt, train_dl, val_dl):
for epoch in range(epochs):
model.train()
train_loss,train_metric=loss_epoch(model,loss_func,train_dl,opt)
model.eval()
with torch.no_grad():
val_loss, val_metric=loss_epoch(model,loss_func,val_dl)
accuracy=100*val_metric
print("epoch: %d, train loss: %.6f, val loss: %.6f,accuracy: %.2f" %(epoch, train_loss,val_loss,accuracy))
设定时期数为5,调用函数进行训练和评估
num_epochs=5
train_val(num_epochs, model, loss_func, opt, train_dl, val_dl)
上一篇: 如何完美解决 Xshell 使用 SSH 连接 Linux 服务器报错:找不到匹配的 host key 算法
下一篇: Structure of Linux Kernel Device Driver(Part II)
本文标签
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。