深度学习前沿应用图像分类Fine-Tuning

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习前沿应用图像分类Fine-Tuning相关的知识,希望对你有一定的参考价值。

【深度学习前沿应用】图像分类Fine-Tuning


(文章目录)


前言

1. 什么是预训练-微调模式?

在计算机视觉领域,预训练-微调模式已经沿用了多年,即在大规模图片数据集预训练模型参数,然后将训练好的参数在新的小数据集任务上进行微调,从而产生泛化性能更好的模型。


2. 什么是ResNet?

ResNet为常用的预训练模型之一,其核心操作为卷积与残差连接。卷积层为3×3的滤波器,并遵循两个简单的设计规则:①对于相同的输出特征图尺寸,每层具有相同数量的滤波器;②如果特征图尺寸减半,则滤波器数量加倍,以保持每层的时间复杂度。直接用步长为2的卷积层进行下采样,网络以全局平均池化层和伴随softmax的1000维全连接层结束,其中,卷积层数为34,因此也称为ResNet34(如下图1所示)。

本小节将使用ResNet34预训练-微调框架,实现猫脸12分类。对于给定的猫脸,判断其所属类型。


一、数据加载及预处理

本实验数据集来源于网络开源数据集(https://aistudio.baidu.com/aistudio/datasetdetail/10954),该数据集中包含12类猫图片,总计数据量为2160,部分图片展示如下图1所示。


(一)、数据加载及预处理

首先将该数据集挂载到当前项目中,然后读取数据文件,将数据按照8:2划分为训练集与验证集

  1. 导入相关包
import os
import time
import os.path as osp
import zipfile

import numpy as np
import paddle
import paddle.nn as nn
import pandas as pd
import paddle.nn.functional as F
from PIL import Image
from paddle.io import Dataset, DataLoader
from paddle.optimizer import Adam
from paddle.vision import Compose, ToTensor, Resize
from paddle.vision.models import resnet34
from paddle.metric import Accuracy
from sklearn.model_selection import StratifiedShuffleSplit

  1. 将train划分为训练集和验证集
info = pd.read_csv(osp.join(./data, train_list.txt), sep=\\t, header=None)
images, labels = info.iloc[:, 0], info.iloc[:, 1]
split = StratifiedShuffleSplit(test_size=0.2)
train_idx, valid_idx = next(split.split(images, labels))
info_tr = info.iloc[train_idx, :]
info_va = info.iloc[valid_idx, :]
info_tr.to_csv(data/train.csv, header=False, index=False)
info_va.to_csv(data/valid.csv, header=False, index=False)

(二)、数据集封装

class CatDataset(Dataset):
    train_file = cat_12_train.zip
    test_file = cat_12_test.zip
    train_label = train_list.txt

    def __init__(self, root, mode, transform=None):
        super(CatDataset, self).__init__()
        self.root = root
        self.mode = mode
        self.transform = transform

        if not osp.isfile(osp.join(root, self.train_file)) or \\
                not osp.isfile(osp.join(root, self.train_label)) or \\
                not osp.isfile(osp.join(root, self.test_file)):
            raise ValueError(wrong data path)
        if not osp.isdir(osp.join(self.root, cat_12_train)):
            with zipfile.ZipFile(osp.join(root, self.train_file)) as f:
                f.extractall(root)
            with zipfile.ZipFile(osp.join(root, self.test_file)) as f:
                f.extractall(root)
        if mode == train:
            info = pd.read_csv(osp.join(root, train_list.txt), sep=\\t, header=None)
            self.images = info.iloc[:, 0].to_list()
            self.labels = paddle.to_tensor(
                info.iloc[:, 1].to_list()
            )
        elif mode == train_:
            info = pd.read_csv(osp.join(root, train.csv), header=None)
            self.images = info.iloc[:, 0].to_list()
            self.labels = paddle.to_tensor(
                info.iloc[:, 1].to_list()
            )
            pass
        elif mode == valid_:
            info = pd.read_csv(osp.join(root, valid.csv), header=None)
            self.images = info.iloc[:, 0].to_list()
            self.labels = paddle.to_tensor(
                info.iloc[:, 1].to_list()
            )
        else:
            images = os.listdir(os.path.join(root, cat_12_test))
            self.images = [cat_12_test/+image for image in images]
            self.labels = None

    def __getitem__(self, idx):
        image = Image.open(osp.join(self.root, self.images[idx]))
        if image.mode != RGB:
            image = image.convert(RGB)
        if self.transform is not None:
            image = self.transform(image)
       
        if self.mode == test:
            return image,
        else:
            label = self.labels[idx]
            return image, label

    def __len__(self):
        return len(self.images)

(三)、样本分类与统计

paddle.set_device(gpu if paddle.is_compiled_with_cuda() else cpu)
transform = Compose([
    Resize([224, 224]),
    ToTensor()
])


train_ds = CatDataset(./data, train_, transform)
valid_ds = CatDataset(./data, valid_, transform)
train_dl = DataLoader(train_ds, batch_size=64, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=64, shuffle=False)
print(训练集样本数:,train_ds.__len__())
print(验证集样本数:,valid_ds.__len__())


二、预训练模型加载

paddle,vision是飞桨在视觉领域的高层API,内部封装了常用的数据集以及常用预测训练模型,如LeNet、VGG系列、ResNet系列及MobileNet系列等。本实验使用resnet34为例,演示如何进行图像分类的微调。

准备好数据集之后,加载预训练模型,调用net=resnet34(pretrained=True),设置参数pretrained为True,便可使用预训练好的参数,否则,需要从头开始训练参数(首次加载预训练参数时需要从相关专业网络中下载):


加载预训练模型,并设置类别数目为12(猫的分类)

net = resnet34(pretrained=True, num_classes=12)

三、模型微调

加载好预训练的模型之后,定义模型的优化器、评价指标等,输入领域数据,执行微调:

(一)、定义优化器

optimizer = Adam(
    parameters=net.parameters(),
    learning_rate=1e-5
)

(二)、定义损失函数

loss_fn = nn.CrossEntropyLoss()

(三)、定义准确率评价指标

metric_fn = Accuracy()

(四)、微调20轮

for epoch in range(20):
    t0 = time.time()
    net.train()
    for data, label in train_dl:
        logit = net(data)
        loss = loss_fn(logit, label.astype(int64))
        optimizer.clear_grad()
        loss.backward()
        optimizer.step() 
        
    # 验证  
    net.eval()
    loss_tr = 0.
    for data, label in train_dl:
        logit = net(data)
        label = label.astype(int64)
        loss_tr += loss_fn(logit, label).cpu().numpy()[0]
    loss_tr /= len(train_dl)

    loss_va = 0.
    for data, label in valid_dl:
        label = label.astype(int64)
        logit = net(data)
        loss_va += loss_fn(logit, label).cpu().numpy()[0]
        metric_fn.update(
            metric_fn.compute(logit, label)
        )
    loss_va /= len(valid_dl)
    acc_va = metric_fn.accumulate()
    metric_fn.reset()
    t = time.time() - t0
    print([Epoch :3d :.2fs] train loss(:.4f); valid loss(:.4f), acc(:.2f)
            .format(epoch, t, loss_tr, loss_va, acc_va))

训练过程部分输出如下图2所示:


四、模型预测

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
def show_image(file_name): 
    img = mpimg.imread(data/+file_name)
    plt.figure(figsize=(10,10))
    plt.imshow(img)  
    plt.show()


test_ds = CatDataset(./data, mode=test, transform=transform)
test_dl = DataLoader(test_ds, batch_size=32, shuffle=False)
test_pred = []
with paddle.no_grad():
    for data, in test_dl:
        logit = net(data)
        pred = paddle.argmax(
            F.softmax(logit, axis=-1),
            axis=-1
        )
        test_pred.append(pred.cpu().numpy())
test_pred = np.concatenate(test_pred, axis=0) 

for image, pred in zip(test_ds.images, test_pred.astype(np.int)):
    img = mpimg.imread(data/+image)
    plt.figure(figsize=(10,10))
    plt.imshow(img)  
    plt.show()
    print(图片路径:%s, 图片预测类型:%d\\n % (image.split(/)[1], pred))

预测结果部分输出如下图3、4、5、6所示


总结

本系列文章内容为根据清华社出版的《机器学习实践》所作的相关笔记和感悟,其中代码均为基于百度飞桨开发,若有任何侵权和不妥之处,请私信于我,定积极配合处理,看到必回!!!

最后,引用本次活动的一句话,来作为文章的结语~( ̄▽ ̄~)~:

【**学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。**】

以上是关于深度学习前沿应用图像分类Fine-Tuning的主要内容,如果未能解决你的问题,请参考以下文章

深度学习前沿应用图像分类Fine-Tuning

深度学习前沿应用文本分类Fine-Tunning

深度学习前沿应用图像风格迁移

深度学习前沿应用文本分类Fine-Tunning

深度学习前沿应用图像风格迁移

深度学习实验:Softmax实现手写数字识别