基于pytorch的BP神经网络模型构建

小伙伴好,最近想要认真学习一波pytorch,打算通过pytorch去构建一系列的网络模型,包括CNN、LSTM、Transform等,后续都会进行搭建。一个不断学习的小菜鸡,也希望有问题小伙伴能指出。

MINST数据集是手写数字的识别,图片尺寸为(28,28,1),标签为数字的类别。

基于pytorch的BP神经网络模型构建_第1张图片


 

1、加载数据

本文这次主要是对MNIST数据集进行测试。利用pytorch加载数据的方法如下:

# 利用datasets中可加载不同的数据集,本次选用MNIST数据集
from torchvision import datasets, transforms

batch_size = 128

# 加载数据
def load_data():
    # 下载数据
    train_data = datasets.MNIST(root='./data/',
                                train=True,
                                transform=transforms.ToTensor(),
                                download=True)

    test_data = datasets.MNIST(root='./data/',
                               train=False,
                               transform=transforms.ToTensor())

    # 返回一个数据迭代器
    # shuffle:是否打乱顺序
    train_loader = torch.utils.data.DataLoader(dataset=train_data,
                                               batch_size=batch_size,
                                               shuffle=True)

    test_loader = torch.utils.data.DataLoader(dataset=test_data,
                                               batch_size=batch_size,
                                               shuffle=False)
    print("Loaded Data successfully!")
    return train_loader, test_loader

获取数据的命令:

datasets.MNIST(root,train=True,transform=None,target_transform=None,download=False)

其中:

  1. root:数据集的根目录,如果已存在则直接加载,不存在则可设置download下载
  2. train:如果为True,则从training.pt创建数据集,否则从testing.pt创建数据集
  3. download: 如果为True,从互联网下载数据集,然后将其放在根目录中。 如果数据集已经存在则不会重复下载。
  4. transform:接受PIL图像并返回转换后版本的函数/转换。 例如transforms.ToTensor()(就是对图像数据进行处理,将类型转变为Tensor传入dataloader)
  5. target_transform:接受目标并对其进行转换的函数/转换。与上述相似。

数据分批加载:

torch.utils.data.DataLoader(dataset=train_data,batch_size=Config.batch_size,shuffle=True) 

主要实现对数据的加载,批次的数据量设置,是否打乱设置。一般训练集打乱,测试集不打乱。

如果是对自己的数据集处理,则dataset=自己的数据集,不需要使用上述加载MNIST数据集的流程。 

2、构建模型

这次主要使用BP神经网络构建,后续还会构建一些常见的CNN网络,如:LeNet、AlexNet、ResNet等进行构建。

本次构建主要包含输入层维度为28*28,输出层维度为10,隐藏层128。本次主要是对工具的使用进行介绍,小伙伴可以根据自己的需要构建网络,提高模型准确率等。

import torch
import torch.nn as nn


class BP(nn.Module):
    def __init__(self):
        super(BP, self).__init__()
        
        # 构建隐藏层
        self.fc1 = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU()
        )
        # 构建输出层
        self.fc2 = nn.Sequential(
            nn.Linear(128, 10),
            nn.Sigmoid()
        )

    def forward(self, x):
        # 将照片铺平为1维向量
        x = x.view(-1,784)
        x = self.fc1(x)
        x = self.fc2(x)
        return x


data = torch.randn(1,28,28)
net = BP()
outputs = net(data)
print(outputs.shape)

构建的模型输出维度为(1,10),10代表标签的类别数目

3、训练模型

选择合适的优化器,损失函数帮助我们的模型快速收敛,一般优化器选择Adam,SGD等效果较好,损失函数一般回归问题选择MSE,分类问题选择交叉熵损失。

# 选择损失为交叉熵损失
criterion = nn.CrossEntropyLoss()
# 选择优化器为Adam
optimizer = torch.optim.Adam()

