Pytorch之神经网络

Pytorch实现基础的神经网络

使用Pytorch配合MNIST数据集实现基础的神经网络

下面从四个方面实现

  1. 加载数据——Data Loader
  2. 建立模型,定义损失函数和优化函数
  3. 训练模型
  4. 测试保存模型

加载数据——Data Loader

要求下载训练集 MNIST,创建符合要求的DataLoader变量data_loader,同时按要求输出特定数据的维度大小和类别,使用pytorch读取训练集是非常便捷的,只需要使用到两个类:
torch.utils.data.Dataset
torch.utils.data.DataLoader
所以要学会导包

其中在pytorch中具有一个集成的数据模块,torchvision.datasetsz在这里面具有以下这些数据集:
MNIST
COCO (Captioning and Detection)
LSUN Classification
ImageFolder
Imagenet-12
CIFAR10 and CIFAR100
STL10

其中MNIST是torchvision.datasets包中的一个类,负责根据传入的参数加载数据集。如果自己之前没有下载过该数据集,可以将download参数设置为True,会自动下载数据集并解包。如果之前已经下载好了,只需将其路径通过root传入即可。

在加载图像后,我们常常需要对图像进行若干预处理。比如减去RGB通道的均值,或者裁剪或翻转图像实现augmentation等,这些操作可以在torchvision.transforms包中找到对应的操作。在下面的代码中,通过使用transforms.ToTensor()将PIL图像转换为Tensor数据(RGB 通道从[0, 255]范围变为[0, 1])。
具体介绍实例化torch.utils.data.DataLoader的使用方式
有了这些基础知识我们可以开始第一步:

import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import os
import sys
path = os.path.split(os.path.abspath(os.path.realpath(sys.argv[0])))[0] + os.path.sep
path = path[:-10] + '/data/'
#/********** Begin *********/
# 下载训练集 MNIST 训练集,设置 root = path,train=False ,download=False,赋值给变量train_dataset
train_dataset = dsets.MNIST(root= path,
                            train=False,
                            transform=transforms.ToTensor(),
                            download=False)
# 创建batch_size=100, shuffle=True的DataLoader变量data_loader
data_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size=100,
                                           shuffle=True)
# 获取数据集中的第四个元素的图片信息和类别
print('Number of samples: ', len(train_dataset))
img, target = train_dataset[3] # load 4th sample
#按照格式“Image Size: ...”输出该图片大小
print("Image Size: ", img.size())
#按照格式“Image Target: ...”输出该图片的类别
print("Image Target: ",target)
#/********** End *********/

建立模型,定义损失函数和优化函数

导入基础数据集后我们将开始构建一个以三层的最简易CNN网络。在此之前我们要知道什么叫前馈神经网络:也就是将每一层的输出作为下一层的输入,在pytorch中前馈神经网络是通过torch.nn中已经实现的卷积层所完成的。如下所示就是一个具有隐含层的MLP网络,nn.Linear负责构建全连接层,需要提供输入和输出的通道数,也就是y = wx+b中x和y的维度。

