使用Pytorch快速搭建神经网络模型(附详细注释和讲解) 您所在的位置:网站首页 抑郁症详细介绍 使用Pytorch快速搭建神经网络模型(附详细注释和讲解)

使用Pytorch快速搭建神经网络模型(附详细注释和讲解)

2023-08-13 09:00| 来源: 网络整理| 查看: 265

文章目录 0 前言1 数据读入2 模型搭建3 模型训练4 模型测试5 模型保存6 参考博客

0 前言

代码参考了知乎上“10分钟快速入门PyTorch”系列,并且附上了详细的注释和函数讲解。从今天这篇博文开始,我将和大家一起踏上Pytorch的学习道路,希望有问题可以指出!代码可以直接复制粘贴后运行。

1 数据读入

torchvision.datasets里面有很多数据类型,里面有官网处理好的数据,比如我们要使用的MNIST数据集(手写数字数据集),可以通过torchvision.datasets.MNIST()来得到:

import torch from torch import nn from torch.utils.data import DataLoader from torchvision import datasets, transforms # 定义超参数 batch_size = 64 learning_rate = 1e-2 num_epochs = 5 # 训练次数 # 判断GPU是否可用 use_gpu = torch.cuda.is_available() # 下载训练集 MNIST 手写数字训练集 # 数据是datasets类型的 train_dataset = datasets.FashionMNIST( root='../datasets', train=True, transform=transforms.ToTensor(), download=True) test_dataset = datasets.FashionMNIST( root='../datasets', train=False, transform=transforms.ToTensor()) # 将数据处理成 DataLoader train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 选择打乱数据 test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 选择不打乱数据 Pytorch的数据读取主要包括3个类:(1)Dataset (2)DataLoader (3)DataLoaderIter,这三者的大致是依次封装的关系,1被装进2,2被装进3。Dataset是一个包装类,负责表示数据集,它可以每次使用__getitem__返回一个样本。我们再使用DataLoader这个类来更加快捷的对数据进行操作。Dataset被封装在了Dataloader中。 def __getitem__(self,index): img_path,label=self.data[index].img_path,self.data[index].label img=Image.open(img_path) return img,label

可见每次会返回:数据+标签

DataLoader是一个比较重要的类,它为我们提供的常用操作有:batch_size(每个batch的大小), shuffle(是否进行shuffle操作), num_workers(加载数据的时候使用几个子进程)。Dataset、Dataloader和DataLoaderIter是层层封装的关系,最终在内部使用DataLoaderIter进行迭代。 2 模型搭建

这里给出一个通用的模型框架:

# 基本的网络构建类模板 class net_name(nn.Module): def __init__(self): super(net_name, self).__init__() # 可以添加各种网络层 self.conv1 = nn.Conv2d(3, 10, 3) # 具体每种层的参数可以去查看文档 def forward(self, x): # 定义向前传播 out = self.conv1(x) return out

由上述框架搭建我们的神经网络:

# 定义简单的前馈神经网络 class neuralNetwork(nn.Module): def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim): super(neuralNetwork, self).__init__() # super() 函数是用于调用父类(超类)的一个方法 # Sequential()表示将一个有序的模块写在一起,也就相当于将神经网络的层按顺序放在一起,这样可以方便结构显示 self.layer1 = nn.Sequential( nn.Linear(in_dim, n_hidden_1), nn.ReLU(True)) # 表示使用ReLU激活函数 self.layer2 = nn.Sequential( nn.Linear(n_hidden_1, n_hidden_2), nn.ReLU(True)) self.layer3 = nn.Sequential( nn.Linear(n_hidden_2, out_dim), nn.ReLU(True)) # 定义向前传播 def forward(self, x): x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) return x # 图片大小是28*28,中间定义了两个隐藏层大小分别为300和100,最后输出层为10,10分类问题 model = neuralNetwork(28 * 28, 300, 100, 10) if use_gpu: model = model.cuda() # 现在可以在GPU上跑代码了 criterion = nn.CrossEntropyLoss() # 定义损失函数类型,使用交叉熵 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) # 定义优化器,使用随机梯度下降 nn.Module 是所有神经网络单元(neural network modules)的基类。pytorch在nn.Module中,实现了__call__方法,而在__call__方法中调用了forward函数。 所以forward函数中依次调用添加到self._module中的子模块,最后输出经过所有神经网络层的结果。最后的forward函数中的x只是重复使用了,是由上往下层层传递的。 3 模型训练

第一个循环表示每个epoch,接着开始前向传播,然后计算loss,然后反向传播,接着优化参数,特别注意的是在每次反向传播的时候需要将参数的梯度归零:

# 开始模型训练 for epoch in range(num_epochs): print('*' * 10) print(f'epoch {epoch+1}') running_loss = 0.0 # 初始值 running_acc = 0.0 for i, data in enumerate(train_loader, 1): # 枚举函数enumerate返回下标和值 img, label = data img = img.view(img.size(0), -1) # 将图片展开为28*28 # 使用GPU? if use_gpu: img = img.cuda() label = label.cuda() # 向前传播 out = model(img) # 前向传播 loss = criterion(out, label) # 计算loss running_loss += loss.item() # loss求和 _, pred = torch.max(out, 1) running_acc += (pred == label).float().mean() # 向后传播 optimizer.zero_grad() # 梯度归零 loss.backward() # 后向传播 optimizer.step() # 更新参数 if i % 300 == 0: print(f'[{epoch+1}/{num_epochs}] Loss: {running_loss/i:.6f}, Acc: {running_acc/i:.6f}') print(f'Finish {epoch+1} epoch, Loss: {running_loss/i:.6f}, Acc: {running_acc/i:.6f}') 4 模型测试

特别注意的是需要用 model.eval(),让model变成测试模式,这主要是对dropout和batch:

## 模型测试 model.eval() # 让模型变成测试模式 eval_loss = 0. eval_acc = 0. for data in test_loader: img, label = data img = img.view(img.size(0), -1) if use_gpu: img = img.cuda() label = label.cuda() with torch.no_grad(): out = model(img) loss = criterion(out, label) eval_loss += loss.item() _, pred = torch.max(out, 1) eval_acc += (pred == label).float().mean() print(f'Test Loss: {eval_loss/len(test_loader):.6f}, Acc: {eval_acc/len(test_loader):.6f}\n')

1.在pytorch中的view()函数就是用来改变tensor的形状的,例如将2行3列的tensor变为1行6列, view( )相当于numpy中resize()的功能,但是用法可能不太一样。 2. 参数中的-1就代表这个位置由其他位置的数字来推断,比如a tensor的数据个数是6个,如果view(1,-1),我们就可以根据tensor的元素个数推断出-1代表6。

5 模型保存 # 保存模型 torch.save(model.state_dict(), './neural_network.pth')

部分运行结果: 在这里插入图片描述

6 参考博客

https://www.zhihu.com/column/c_94953554 https://blog.csdn.net/gdymind/article/details/82226509 https://blog.csdn.net/jzwong/article/details/113308158 https://blog.csdn.net/qq_38929105/article/details/106438045 https://blog.csdn.net/york1996/article/details/81949843 https://blog.csdn.net/york1996/article/details/81949843



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有