对于一些参数的选择可以自行搜索

    def train_step(self):
        print("Training & Evaluating based on BP......")
        file = './result/raw_train_mnist.txt'
        fp = open(file,'w',encoding='utf-8')
        fp.write('epoch\tbatch\tloss\taccuracy\n')
        # 循环轮次
        for epoch in range(Config.epoch):
            # 显示当前轮
            print("Epoch {:3}.".format(epoch + 1))
            # 循环批次,每一批的数目当前设置128
            for batch_idx,(data, label) in enumerate(self.train):
                # 这里设置主要是我利用GPU训练,用cpu训练的可以忽略
                data, label = Variable(data.cuda()), Variable(label.cuda())
                
                # 优化器初始化
                self.optimizer.zero_grad()
                outputs = self.net(data)
                # 计算损失
                loss = self.criterion(outputs, label)
                loss.backward()
                # 进行优化计算
                self.optimizer.step()

                # 每100次打印一次结果
                if batch_idx % Config.print_per_step == 0:
                    # 每100批次计算当前准确率
                    _, predicted = torch.max(outputs, 1)
                    correct = 0
                    for _ in predicted == label:
                        if _:
                            correct += 1
                    accuracy = correct / Config.batch_size
                    msg = "Batch: {:5}, Loss: {:6.2f}, Accuracy: {:8.2%}."
                    # 输出准确率
                    print(msg.format(batch_idx, loss, accuracy))
                    fp.write('{}\t{}\t{}\t{}\n'.format(epoch,batch_idx,loss,accuracy))
        fp.close()
        test_loss = 0.
        test_correct = 0
        for data, label in self.test:
            data, label = Variable(data.cuda()), Variable(label.cuda())
            outputs = self.net(data)
            loss = self.criterion(outputs, label)
            test_loss += loss * Config.batch_size
            _, predicted = torch.max(outputs, 1)
            correct = int(sum(predicted == label))
            test_correct += correct

        accuracy = test_correct / len(self.test.dataset)
        loss = test_loss / len(self.test.dataset)
        print("Test Loss: {:5.2f}, Accuracy: {:6.2%}".format(loss, accuracy))
        torch.save(self.net.state_dict(),'./result/raw_train_mnist_model.pth')

4、整体代码以及模型训练

import torch
from torchvision import datasets, transforms
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import numpy as np


device = torch.device('cuda:0')


class Config:
    batch_size = 128
    epoch = 10
    alpha = 1e-3
    print_per_step = 100  # 控制输出


class BP(nn.Module):
    def __init__(self):
        super(BP, self).__init__()

        self.fc1 = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU()
        )

        self.fc2 = nn.Sequential(
            nn.Linear(128, 10),
            nn.Sigmoid()
        )

    def forward(self, x):
        x = x.view(-1,784)
        x = self.fc1(x)
        x = self.fc2(x)
        return x


class TrainProcess:

    def __init__(self):
        self.train, self.test = self.load_data()
        self.net = BP().to(device)
        self.criterion = nn.CrossEntropyLoss()  # 定义损失函数
        self.optimizer = optim.Adam(self.net.parameters(), lr=Config.alpha)

    @staticmethod
    def load_data():
        train_data = datasets.MNIST(root='./data/',
                                    train=True,
                                    transform=transforms.ToTensor(),
                                    download=True)

        test_data = datasets.MNIST(root='./data/',
                                   train=False,
                                   transform=transforms.ToTensor())

        # 返回一个数据迭代器
        # shuffle:是否打乱顺序
        train_loader = torch.utils.data.DataLoader(dataset=train_data,
                                                   batch_size=Config.batch_size,
                                                   shuffle=True)

        test_loader = torch.utils.data.DataLoader(dataset=test_data,
                                                  batch_size=Config.batch_size,
                                                  shuffle=False)
        return train_loader, test_loader

    def train_step(self):
        print("Training & Evaluating based on BP......")
        file = './result/raw_train_mnist.txt'
        fp = open(file,'w',encoding='utf-8')
        fp.write('epoch\tbatch\tloss\taccuracy\n')
        for epoch in range(Config.epoch):
            print("Epoch {:3}.".format(epoch + 1))
            for batch_idx,(data, label) in enumerate(self.train):
                data, label = Variable(data.cuda()), Variable(label.cuda())

                self.optimizer.zero_grad()
                outputs = self.net(data)
                loss = self.criterion(outputs, label)
                loss.backward()
                self.optimizer.step()

                # 每100次打印一次结果
                if batch_idx % Config.print_per_step == 0:
                    _, predicted = torch.max(outputs, 1)
                    correct = 0
                    for _ in predicted == label:
                        if _:
                            correct += 1
                    accuracy = correct / Config.batch_size
                    msg = "Batch: {:5}, Loss: {:6.2f}, Accuracy: {:8.2%}."
                    print(msg.format(batch_idx, loss, accuracy))
                    fp.write('{}\t{}\t{}\t{}\n'.format(epoch,batch_idx,loss,accuracy))
        fp.close()
        test_loss = 0.
        test_correct = 0
        for data, label in self.test:
            data, label = Variable(data.cuda()), Variable(label.cuda())
            outputs = self.net(data)
            loss = self.criterion(outputs, label)
            test_loss += loss * Config.batch_size
            _, predicted = torch.max(outputs, 1)
            correct = 0
            for _ in predicted == label:
                if _:
                    correct += 1
            test_correct += correct
        accuracy = test_correct / len(self.test.dataset)
        loss = test_loss / len(self.test.dataset)
        print("Test Loss: {:5.2f}, Accuracy: {:6.2%}".format(loss, accuracy))
        torch.save(self.net.state_dict(),'./result/raw_train_mnist_model.pth')