# 定义简单的前馈神经网络
class Neuralnetwork(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
#调用父类的初始化函数
        super(Neuralnetwork, self).__init__()
# 定义全连接层:线性连接(y = Wx + b),in_dim个节点连接到n_hidden_1个节点上
        self.layer1 = nn.Linear(in_dim, n_hidden_1)
# 定义全连接层:线性连接(y = Wx + b),n_hidden_1个节点连接到n_hidden_2个节点上
        self.layer2 = nn.Linear(n_hidden_1, n_hidden_2)
# 定义全连接层:线性连接(y = Wx + b),n_hidden_2个节点连接到out_dim个节点上
        self.layer3 = nn.Linear(n_hidden_2, out_dim)
    def forward(self, x):
# 输入x->layer1,更新到x
        x = self.layer1(x)
# 输入x->layer2,更新到x
        x = self.layer2(x)
# 输入x->layer3,更新到x
        x = self.layer3(x)
        return x
model = Neuralnetwork(28 * 28, 300, 100, 10)
损失函数

在损失函数这一块我们选择使用交叉熵作为损失函数也就是:criterion = nn.CrossEntropyLoss()

优化方法

在训练时,我们确定优化方法为SGD方法。下面代码中的optim.SGD初始化需要接受网络中待优化的Parameter列表(或是迭代器),以及学习率lr。optimizer = optim.SGD(model.parameters(), lr=learning_rate)
因此时间建立模型,定义损失和优化函数则是有以下方式实现:

import torch 
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable
# CNN Model (2 conv layer)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5, padding=2),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(2))
        #/********** Begin *********/
        self.layer2 = nn.Sequential(
            #定义卷积层Conv2d:输入16张特征图,输出32张特征图,卷积核5x5,padding为2
            nn.Conv2d(16, 32, kernel_size=5, padding=2),
            #定义BatchNorm2d层,参数为32
            nn.BatchNorm2d(32),
            #定义非线性层ReLU
            nn.ReLU(),
            #定义2x2窗口的最大池化层MaxPool2d
            nn.MaxPool2d(2))
        # 定义全连接层:线性连接(y = Wx + b),7*7*32个节点连接到10个节点上
        self.fc = nn.Linear(7*7*32, 10)
    def forward(self, x):
        out = self.layer1(x)
        # 输入out->layer2->更新到out
        out = self.layer2(out)
        #view函数将张量x变形成一维向量形式,总特征数不变,为全连接层做准备
        out = out.view(out.size(0), -1)
        # 输入out->fc,更新到out
        out = self.fc(out)
        return out
    #/********** End *********/
cnn = CNN()
# 返回参数值:顺序和下面的named一致
params = list(cnn.parameters())
print(len(params))
# net.named_parameters(): ((参数名称,参数属性),……)
for name, parameters in cnn.named_parameters():
    print(name, ":", parameters.size())

训练模型

构建完模型后我们将开始模型的训练并创建一个交叉熵损失函数,创建类型为Adam的优化算子,补充梯度归零、反馈求导、优化等语句,根据num_epochs的设定共训练60次,分10次输出一回loss的数值信息。

import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable
import os
import sys
path = os.path.split(os.path.abspath(os.path.realpath(sys.argv[0])))[0] + os.path.sep
#rootpath = path[:10] + '/data/'
#print(path)
# Hyper Parameters
batch_size = 100
learning_rate = 0.001
num_epochs = 1
# MNIST Dataset
train_dataset = dsets.MNIST(root='./data/',
                            train=True,
                            transform=transforms.ToTensor(),
                            download=False)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True)
# CNN Model (2 conv layer)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
                                    nn.Conv2d(1, 16, kernel_size=5, padding=2),
                                    nn.BatchNorm2d(16),
                                    nn.ReLU(),
                                    nn.MaxPool2d(2))
        self.layer2 = nn.Sequential(
                                    nn.Conv2d(16, 32, kernel_size=5, padding=2),
                                    nn.BatchNorm2d(32),
                                    nn.ReLU(),
                                    nn.MaxPool2d(2))
        self.fc = nn.Linear(7*7*32, 10)
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.view(out.size(0), -1)
        out = self.fc(out)
        return out
