AlexNet分类Fashion-MNIST(Pytorch实现)

这个notebook也同时发表在Kaggle

Fashion MNIST数据集

Label Class
0 T-shirt/top
1 Trouser
2 Pullover
3 Dress
4 Coat
5 Sandal
6 Shirt
7 Sneaker
8 Bag
9 Ankle boot

准备工作

import os
import torch
import torch.nn.functional as F
import torch.nn as nn
import torch.optim as optim
import numpy as np
import pandas as pd
from PIL import Image
import matplotlib.pyplot as plt
from torchvision import transforms, datasets
from torch.utils.data import Dataset, DataLoader


EPOCHS = 20
BATCH_SIZE = 512
DEVICE = ("cuda" if torch.cuda.is_available() else "cpu")
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

print(torch.__version__)
print(DEVICE)
1.4.0
cuda

加载数据

有两种方式来加载 Fashion-MNIST dataset:

  • 使用官方在 datasets.FashionMNIST给出的数据集
  • 使用下载的原始csv数据集

在这里我们选择第二种,因此需要建立我们自己的 dataset

首先 ,用pd.read_csv导入'.csv' 文件

train_csv = pd.read_csv('/content/fashion-mnist_train.csv')
test_csv = pd.read_csv('/content/fashion-mnist_test.csv')

print(train_csv.shape)
print(test_csv.shape)
(60000, 785)
(10000, 785)
print(train_csv.info())
print(train_csv.head())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 60000 entries, 0 to 59999
Columns: 785 entries, label to pixel784
dtypes: int64(785)
memory usage: 359.3 MB
None
   label  pixel1  pixel2  pixel3  ...  pixel781  pixel782  pixel783  pixel784
0      2       0       0       0  ...         0         0         0         0
1      9       0       0       0  ...         0         0         0         0
2      6       0       0       0  ...         0         0         0         0
3      0       0       0       0  ...         0         0         0         0
4      3       0       0       0  ...         0         0         0         0

[5 rows x 785 columns]

根据输出可知,第一列是每个图像的label,而每个图像由784个像素组成

建立Dataset

关于Dataset的有关内容在这里提到过

我们需要建立一个继承自Dataset的类,其中必须定义函数get_item() & len()

  • get_item() 返回指定图像和label
  • len() 返回数据集中数据数量
# 创建自己的Dataset
class FashionDataset(Dataset):
    def __init__(self, data, transform=None):       
        self.fashion_MNIST = list(data.values)
        self.transform = transform
        
        label, image = [], []
        
        for i in self.fashion_MNIST:
            label.append(i[0])
            image.append(i[1:])
        self.labels = np.asarray(label)
        self.images = np.asarray(image).reshape(-1, 28, 28).astype('float32')
        
    def __len__(self):
        return len(self.images)
    
    def __getitem__(self, idx):
        # 返回指定行数据
        label = self.labels[idx]
        image = self.images[idx]        
        
        if self.transform is not None:
            # 转换成PIL
            pil_image = Image.fromarray(np.uint8(image)) 
            image = self.transform(pil_image)
            
        return image, label

Transform

Transform有关的内容也在之前的blog中介绍过:blog:PYTORCH_TORCHVISION

我们打算使用AlexNet进行训练,AlexNet输入size为227*227,而Fashion-MNIST默认为28*28,故我们需要在transform中对image进行resize

AlexTransform = transforms.Compose([
    transforms.Resize((227, 227)),
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

DataLoader

train_loader = DataLoader(
    FashionDataset(train_csv, transform=AlexTransform), 
    batch_size=BATCH_SIZE, shuffle=True)

test_loader = DataLoader(
    FashionDataset(test_csv, transform=AlexTransform), 
    batch_size=BATCH_SIZE, shuffle=True)

查看图像

这一步阔以略过,只是看看我们数据集中的图像罢了

def matplotlib_imshow(img):
    img = img.mean(dim=0)
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(npimg, cmap="Greys")


dataiter = iter(train_loader)
images, labels = dataiter.next()


img_grid = torchvision.utils.make_grid(images[0])


matplotlib_imshow(img_grid)
print(class_names[labels[0]])
T-shirt/top

定义Net

AlexNet网络的相关介绍可以在这篇文章:卷积神经网络CNN以及几种经典模型中找到

class fasion_mnist_alexnet(nn.Module):  # 选用AlexNet网络
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=96, kernel_size=11, stride=4, padding=0),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU()
        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU()
        )
        self.conv5 = nn.Sequential(
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )

        self.fc1 = nn.Linear(256 * 6 * 6, 4096)
        self.fc2 = nn.Linear(4096, 4096)
        self.fc3 = nn.Linear(4096, 10)

    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        out = self.conv3(out)
        out = self.conv4(out)
        out = self.conv5(out)
        out = out.view(out.size(0), -1)

        out = F.relu(self.fc1(out))  # 256*6*6 -> 4096
        out = F.dropout(out, 0.5)
        out = F.relu(self.fc2(out))
        out = F.dropout(out, 0.5)
        out = self.fc3(out)
        out = F.log_softmax(out, dim=1)

        return out

