三、基础实战FashionMNIST时装分类——pytorch学习

使用FashionMNIST数据集, 对10个类别的“时装”图像进行分类,数据集中的样例图如下,其中每个小图对应一个样本。数据集中包含已经预先划分好的训练集和测试集,其中训练集共60,000张图像,测试集共10,000张图像。每张图像均为单通道黑白图像,大小为28*28pixel,分属10个类别。

fashion-mnist

本次学习的内容将按照一个完整的深度学习流程进行,主要步骤如下:

  • 首先导入基础的包
  • 配置训练环境和超参数
  • 数据读入和加载
  • 数据可视化查看,确认数据读入无误
  • 构建模型
  • 训练函数和验证函数封装
  • 训练模型,查看训练集和验证集loss,准确率
  • 保存模型

1.导入基础的包

# 1.导入基础的包
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
  1. 配置GPU
    由于自己的电脑是cpu,没有gpu,所以这里的gpu的内容注释掉了
# 2. 配置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 =128
num_workers = 0   # 对于Windows用户,这里应设置为0,否则会出现多线程错误
lr = 1e-4
epochs = 20
  1. 首先设置数据变换
# 3. 首先设置数据变换
from torchvision import transforms

image_size = 28
data_transform = transforms.Compose([
    transforms.ToPILImage(),  
     # 这一步取决于后续的数据读取方式,如果使用内置数据集读取方式则不需要
    transforms.Resize(image_size),
    transforms.ToTensor()
])
  1. 数据读取,构建dataset类
## 读取方式一:使用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)

## 4. 读取方式二:读入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('/Users/anker/Desktop/python_code/datasets/fashionMNIST/fashion-mnist_train.csv')
test_df = pd.read_csv('/Users/anker/Desktop/python_code/datasets/fashionMNIST/fashion-mnist_test.csv')
# 按dataset构建训练集和测试集
train_data = FMDataset(train_df, data_transform)
test_data = FMDataset(test_df, data_transform)
# 定义DataLoader类,以便在训练和测试时加载数据
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=num_workers, drop_last=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=num_workers)

5.对读入的数据进行可视化,验证读入数据是否准确

# 5.对读入的数据进行可视化,验证读入数据是否准确
%matplotlib inline
import matplotlib.pyplot as plt
image, label = next(iter(train_loader))
print(image.shape, label.shape)
print(label[0])
plt.imshow(image[0][0], cmap='gray')
# 输出
torch.Size([128, 1, 28, 28]) torch.Size([128])
tensor(2)
示例.png
  1. 模型设计
# 6. 模型设计,由于任务较为简单,这里我们手搭一个CNN,而不考虑当下各种模型的复杂结构,模型构建完成后,将模型放到GPU上用于训练。
from turtle import forward


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()  # 实现模型从cpu到gpu的迁移
# model = nn.DataParallel(model).cuda()   # 多卡训练时的写法
  1. 设定损失函数
# 7. 设定损失函数,
# 使用torch.nn模块自带的CrossEntropy损失
# PyTorch会自动把整数型的label转为one-hot型,用于计算CE loss
# 这里需要确保label是从0开始的,同时模型不加softmax层(使用logits计算),这也说明了PyTorch训练中各个部分不是独立的,需要通盘考虑
criterion = nn.CrossEntropyLoss()
  1. 设定优化器
# 8. 设定优化器(对反向传播及梯度管理),常使用的是Adam优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
  1. 对训练函数和测试分别封装成函数
# 9. 对训练函数和测试分别封装成函数,方便后续调用
# 训练和测试的主要区别在于:1.模型状态的设置 2.是否需要初始优化器 3.是否需要将loss传回网络  4.是否需要每步更新optimizer
# 测试或验证可以计算分类的准确率
def train(epoch):
    model.train()
    train_loss = 0
    for data, label in train_loader:
        # data, label = data.cuda(), label.cuda()       # 将数据放到gpu
        # 清零梯度
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, label)     # 计算loss
        loss.backward()                     # 反向传播
        optimizer.step()                    # 参数更新
        train_loss = train_loss + loss.item() * data.size(0)

    train_loss = train_loss / len(train_loader.dataset)
    print('epoch: {}\t training 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:
            # data, label = data.cuda(), label.cuda()       # 将数据放到gpu
            output = model(data)
            preds = torch.argmax(output, 1)
            # gt_labels.append(label.cuda().data.numpy())       # 将数据从gpu中拿出来
            gt_labels.append(label.cpu().data.numpy())          # 将数据从cpu中拿出来,存储起来
            pred_labels.append(preds.cpu().data.numpy())
            # 计算loss
            loss = criterion(output, label)                 
            val_loss = 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:{}\t Calidation loss: {:.6f}, Accuracy:{:.6f}'.format(epoch, val_loss, acc))

#验证代码是否正确
# val(1)
  1. 训练模型,查看loss
# 10. 训练模型,查看loss
from pathlib import Path
import os
for epoch in range(1, epochs): 
    train(epoch)
    val(epoch)
    # 模型保存
    save_path = Path('./FahionModel_' + str(epoch) +  '.pkl')
    torch.save(model, save_path)
    print('model saved {}'.format(save_path))

# 输出,这里只训练了10个epoch
epoch: 1         training loss: 0.669471
epoch: 1         Calidation loss: 0.463060, Accuracy: 0.834800
model saved as Fashion_model_1.pkl
epoch: 2         training loss: 0.436001
epoch: 2         Calidation loss: 0.365704, Accuracy: 0.868500
model saved as Fashion_model_2.pkl
epoch: 3         training loss: 0.371728
epoch: 3         Calidation loss: 0.321203, Accuracy: 0.883000
model saved as Fashion_model_3.pkl
epoch: 4         training loss: 0.336750
epoch: 4         Calidation loss: 0.286281, Accuracy: 0.894400
model saved as Fashion_model_4.pkl
epoch: 5         training loss: 0.315759
epoch: 5         Calidation loss: 0.287050, Accuracy: 0.897600
model saved as Fashion_model_5.pkl
epoch: 6         training loss: 0.297339
epoch: 6         Calidation loss: 0.262994, Accuracy: 0.905900
model saved as Fashion_model_6.pkl
epoch: 7         training loss: 0.282930
epoch: 7         Calidation loss: 0.248433, Accuracy: 0.909600
model saved as Fashion_model_7.pkl
epoch: 8         training loss: 0.267312
epoch: 8         Calidation loss: 0.240321, Accuracy: 0.912300
model saved as Fashion_model_8.pkl
epoch: 9         training loss: 0.256241
epoch: 9         Calidation loss: 0.235803, Accuracy: 0.912100
model saved as Fashion_model_9.pkl
epoch: 10        training loss: 0.246015
epoch: 10        Calidation loss: 0.243302, Accuracy: 0.910300
model saved as Fashion_model_10.pkl

以上就是一个深度学习模型的完整训练过程,实际在工程中还会有推理的部分,后续再说明。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容