欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深度学习Fashion-MNIST:由简到繁的pytorch图像分类(一)

程序员文章站 2024-03-19 23:06:10
...

完整代码会附在文章末尾,建议使用anaconda安装pytorch,本文不再赘述。具体安装可参考此处

Fashion-MNIST数据集

Fashion-MNIST是Zalando文章图像的数据集-包含60,000个示例的训练集和10,000个示例的测试集。每个示例都是一个28x28灰度图像,与来自10个类别的标签相关联。Fashion-MNIST直接替代原始MNIST数据集,以对机器学习算法进行基准测试。它具有相同的图像大小以及训练和测试分割的结构。
在这里我们放上原项目的GitHub地址:

https://github.com/zalandoresearch/fashion-mnist
深度学习Fashion-MNIST:由简到繁的pytorch图像分类(一)
pytorch很贴心的将Fashion-MNIST数据集内置,所以我们只需要很简单的几行代码就能使用Fashion-MNIST数据集。

train_loader = torch.utils.data.DataLoader(
    datasets.FashionMNIST('./data', train=True, download=True,
                   transform=transforms.Compose([
                       transforms.Resize(32),  # resnet默认图片输入大小224*224
                       transforms.ToTensor(),
                       transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                   ])),
    batch_size=args.batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
    datasets.FashionMNIST('./data', train=False, transform=transforms.Compose([
        transforms.Resize(32),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])),
    batch_size=args.test_batch_size, shuffle=True)

最“单纯”的卷积神经网络

对卷积神经网络不了解的同学可以先阅读这篇文章
首先我们将需要的包导入:

# coding:utf8
import argparse  # 使得我们能够手动输入命令行参数,就是让风格变得和Linux命令行差不多
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms,models
from torch.autograd import Variable
from torchnet import meter
import random
import os
import torchvision
os.environ["CUDA_VISIBLE_DEVICES"] = "3"

其中os.environ[“CUDA_VISIBLE_DEVICES”] = "3"用来设置使用哪一张显卡。用cpu的朋友可以无视这一行

接下来我们搭建完全由卷积构成的分类网络,在读入数据的时候我们将已经图片resize成[32,32],通过四层卷积后得到256个channels[2,2]大小的特征,对于这个10分类任务我们只需要将输出向量展平以后再通过一个线性层Linear(256×2×2,10)和softmax/log_softmax即可
softmax与log_softmax的区别可以阅读此文章

卷积图片输出大小的计算公式:
假设输入图片大小 W×W,Filter大小 F×F,步长 S,padding的像素数 P。于是我们可以得出N = (W − F + 2P )/S+1
输出为N×N大小的图片

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #[32,32]
        self.conv1 = nn.Conv2d(1, 3, 4, 2, 1, bias=False)
        self.conv2 = nn.Conv2d(3, 64, 4, 2, 1, bias=False)
        self.conv3 = nn.Conv2d(64,128, 4, 2, 1, bias=False)
        self.conv4 = nn.Conv2d(128,256, 4, 2, 1, bias=False)
        self.fc1 = nn.Linear(256 * 2 * 2, 10)

    def forward(self, x):
        #[32,32]
        x = self.conv1(x)
        #[16,16]
        x = self.conv2(x)
        #[8,8]
        x = self.conv3(x)
        #[4,4]
        out = self.conv4(x)
        #[2,2]
        out = out.view(out.size(0), -1)
        out=self.fc1(out)
        return F.log_softmax(out, dim=1)


训练过程:

model = Net().cuda()

criterion = nn.NLLLoss()
if args.cuda:
    model.cuda()  # 判断是否调用GPU模式

#optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)  #

optimizer = optim.Adam(model.parameters(), lr=args.lr)

def train(epoch):  # 定义每个epoch的训练细节
    model.train()  # 设置为trainning模式
    for batch_idx, (data, target) in enumerate(train_loader):
        if args.cuda:  # 如果要调用GPU模式,就把数据转存到GPU
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data), Variable(target)  # 把数据转换成Variable
        optimizer.zero_grad()  # 优化器梯度初始化为零
        output = model(data)  # 把数据输入网络并得到输出,即进行前向传播
        loss = criterion(output, target)  # 计算损失函数
        loss.backward()  # 反向传播梯度
        optimizer.step()  # 结束一次前传+反传之后,更新优化器参数
        if batch_idx % args.log_interval == 0:  
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))

完整代码:

import argparse  # 使得我们能够手动输入命令行参数,就是让风格变得和Linux命令行差不多
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms,models
from torch.autograd import Variable
from torchnet import meter
import random
import os
import torchvision
os.environ["CUDA_VISIBLE_DEVICES"] = "3"
parser = argparse.ArgumentParser(description='PyTorch MNIST')
parser.add_argument('--batch-size', type=int, default=32, metavar='N',
                    help='input batch size for training (default: 32)')
parser.add_argument('--test-batch-size', type=int, default=10, metavar='N',
                    help='input batch size for testing (default: 10)')
parser.add_argument('--epochs', type=int, default=10, metavar='N',
                    help='number of epochs to train (default: 10)')
parser.add_argument('--lr', type=float, default=0.001, metavar='LR',
                    help='learning rate (default: 0.001)')
parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                    help='SGD momentum (default: 0.5)')
parser.add_argument('--no-cuda', action='store_true', default=False,  # GPU参数,默认为False
                    help='disables CUDA training')
parser.add_argument('--log-interval', type=int, default=10, metavar='N',  # 跑多少次batch进行一次日志记录
                    help='how many batches to wait before logging training status')


args = parser.parse_args()
args.cuda = not args.no_cuda and torch.cuda.is_available()
#使用pytorch内置的FashionMNIST数据集
train_loader = torch.utils.data.DataLoader(
    datasets.FashionMNIST('./data', train=True, download=True,
                   transform=transforms.Compose([
                       transforms.Resize(32),  # resnet默认图片输入大小224*224
                       transforms.ToTensor(),
                       transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                   ])),
    batch_size=args.batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
    datasets.FashionMNIST('./data', train=False, transform=transforms.Compose([
        transforms.Resize(32),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])),
    batch_size=args.test_batch_size, shuffle=True)


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #[32,32]
        self.conv1 = nn.Conv2d(1, 3, 4, 2, 1, bias=False)
        self.conv2 = nn.Conv2d(3, 64, 4, 2, 1, bias=False)
        self.conv3 = nn.Conv2d(64,128, 4, 2, 1, bias=False)
        self.conv4 = nn.Conv2d(128,256, 4, 2, 1, bias=False)
        self.fc1 = nn.Linear(256 * 2 * 2, 10)

    def forward(self, x):
        #[32,32]
        x = self.conv1(x)
        #[16,16]
        x = self.conv2(x)
        #[8,8]
        x = self.conv3(x)
        #[4,4]
        out = self.conv4(x)
        #[2,2]
        out = out.view(out.size(0), -1)
        out=self.fc1(out)
        return F.log_softmax(out, dim=1)

model = Net().cuda()

criterion = nn.NLLLoss()
if args.cuda:
    model.cuda()  # 判断是否调用GPU模式

#optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)  #

optimizer = optim.Adam(model.parameters(), lr=args.lr)

def train(epoch):  # 定义每个epoch的训练细节
    model.train()  # 设置为trainning模式
    for batch_idx, (data, target) in enumerate(train_loader):
        if args.cuda:  # 如果要调用GPU模式,就把数据转存到GPU
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data), Variable(target)  # 把数据转换成Variable
        optimizer.zero_grad()  # 优化器梯度初始化为零
        output = model(data)  # 把数据输入网络并得到输出,即进行前向传播
        loss = criterion(output, target)  # 计算损失函数
        loss.backward()  # 反向传播梯度
        optimizer.step()  # 结束一次前传+反传之后,更新优化器参数
        if batch_idx % args.log_interval == 0:  
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))
MAX=0
for epoch in range(1, args.epochs + 1):  # 以epoch为单位进行循环
    train(epoch)
    model.eval()  # 设置为test模式
    test_loss = 0  # 初始化测试损失值为0
    correct = 0  # 初始化预测正确的数据个数为0
    confusion_matrix = meter.ConfusionMeter(10)
    for data, target in test_loader:
        if args.cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data), Variable(target)
        output = model(data)
        test_loss += F.nll_loss(output, target, size_average=False).item()  # sum up batch loss 把所有loss值进行累加
        pred = output.data.max(1, keepdim=True)[1]  # get the index of the max log-probability
        correct += pred.eq(target.data.view_as(pred)).cpu().sum()  # 对预测正确的数据个数进行累加
    MAX=max(MAX,correct)
    print(MAX)#最好的正确率
    test_loss /= len(test_loader.dataset) 
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))