if __name__ == "__main__":
    p = TrainProcess()
    p.train_step()

训练结果:

Training & Evaluating based on BP......
Epoch   1.
Batch:     0, Loss:   2.31, Accuracy:   10.16%.
Batch:   100, Loss:   1.68, Accuracy:   83.59%.
Batch:   200, Loss:   1.60, Accuracy:   89.84%.
Batch:   300, Loss:   1.60, Accuracy:   85.94%.
Batch:   400, Loss:   1.55, Accuracy:   91.41%.
Epoch   2.
Batch:     0, Loss:   1.54, Accuracy:   91.41%.
Batch:   100, Loss:   1.56, Accuracy:   89.84%.
Batch:   200, Loss:   1.53, Accuracy:   91.41%.
Batch:   300, Loss:   1.56, Accuracy:   91.41%.
Batch:   400, Loss:   1.51, Accuracy:   96.09%.
Epoch   3.
Batch:     0, Loss:   1.50, Accuracy:   97.66%.
Batch:   100, Loss:   1.54, Accuracy:   92.19%.
Batch:   200, Loss:   1.52, Accuracy:   93.75%.
Batch:   300, Loss:   1.51, Accuracy:   95.31%.
Batch:   400, Loss:   1.53, Accuracy:   93.75%.
Epoch   4.
Batch:     0, Loss:   1.51, Accuracy:   94.53%.
Batch:   100, Loss:   1.50, Accuracy:   94.53%.
Batch:   200, Loss:   1.52, Accuracy:   95.31%.
Batch:   300, Loss:   1.53, Accuracy:   93.75%.
Batch:   400, Loss:   1.50, Accuracy:   96.88%.
Epoch   5.
Batch:     0, Loss:   1.49, Accuracy:   96.88%.
Batch:   100, Loss:   1.50, Accuracy:   96.09%.
Batch:   200, Loss:   1.50, Accuracy:   97.66%.
Batch:   300, Loss:   1.50, Accuracy:   93.75%.
Batch:   400, Loss:   1.50, Accuracy:   95.31%.
Epoch   6.
Batch:     0, Loss:   1.51, Accuracy:   96.88%.
Batch:   100, Loss:   1.51, Accuracy:   94.53%.
Batch:   200, Loss:   1.54, Accuracy:   92.97%.
Batch:   300, Loss:   1.48, Accuracy:   97.66%.
Batch:   400, Loss:   1.51, Accuracy:   96.09%.
Epoch   7.
Batch:     0, Loss:   1.50, Accuracy:   96.88%.
Batch:   100, Loss:   1.51, Accuracy:   95.31%.
Batch:   200, Loss:   1.49, Accuracy:   96.88%.
Batch:   300, Loss:   1.50, Accuracy:   94.53%.
Batch:   400, Loss:   1.49, Accuracy:   94.53%.
Epoch   8.
Batch:     0, Loss:   1.49, Accuracy:   96.88%.
Batch:   100, Loss:   1.49, Accuracy:   97.66%.
Batch:   200, Loss:   1.49, Accuracy:   96.88%.
Batch:   300, Loss:   1.51, Accuracy:   96.09%.
Batch:   400, Loss:   1.51, Accuracy:   96.88%.
Epoch   9.
Batch:     0, Loss:   1.49, Accuracy:   96.88%.
Batch:   100, Loss:   1.50, Accuracy:   95.31%.
Batch:   200, Loss:   1.49, Accuracy:   96.09%.
Batch:   300, Loss:   1.49, Accuracy:   96.09%.
Batch:   400, Loss:   1.49, Accuracy:   98.44%.
Epoch  10.
Batch:     0, Loss:   1.48, Accuracy:   97.66%.
Batch:   100, Loss:   1.48, Accuracy:   98.44%.
Batch:   200, Loss:   1.50, Accuracy:   95.31%.
Batch:   300, Loss:   1.49, Accuracy:   97.66%.
Batch:   400, Loss:   1.49, Accuracy:   97.66%.
Test Loss:  1.51, Accuracy: 97.02%

这里训练了10的epoch就可以达到97%,而且是非常简单的神经网络。希望可以帮助大家可以快速上手pytorch。

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