卷积神经网络(CNN)(下)

本文介绍了如何基于预训练的VGG16模型,利用PyTorch进行图像分类。首先导入预训练的VGG16模型并冻结其参数,然后在卷积层后添加新的全连接层以适应特定的10类猴子图像分类任务。数据集来自Kaggle,包括训练集和验证集,使用数据增强技术增强训练集,并对图像进行预处理。最终,使用DataLoader加载数据并可视化部分训练样本。
摘要由CSDN通过智能技术生成

深度卷积神经网络模型由于其层数多,需要训练的参数多,导致从零开始训练很深的卷积神经网络非常困难,同时训练很深的网络通畅需要大量的数据集,这对于设备算力不够的使用者非常不友好。幸运的是Pytorch已经提供了使用ImageNet数据集与与训练好的流行的深度学习网络,我们可以针对自己的需求,对与训练好的网络进行微调,从而快速完成自己的任务。

下面将会基于与训练好的VGG16网络,对其网络结构进行微调,使用自己的分类数据集,训练一个图像分类器。使用的数据集来自kaggle数据集中的10类猴子数据库,数据地址为https://www.kaggle.com/slothkong/10-money-species。在该数据集中包含训练数据集合验证数据集,其中训练数据集中每类约140张RGB图像,验证数据集中每类30张图像。针对该数据集使用VGG16的卷积层和池化层的预训练好的权重,提取数据特征,然后定义新的全连接层,用于图像的分类。

首先导入所需要的库和模块。

# import numpy as np
# import pandas as pd
# from sklearn.metrics import accuracy_score,confusion_matrix,classification_report
# import matplotlib.pyplot as plt
# import seaborn as sns
# import hiddenlayer as hl
# import torch
import torch.nn as nn
# from torch.optim import SGD,Adam
# import torch.utils.data as Data
from torchvision import models
# from torchvision import transforms
# from torchvision.datasets import ImageFolder

对于已经训练好的VGG16网络,需要首先导入网络。

vgg16=models.vgg16(pretrained=True)
vgg=vgg16.features
# for param in vgg.parameters():
#     param.requires_grad_(False)

在上面的程序中,使用models.vgg16(pretrained=True)导入网络,其中参数pretrained=True表示导入的网络是使用ImageNet数据集预训练好的网络(如果第一次使用该程序,需要一定时间从网络上下载模型)。在得到的VGG16网络中,使用vgg16.features获取VGG16网络的特征提取模块,即前面的卷积池化层,不包括全连接层。为了提升网络的训练速度,只是用VGG16提取图像的特征,需要将VGG16的特征提取层参数冻结,不更新其权重,通过for循环和param.requires_grad_(False)即可。

VGG特征提取层预处理结束后,可在VGG16特征提取层之后添加新的全连接层,用于图像分类,程序定义网络结构如下:

class MyVggModel(nn.Module):
    def __init__(self):
        super(MyVggModel,self).__init__()
        self.vgg=vgg
        self.classifier=nn.Sequential(
            nn.Linear(25088,512),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(512,256),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(256,10),
            nn.Softmax(dim=1)
        )
    def forward(self,x):
        x=self.vgg(x)
        x=x.view(x.size(0),-1)
        output=self.classifier(x)
        return output

在上面的程序中,定义了一个卷积神经网络类MyVggModel,在该网络中,包含两个大的结构,一个是self.vgg,使用预训练好的VGG16的特征提取并且其参数的权重已经冻结;另一个是self.classifier,由三个全连接层组成,并且神经元的个数分别为512,256,和10.在全连接层中使用ReLU函数作为激活函数,并通过nn.Dropout()层防止过拟合。在网络的前向传播函数中,有self.classifier得到输出。

可以通过下面的程序查看网络的详细结构。

Myvggc=MyVggModel()
print(Myvggc)

输出结果为:

在定义好卷积神经网络Myvggc后,下面需要对数据集进行准备。首先定义训练集和验证集的预处

理过程,程序如下:

train_data_transforms=transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])

])
val_data_transforms=transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])
])

上面的程序定义了对训练集的预处理过程train_data_transforms,从而对训练集进行数据增强,对验证集的预处理过程val_data_trabsforms与train_data_transforms会有一些差异,其不需要对图像进行随机翻转与随机裁剪操作。在对读入的单张图像进行预处理时,通过RandomResizedCrop()对图像进行随机裁剪,使用RandomHorizontalFlip()将图像依概率p=0.5水平翻转,通过Resize()充值图像分辨率,通过CenterCrop()将图像按照给定的尺寸从中心裁剪,通过Normalize()将他徐昂的像素值进行标准化处理等。

因为每类图像都分别保存在一个单独的文件夹中,所以可以使用ImageFolder()函数从文件中读取训练集和验证集,数据读取的程序如下:

train_data_dir="data/chap6/10-monkey-species/training"
train_data=ImageFolder(train_data_dir,transform=train_data_transforms)
train_data_loader=Data.DataLoader(train_data,batch_size=32,shuffle=True,num_workers=2)
val_data_dir="data/chap6/10-monkey-species/validation"
val_data=ImageFolder(val_data_dir,transform=val_data_transforms)
val_data_loader=Data.DataLoader(val_data,batch_size=32,shuffle=True,num_workers=2)
print("训练集样本数:",len(train_data.targets))
print("验证集样本数:",len(val_data.targets))

输出结果如下:

 上面的程序在读取图像后,分别使用Data.DataLoader()函数,将训练集和测试集处理为数据加载起train_data_loader和val_data_loader,并且每个batch包含32张图像。从输出结果发现,训练集有1097个样本,验证集有272个样本。下面我们获取训练集的一个batch图像,然后将获取的32张图像进行可视化,观察数据中图像的内容。

    for step,(b_x,b_y) in enumerate(train_data_loader):
        if step>0:
            break
    mean=np.array([0.485,0.456,0.406])
    std=np.array([0.229,0.224,0.225])
    plt.figure(figsize=(12,6))
    for ii in np.arange(len(b_y)):
        plt.subplot(4,8,ii+1)
        image=b_x[ii,:,:,:].numpy().transpose((1,2,0))
        image=std*image+mean
        image=np.clip(image,0,1)
        plt.imshow(image)
        plt.title(b_y[ii].data.numpy())
        plt.axis("off")
    plt.subplots_adjust(hspace=0.3)
    plt.show()

上面的程序在获取了一个batch图像后,再可视化前,需要将图像每个通道的像素值乘以对应的标准差并加上对应的均值。最后的图像如下:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mez_Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值