DataWhale10月“深入浅出PyTorch”Task04打卡

ps:本文记录参与Datawhale10月“深入浅出Pytorch”的学习笔记
pss:该教程的GitHub地址:深入浅出PyTorch
哔哩哔哩视频地址:深入浅出Pytorch

基础实战——FashionMNIST时装分类

以下内容根据DataWhale的教程基础实战——FashionMNIST时装分类撰写。

经过前面三章内容的学习,我们完成了以下的内容:

  • 对PyTorch有了初步的认识
  • 学会了如何安装PyTorch以及对应的编程环境
  • 学习了PyTorch最核心的理论基础(张量&自动求导) (并没有)
  • 梳理了利用PyTorch完成深度学习的主要步骤和对应实现方式 (并没有)
    现在,我们通过一个基础实战案例,将第一部分所涉及的PyTorch入门知识串起来,便于加深理解。同时为后续的进阶学习打好基础。

我们这里的任务是对10个类别的“时装”图像进行分类,使用FashionMNIST数据集(https://www.kaggle.com/zalando-research/fashionmnist?select=fashion-mnist_test.csv )。
FashionMNIST数据集中包含已经预先划分好的训练集和测试集,其中训练集共60,000张图像,测试集共10,000张图像。每张图像均为单通道黑白图像,大小为32*32pixel,分属10个类别。

导入必要的包

import os
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

配置训练环境和超参数

# 配置GPU,这里有两种方式
## 方案一:使用os.environ
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
# 方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可
#device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")

## 配置其他超参数,如batch_size, num_workers, learning rate, 以及总的epochs
batch_size = 256
num_workers = 4
lr = 1e-4
epochs = 20

数据读入和加载

这里介绍常见的有两种方式:

  • 下载并使用PyTorch提供的内置数据集
  • 从网站(例如kaggle)下载以csv格式存储的数据,读入并转成预期的格式

第一种数据读入方式只适用于常见的数据集,如MNIST,CIFAR10等,PyTorch官方提供了数据下载。这种方式往往适用于快速测试方法(比如测试下某个idea在MNIST数据集上是否有效)。
第二种数据读入方式需要自己构建Dataset,这对于PyTorch应用于自己的工作中十分重要。
同时,还需要对数据进行必要的变换,比如说需要将图片统一为一致的大小,以便后续能够输入网络训练;需要将数据格式转为Tensor类,等等。这些变换可以很方便地借助torchvision包来完成,这是PyTorch官方用于图像处理的工具库,上面提到的使用内置数据集的方式也要用到。

# 首先设置数据变换
from torchvision import transforms

image_size = 28
data_transform = transforms.Compose([
    transforms.ToPILImage(),   # 这一步取决于后续的数据读取方式,如果使用内置数据集则不需要
    transforms.Resize(image_size),
    transforms.ToTensor()
])

下载内置数据集方式

## 读取方式一:使用torchvision自带数据集,下载可能需要一段时间
from torchvision import datasets

train_data = datasets.FashionMNIST(root='./', train=True, download=True, transform=data_transform)
test_data = datasets.FashionMNIST(root='./', train=False, download=True, transform=data_transform)

自己转换的方式(本实验采用这种方式)

## 读取方式二:读入csv格式的数据,自行构建Dataset类
class FMDataset(Dataset):
    def __init__(self, df, transform=None):
        self.df = df
        self.transform = transform
        self.images = df.iloc[:,1:].values.astype(np.uint8)
        self.labels = df.iloc[:, 0].values
        
    def __len__(self):
        return len(self.images)
    
    def __getitem__(self, idx):
        image = self.images[idx].reshape(28,28,1)
        label = int(self.labels[idx])
        if self.transform is not None:
            image = self.transform(image)
        else:
            image = torch.tensor(image/255., dtype=torch.float)
        label = torch.tensor(label, dtype=torch.long)
        return image, label

train_df = pd.read_csv("./FashionMNIST/fashion-mnist_train.csv")#得先去kaggle上下载这两csv文件
test_df = pd.read_csv("./FashionMNIST/fashion-mnist_test.csv")
train_data = FMDataset(train_df, data_transform)
test_data = FMDataset(test_df, data_transform)

在构建训练和测试数据集完成后,需要定义DataLoader类,以便在训练和测试时加载数据

#将num_workers设为0不然会报错误 BrokenPipeError: [Errno 32] Broken pipe
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=0, drop_last=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=0)

读入后,我们可以做一些数据可视化操作,主要是验证我们读入的数据是否正确

import matplotlib.pyplot as plt
image, label = next(iter(train_loader))
print(image.shape, label.shape)
plt.imshow(image[0][0], cmap="gray")
plt.show()

输出结果:
在这里插入图片描述

模型设计

由于任务较为简单,这里我们手搭一个CNN,而不考虑当下各种模型的复杂结构
模型构建完成后,将模型放到GPU上用于训练(实验室办公机只有CPU,将相应出现Cuda的代码删去就好)

定义网络模型

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 32, 5),
            nn.ReLU(),
            nn.MaxPool2d(2, stride=2),
            nn.Dropout(0.3),
            nn.Conv2d(32, 64, 5),
            nn.ReLU(),
            nn.MaxPool2d(2, stride=2),
            nn.Dropout(0.3)
        )
        self.fc = nn.Sequential(
            nn.Linear(64*4*4, 512),
            nn.ReLU(),
            nn.Linear(512, 10)
        )
        
    def forward(self, x):
        x = self.conv(x)
        x = x.view(-1, 64*4*4)
        x = self.fc(x)
        # x = nn.functional.normalize(x)
        return x

model = Net()
#model = model.cuda() #有GPU可不去掉,只有集显就去掉
# model = nn.DataParallel(model).cuda()   # 多卡训练时的写法,之后的课程中会进一步讲解

设定损失函数

此处使用torch.nn模块自带的CrossEntropy损失
PyTorch会自动把整数型的label转为one-hot型,用于计算CE loss
这里需要确保label是从0开始的,同时模型不加softmax层(使用logits计算),这也说明了PyTorch训练中各个部分不是独立的,需要通盘考虑

criterion = nn.CrossEntropyLoss()
# criterion = nn.CrossEntropyLoss(weight=[1,1,1,1,3,1,1,1,1,1])

设定优化器

这里我们使用Adam优化器

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

训练和测试(验证)

各自封装成函数,方便后续调用,另外还需关注两者的主要区别

  • 模型状态设置
  • 是否需要初始化优化器
  • 是否需要将loss传回到网络
  • 是否需要每步更新optimizer
  • 此外,对于测试或验证过程,可以计算分类准确率
def train(epoch):
    model.train()
    train_loss = 0
    for data, label in train_loader:
    	#因为无GPU注释掉了这句
        # data, label = data.cuda(), label.cuda()
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, label)
        loss.backward()
        optimizer.step()
        train_loss += loss.item()*data.size(0)
    train_loss = train_loss/len(train_loader.dataset)
    print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))
def val(epoch):       
    model.eval()
    val_loss = 0
    gt_labels = []
    pred_labels = []
    with torch.no_grad():
        for data, label in test_loader:
        	#无GPU注释掉了该句
           # data, label = data.cuda(), label.cuda()
            output = model(data)
            preds = torch.argmax(output, 1)
            gt_labels.append(label.cpu().data.numpy())
            pred_labels.append(preds.cpu().data.numpy())
            loss = criterion(output, label)
            val_loss += loss.item()*data.size(0)
    val_loss = val_loss/len(test_loader.dataset)
    gt_labels, pred_labels = np.concatenate(gt_labels), np.concatenate(pred_labels)
    acc = np.sum(gt_labels==pred_labels)/len(pred_labels)
    print('Epoch: {} \tValidation Loss: {:.6f}, Accuracy: {:6f}'.format(epoch, val_loss, acc))
for epoch in range(1, epochs+1):
    train(epoch)
    val(epoch)

训练结果&验证结果

Epoch: 1 	Training Loss: 0.659075
Epoch: 1 	Validation Loss: 0.440650, Accuracy: 0.839600
Epoch: 2 	Training Loss: 0.413379
Epoch: 2 	Validation Loss: 0.340012, Accuracy: 0.877000
Epoch: 3 	Training Loss: 0.351616
Epoch: 3 	Validation Loss: 0.306806, Accuracy: 0.888400
Epoch: 4 	Training Loss: 0.321989
Epoch: 4 	Validation Loss: 0.294872, Accuracy: 0.886300
Epoch: 5 	Training Loss: 0.301666
Epoch: 5 	Validation Loss: 0.258970, Accuracy: 0.901900
Epoch: 6 	Training Loss: 0.285034
Epoch: 6 	Validation Loss: 0.280590, Accuracy: 0.894600
Epoch: 7 	Training Loss: 0.272261
Epoch: 7 	Validation Loss: 0.251542, Accuracy: 0.906300
Epoch: 8 	Training Loss: 0.258121
Epoch: 8 	Validation Loss: 0.238774, Accuracy: 0.911400
Epoch: 9 	Training Loss: 0.251401
Epoch: 9 	Validation Loss: 0.236957, Accuracy: 0.910900
Epoch: 10 	Training Loss: 0.237163
Epoch: 10 	Validation Loss: 0.229563, Accuracy: 0.915700
Epoch: 11 	Training Loss: 0.232615
Epoch: 11 	Validation Loss: 0.227246, Accuracy: 0.916000
Epoch: 12 	Training Loss: 0.225739
Epoch: 12 	Validation Loss: 0.218712, Accuracy: 0.918100
Epoch: 13 	Training Loss: 0.218604
Epoch: 13 	Validation Loss: 0.210563, Accuracy: 0.921800
Epoch: 14 	Training Loss: 0.212036
Epoch: 14 	Validation Loss: 0.217458, Accuracy: 0.916200
Epoch: 15 	Training Loss: 0.204831
Epoch: 15 	Validation Loss: 0.213358, Accuracy: 0.922700
Epoch: 16 	Training Loss: 0.199550
Epoch: 16 	Validation Loss: 0.207311, Accuracy: 0.924500
Epoch: 17 	Training Loss: 0.191927
Epoch: 17 	Validation Loss: 0.202918, Accuracy: 0.923200
Epoch: 18 	Training Loss: 0.184978
Epoch: 18 	Validation Loss: 0.204237, Accuracy: 0.926500
Epoch: 19 	Training Loss: 0.179726
Epoch: 19 	Validation Loss: 0.202566, Accuracy: 0.924700
Epoch: 20 	Training Loss: 0.176439
Epoch: 20 	Validation Loss: 0.200032, Accuracy: 0.925900

模型保存

训练完成后,可以使用torch.save保存模型参数或者整个模型,也可以在训练过程中保存模型

save_path = "./FahionModel.pkl"
torch.save(model, save_path)
#加载模型
model.load_state_dict(torch.load(save_path))
#开启评估模式 在评估模式下,batchNorm层,dropout层等用于优化训练而添加的网络层会被关闭,从而使得评估时不会发生偏移。
model.eval()
#想使用训练的模型来进行预测图,但还没写出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值