cnnmodel = CNN()
#创建输出文件 output.txt
f = open(path + 'output.txt', 'w')
f.seek(0)
f.truncate()   #清空文件
#/********** Begin *********/
# 声明一个为交叉熵损失函数的变量criterion
criterion = nn.CrossEntropyLoss()
# 声明一个为Adam优化函数的变量optimizer,传入 cnn的参数,并使学习率lr为0.001
optimizer = torch.optim.Adam(cnnmodel.parameters(), lr=learning_rate)
# 训练模型
for i, (images, labels) in enumerate(train_loader):
    # 将images,labels数据转换为Variable类型
    images = Variable(images)
    labels = Variable(labels)
    # optimizer梯度归零
    optimizer.zero_grad()
    # 对 images 应用 cnnmodel 模型并赋值给变量 outputs
    outputs = cnnmodel(images)
    loss = criterion(outputs, labels)
    #Backward
    loss.backward()
    #Optimize
    optimizer.step()
    #共训练60次,分别100次输出一回loss信息,并将输出信息存到文件中
    if (i+1) % 10 == 0:
        f.writelines('Epoch [%d/%d], Iter [%d/%d] Loss: %.4f \n'
                     %(1, num_epochs, i+1, len(train_dataset)//1000, loss.data[0]))
        print ('Epoch [%d/%d], Iter [%d/%d] Loss: %.4f'
            %(1, num_epochs, i+1, len(train_dataset)//1000, loss.data[0]))
    if i > 60:
        break
f.close()
#/********** End *********/

测试保存模型

训练完模型后我们要学会保存并使用模型解决实际问题。
如下是简单的测试模型代码模板:

model.eval()
    eval_loss = 0.
    eval_acc = 0.
    for data in test_loader:
        img, label = data
        img = img.view(img.size(0), -1)
        if torch.cuda.is_available():
            img = Variable(img, volatile=True).cuda()
            label = Variable(label, volatile=True).cuda()
        else:
            img = Variable(img, volatile=True)
            label = Variable(label, volatile=True)
        out = model(img)
        loss = criterion(out, label)
        eval_loss += loss.data[0] * label.size(0)
        _, pred = torch.max(out, 1)
        num_correct = (pred == label).sum()
        eval_acc += num_correct.data[0]
    print('Test Loss: {:.6f}, Acc: {:.6f}'.format(eval_loss / (len(
        test_dataset)), eval_acc / (len(test_dataset))))
    print()

得到的输出结果结构模式如下:

**********
[1/50] Loss: 1.941826, Acc: 0.542292
[1/50] Loss: 1.495615, Acc: 0.655469
[1/50] Loss: 1.214473, Acc: 0.714271
[1/50] Loss: 1.039444, Acc: 0.750990
[1/50] Loss: 0.923493, Acc: 0.775104
[1/50] Loss: 0.840292, Acc: 0.792604
Finish 1 epoch, Loss: 0.824490, Acc: 0.795817
Test Loss: 0.381371, Acc: 0.895400
#省略中间的迭代输出
epoch 50
**********
[50/50] Loss: 0.244704, Acc: 0.932083
[50/50] Loss: 0.244863, Acc: 0.933125
[50/50] Loss: 0.248566, Acc: 0.932187
[50/50] Loss: 0.246309, Acc: 0.932344
[50/50] Loss: 0.243054, Acc: 0.933167
[50/50] Loss: 0.244555, Acc: 0.932708
Finish 50 epoch, Loss: 0.244324, Acc: 0.932467
Test Loss: 0.270616, Acc: 0.926000
保存模型

torch.save(model.state_dict(), ‘./neural_network.pth’)
所以最后测试代码也就是:

import torch
import torch.nn as nn
import torchvision.datasets as dsets
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms
from torch.autograd import Variable
import warnings
from PIL import Image
warnings.filterwarnings('ignore')
import os,sys
path = os.path.split(os.path.abspath(os.path.realpath(sys.argv[0])))[0] + os.path.sep
rootpath = path[:-10]
#print("validation path:" ,root)
# MNIST Dataset
test_dataset = dsets.MNIST(root='./data/',
                           train=False,
                           transform=transforms.ToTensor(),
                           download=False)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                          batch_size=100,
                                          shuffle=True)
# CNN Model (2 conv layer)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
                                    nn.Conv2d(1, 16, kernel_size=5, padding=2),
                                    nn.BatchNorm2d(16),
                                    nn.ReLU(),
                                    nn.MaxPool2d(2))
        self.layer2 = nn.Sequential(
                                    nn.Conv2d(16, 32, kernel_size=5, padding=2),
                                    nn.BatchNorm2d(32),
                                    nn.ReLU(),
                                    nn.MaxPool2d(2))
        self.fc = nn.Linear(7*7*32, 10)
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.view(out.size(0), -1)
        out = self.fc(out)
        return out
cnnmodel = CNN()
#加载整个模型
cnnmodel = torch.load( rootpath + 'src/step3/cnnModel.pkl')
#/********** Begin *********/
# Change model to 'eval' mode
cnnmodel.eval()
correct = 0
total = 0
i = 0
for images, labels in test_loader:
    images = Variable(images)
    #对images 应用cnn模型,将结果赋值给 outputs
    outputs = cnnmodel(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum()
    i += 1
    # 为了节约时间, 我们测试时只测试前10个
    if  i> 10 :
        break
#输出正确率correct/total 的百分比
print('Test Accuracy of the model on the 200 test images: %d %%' % (100 * correct / total))
#/********** End *********/

讲实话很长时间没有更新博客了,学习还是得学会坚持,人一懒下来就完全不想再开始学习。希望自己未来还能坚持下去,冲!!!!!

欢乐的时光总是短暂的,让我们下一次再见!!!

good good study,day day up! (study hard, improve every day)

预知后事,请听下回分解!!!!

你可能感兴趣的:(机器学习,教学教程,pytorch,神经网络,深度学习)