实例化Model

model = fasion_mnist_alexnet().to(DEVICE)
criterion = F.nll_loss
optimizer = optim.Adam(model.parameters())

训练函数

def train(model, device, train_loader, optimer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        target = target.type(torch.LongTensor)
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        if (batch_idx + 1) % 30 == 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()))

测试函数


def test(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += criterion(output, target, reduction='sum').item()
            pred = output.max(1, keepdim=True)[1]
            correct += pred.eq(target.view_as(pred)).sum().item()

        test_loss /= len(test_loader.dataset)  # loss之和除以data数量 -> mean
        print("\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n".format(
            test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset)))
        print('='*50)

开始训练

for epoch in range(1, EPOCHS+1):
    train(model, DEVICE, train_loader, optimizer, epoch)
    test(model, DEVICE, test_loader)
Train Epoch:1 [14848/60000 (25%)]	Loss: 0.877214
Train Epoch:1 [30208/60000 (50%)]	Loss: 0.644841
Train Epoch:1 [45568/60000 (75%)]	Loss: 0.532848

Test set: Average loss: 0.4413, Accuracy: 8316/10000 (83%)

==================================================
Train Epoch:2 [14848/60000 (25%)]	Loss: 0.433440
Train Epoch:2 [30208/60000 (50%)]	Loss: 0.360927
Train Epoch:2 [45568/60000 (75%)]	Loss: 0.368575

Test set: Average loss: 0.3194, Accuracy: 8838/10000 (88%)

==================================================
Train Epoch:3 [14848/60000 (25%)]	Loss: 0.308415
Train Epoch:3 [30208/60000 (50%)]	Loss: 0.224128
Train Epoch:3 [45568/60000 (75%)]	Loss: 0.245119

Test set: Average loss: 0.2992, Accuracy: 8995/10000 (90%)

==================================================
Train Epoch:4 [14848/60000 (25%)]	Loss: 0.272408
Train Epoch:4 [30208/60000 (50%)]	Loss: 0.226366
Train Epoch:4 [45568/60000 (75%)]	Loss: 0.274030

Test set: Average loss: 0.2753, Accuracy: 8973/10000 (90%)

==================================================
Train Epoch:5 [14848/60000 (25%)]	Loss: 0.224429
Train Epoch:5 [30208/60000 (50%)]	Loss: 0.237268
Train Epoch:5 [45568/60000 (75%)]	Loss: 0.280958

Test set: Average loss: 0.2686, Accuracy: 9082/10000 (91%)

==================================================
Train Epoch:6 [14848/60000 (25%)]	Loss: 0.217329
Train Epoch:6 [30208/60000 (50%)]	Loss: 0.258806
Train Epoch:6 [45568/60000 (75%)]	Loss: 0.179489

Test set: Average loss: 0.2273, Accuracy: 9180/10000 (92%)

==================================================
Train Epoch:7 [14848/60000 (25%)]	Loss: 0.232198
Train Epoch:7 [30208/60000 (50%)]	Loss: 0.193284
Train Epoch:7 [45568/60000 (75%)]	Loss: 0.180621

Test set: Average loss: 0.2556, Accuracy: 9073/10000 (91%)

==================================================
Train Epoch:8 [14848/60000 (25%)]	Loss: 0.202838
Train Epoch:8 [30208/60000 (50%)]	Loss: 0.177613
Train Epoch:8 [45568/60000 (75%)]	Loss: 0.166227

Test set: Average loss: 0.2537, Accuracy: 9090/10000 (91%)

==================================================
Train Epoch:9 [14848/60000 (25%)]	Loss: 0.191794
Train Epoch:9 [30208/60000 (50%)]	Loss: 0.179932
Train Epoch:9 [45568/60000 (75%)]	Loss: 0.157028

Test set: Average loss: 0.2236, Accuracy: 9181/10000 (92%)

==================================================
Train Epoch:10 [14848/60000 (25%)]	Loss: 0.201635
Train Epoch:10 [30208/60000 (50%)]	Loss: 0.193036
Train Epoch:10 [45568/60000 (75%)]	Loss: 0.133806

Test set: Average loss: 0.2228, Accuracy: 9207/10000 (92%)

==================================================
Train Epoch:11 [14848/60000 (25%)]	Loss: 0.140554
Train Epoch:11 [30208/60000 (50%)]	Loss: 0.195291
Train Epoch:11 [45568/60000 (75%)]	Loss: 0.167740

Test set: Average loss: 0.2298, Accuracy: 9169/10000 (92%)

==================================================
Train Epoch:12 [14848/60000 (25%)]	Loss: 0.145187
Train Epoch:12 [30208/60000 (50%)]	Loss: 0.136410
Train Epoch:12 [45568/60000 (75%)]	Loss: 0.148455

Test set: Average loss: 0.2208, Accuracy: 9244/10000 (92%)

==================================================
Train Epoch:13 [14848/60000 (25%)]	Loss: 0.102129
Train Epoch:13 [30208/60000 (50%)]	Loss: 0.119473
Train Epoch:13 [45568/60000 (75%)]	Loss: 0.151384

Test set: Average loss: 0.2176, Accuracy: 9245/10000 (92%)

==================================================
Train Epoch:14 [14848/60000 (25%)]	Loss: 0.085864
Train Epoch:14 [30208/60000 (50%)]	Loss: 0.161960
Train Epoch:14 [45568/60000 (75%)]	Loss: 0.173307

Test set: Average loss: 0.2276, Accuracy: 9210/10000 (92%)

==================================================
Train Epoch:15 [14848/60000 (25%)]	Loss: 0.158055
Train Epoch:15 [30208/60000 (50%)]	Loss: 0.164117
Train Epoch:15 [45568/60000 (75%)]	Loss: 0.119916

Test set: Average loss: 0.2236, Accuracy: 9236/10000 (92%)

==================================================
Train Epoch:16 [14848/60000 (25%)]	Loss: 0.120705
Train Epoch:16 [30208/60000 (50%)]	Loss: 0.138526
Train Epoch:16 [45568/60000 (75%)]	Loss: 0.132989

Test set: Average loss: 0.2330, Accuracy: 9241/10000 (92%)

==================================================
Train Epoch:17 [14848/60000 (25%)]	Loss: 0.082980
Train Epoch:17 [30208/60000 (50%)]	Loss: 0.142380
Train Epoch:17 [45568/60000 (75%)]	Loss: 0.088001

Test set: Average loss: 0.2495, Accuracy: 9213/10000 (92%)

==================================================
Train Epoch:18 [14848/60000 (25%)]	Loss: 0.106110
Train Epoch:18 [30208/60000 (50%)]	Loss: 0.121420
Train Epoch:18 [45568/60000 (75%)]	Loss: 0.102312

Test set: Average loss: 0.2547, Accuracy: 9251/10000 (93%)

==================================================
Train Epoch:19 [14848/60000 (25%)]	Loss: 0.118317
Train Epoch:19 [30208/60000 (50%)]	Loss: 0.113046
Train Epoch:19 [45568/60000 (75%)]	Loss: 0.085053

Test set: Average loss: 0.2661, Accuracy: 9213/10000 (92%)

==================================================
Train Epoch:20 [14848/60000 (25%)]	Loss: 0.103729
Train Epoch:20 [30208/60000 (50%)]	Loss: 0.049429
Train Epoch:20 [45568/60000 (75%)]	Loss: 0.109371

Test set: Average loss: 0.2729, Accuracy: 9230/10000 (92%)

==================================================

可见当进行10次训练后,我们模型的准确率就稳定在了92%,所以想要继续提升准确率就需要对模型进行改进

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus