Pytorch-Fashion MNIST Conjunto de datos Red neuronal convolucional Código de ejemplo Programa Entrenamiento Predicción Tasa de precisión 94 %

Contenido
1. Descarga de conjuntos de datos y mejora de datos

2. Observa las imágenes de Fashion mnist

3. Construye un modelo

4. Preparación antes del entrenamiento

5. Entrenamiento modelo

6. Análisis de resultados de predicción (matriz de confusión)

Siete, guarda el método del modelo.

1. Descarga de conjuntos de datos y mejora de datos

1. Llame a la biblioteca:

import copy
import os
from tqdm import tqdm
from time import time
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
from IPython import display

import torch 
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
from sklearn.metrics import confusion_matrix 

import torchvision
import torch.utils.data.dataloader as loader
import torch.utils.data as Dataset 
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils import data
from torchvision import models

2. Descarga de conjuntos de datos y mejora de datos

# 对训练集进行数据增强并通过ToTensor实例将图像数据从PIL类型变换tensor类型
transform = transforms.Compose(
    [
     transforms.RandomHorizontalFlip(),
     transforms.RandomGrayscale(),
     transforms.ToTensor(),
     transforms.Normalize((0.5,),(0.5,))])

transform1 = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5,),(0.5,))])


mnist_train = torchvision.datasets.FashionMNIST(
    root="data", train=True, transform=transform, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
    root="data", train=False, transform=transform1, download=True)

BATCH_SIZE = 100
trainloader =loader.DataLoader(mnist_train,batch_size = BATCH_SIZE,shuffle = True)
testloader =loader.DataLoader(mnist_test,batch_size = BATCH_SIZE,shuffle = False)

2. Observe la imagen del conjunto de datos:

"""返回Fashion-MNIST数据集的文本标签。"""
labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']

def show_images(imgs, num_rows, num_cols,targets,labels=None, scale=1.5):  
    """Plot a list of images."""
    figsize = (num_cols * scale, num_rows * scale)
    _, axes = plt.subplots(num_rows, num_cols, figsize=figsize)
    axes = axes.flatten()
    for ax, img,target in zip(axes, imgs,targets):
        if torch.is_tensor(img):
            # 图片张量
            ax.imshow(img.numpy())
        else:
            # PIL
            ax.imshow(img)
        # 设置坐标轴不可见
        ax.axes.get_xaxis().set_visible(False)
        ax.axes.get_yaxis().set_visible(False)
        plt.subplots_adjust(hspace = 0.35)
        if labels:
            ax.set_title('{}-'.format(target)+labels[target])
    return axes

# 将dataloader转换成迭代器才可以使用next方法
X, y = next(iter(data.DataLoader(mnist_train, batch_size=24,shuffle = True)))
show_images(X.reshape(24, 28, 28), 3, 8, labels=labels, targets = y)

3. Construye un modelo

1. Modelo 1: tres capas de convolución más dos capas de conexión completa, usando una capa de abandono

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv = nn.Sequential(
        nn.Conv2d(1,40,2),
        nn.ReLU(),
        nn.MaxPool2d(2,1),
        nn.Conv2d(40,80,2),
        nn.ReLU(),
        nn.MaxPool2d(2,1),
        nn.Conv2d(80,160,3,padding = 1),
        nn.ReLU(),
        nn.Dropout(p = 0.5),
        nn.MaxPool2d(3,3),)
        
        
        self.classifier = nn.Sequential(
        nn.Linear(160*8*8,200),
        nn.ReLU(),
#         nn.Linear(120,84),
#         nn.ReLU(),
#         nn.Linear(84,42),
#         nn.ReLU(),
        nn.Dropout(p = 0.5),
        nn.Linear(200,10))
        
        
    def forward(self,x):
        x = self.conv(x)
        x = x.view(x.size(0),-1)
        x = self.classifier(x)

        return x
       

2. Modelo 2: consulte el modelo vgg usando dos bloques vgg y dos conexiones completas, usando la normalización por lotes

# 训练30个epochs后测试集准确率高达93.8%
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv1 = nn.Conv2d(1,128,1,padding=1)
        self.conv2 = nn.Conv2d(128,128,3,padding=1)
        self.pool1 = nn.MaxPool2d(2, 2)
        self.bn1 = nn.BatchNorm2d(128)
        self.relu1 = nn.ReLU()

        self.conv3 = nn.Conv2d(128,256,3,padding=1)
        self.conv4 = nn.Conv2d(256, 256, 3,padding=1)
        self.pool2 = nn.MaxPool2d(2, 2, padding=1)
        self.bn2 = nn.BatchNorm2d(256)
        self.relu2 = nn.ReLU()

        self.fc5 = nn.Linear(256*8*8,512)
        self.drop1 = nn.Dropout2d()
        self.fc6 = nn.Linear(512,10)


    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.pool1(x)
        x = self.bn1(x)
        x = self.relu1(x)


        x = self.conv3(x)
        x = self.conv4(x)
        x = self.pool2(x)
        x = self.bn2(x)
        x = self.relu2(x)

        #print(" x shape ",x.size())
        x = x.view(-1,256*8*8)
        x = F.relu(self.fc5(x))
        x = self.drop1(x)
        x = self.fc6(x)
        return x

4. Preparación antes del entrenamiento:

1. Inicialización de la función del modelo

net =Net() # 模型初始化
loss = nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer = optim.Adam(net.parameters(),lr = 0.001) # 随机梯度下降优化算法
# xavier初始化
def init_xavier(model):
    for m in model.modules():
        if isinstance(m, (nn.Conv2d, nn.Linear)):
            nn.init.xavier_uniform_(m.weight, gain=nn.init.calculate_gain('relu'))
# 凯明初始化
def init_kaiming(model):
    for m in model.modules():
        if isinstance(m, (nn.Conv2d, nn.Linear)):
            nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')

init_kaiming(net)

2. Use GPU (la CPU se usa automáticamente si no)

"""使用GPU"""
def use_gpu(net):
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    net.to(device)
    gpu_nums = torch.cuda.device_count()
    if gpu_nums > 1:
        print("Let's use", gpu_nums, "GPUs")
        net = nn.DataParallel(net)
    elif gpu_nums == 1:
        print("Let's use GPU")
    else:
        print("Let's use CPU")
    return device 

3. Escriba la función auxiliar del programa de entrenamiento modelo

(1) Función de animación de efecto de entrenamiento visual

class Animator:  #@save
    """在动画中绘制数据。"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
                 ylim=None, xscale='linear', yscale='linear',
                 fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
                 figsize=(5, 3.5)):
        # 增量地绘制多条线
        if legend is None:
            legend = []
            
        # 使用矢量图
        display.set_matplotlib_formats('svg')
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使用lambda函数捕获、保存参数
        self.config_axes = lambda: self.set_axes(
            self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts

    def add(self, x, *y):
        # 向图表中添加多个数据点
        n = len(y)
        x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a, b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
                
        self.axes[0].cla() # 清除当前活动的axes
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt,linewidth = 2)
            
        self.axes[0].set_yticks(ticks = np.linspace(0,1,11))
        self.config_axes()
        display.display(self.fig)
        # 清除输出,使重画的图在原位置输出,形成动图效果
        display.clear_output(wait=True)  

    def set_axes(self,axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
        # 设置matplotlib的轴。\

        axes.grid(True)
        axes.set_title("gaojianwen")
        axes.set_xlabel(xlabel)
        axes.set_ylabel(ylabel)
        axes.set_xscale(xscale)
        axes.set_yscale(yscale)
        axes.set_xlim(xlim)
        axes.set_ylim(ylim)
        if legend:
            axes.legend(legend)

(2) Acumulador (almacenamiento de datos intermedios, como precisión, etc.)

class Accumulator:
    """定义累加器"""
    def __init__(self, n):
        self.data = [0.0 ] * n
        
    def add(self, *args):
        # 累加
        self.data = [a + float(b) for a, b in zip(self.data, args)]
        
    def reset(self):
        # 重置累加器
        self.data = [0.0] * len(self.data)
        
    def __getitem__(self,index):
        return  self.data[index]

5. Modelo de formación

def train_epoch(net, train_iter, loss, updater,device):
    """训练模型一个迭代周期"""
    # 将模型设置为训练模式
    if isinstance(net, torch.nn.Module):
        net.train()
    # metrix分别存储训练损失总和、训练准确数量总和、样本数
    metric = Accumulator(3)
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    for x, y in train_iter:
        x,y =x.to(device),y.to(device)
        updater.zero_grad()
        output = net(x)
        l = loss(output, y) # 计算损失,注意这里l为平均损失
        y_pred = torch.argmax(output,dim = 1) # 取出预测标签
        if isinstance(updater, torch.optim.Optimizer):
            # 使用PyTorch内置的优化器和损失函数
            l.backward()
            updater.step()
            metric.add(float(l) * len(y), (y_pred == y).sum(), y.numel())

    # 返回训练集损失和准确率
    return metric[0] / metric[2], metric[1] / metric[2]
def evaluate_accuracy(net, test_iter,loss,device):  
    """计算在指定数据集上模型的精度。"""
    if isinstance(net, torch.nn.Module):
        net.eval()  # 将模型设置为评估模式
    metric = Accumulator(3)  # 测试集损失、正确预测数、预测总数
    for x, y in test_iter:
        x,y = x.to(device),y.to(device)
        output = net(x)
        l = loss(output,y) #注意l为平均损失
        y_pred = torch.argmax(output,dim = -1)
        metric.add(float(l) * len(y),(y_pred == y).sum(), y.numel())
    # 返回测试集损失和准确率
    return metric[0] / metric[2], metric[1] / metric[2]
def train(net, train_iter, test_iter, loss, updater, epochs):  
    """训练模型"""
    device = use_gpu(net)
    global animator
    animator = Animator(xlabel='epoch', xlim=[0, epochs], ylim=[0, 1],
                        legend=['train loss', 'train acc', 'test loss', 'test acc'])
    net_list = []  # 用来保存每次epoch后的模型
    start = time() # 开始时间
    for epoch in range(epochs+1):
        if epoch == 0:
            # 第0次epoch不训练,计算初始随机准确率。
            train_loss,train_acc = evaluate_accuracy(net, train_iter, loss,device)
        else:    
            train_loss,train_acc = train_epoch(net, train_iter, loss, updater,device)
        # 计算在测试集上的损失(平均损失)和准确率
        test_loss, test_acc = evaluate_accuracy(net, test_iter,loss,device)
        animator.add(epoch, train_loss, train_acc, test_loss, test_acc)
        # 保存每次epoch后的模型参数
        net_list.append(net.state_dict())
    end = time() # 结束时间
    max_net_index = animator.Y[3].index(max(animator.Y[3])) # 在测试集上最高准确率所对应的索引
    print("总花费时长:{} 秒 \n每次epoch花费时长:{} 秒".format(end-start, (end-start) / epochs))
    print("训练集最高准确率为:{}%".format(max(animator.Y[1])*100))
    print("测试集最高准确率为:{}%(第{}epoch)".format(max(animator.Y[3])*100, max_net_index))
    
    # 返回测试集准确率最高时对应的模型
    net.load_state_dict(net_list[max_net_index])
    return net

max_net = train(net, trainloader, testloader, loss , optimizer,30)

        Usando el modelo 1 para el entrenamiento, el tiempo de entrenamiento es de media hora usando gpu (el número es 1), y el tiempo de entrenamiento es de aproximadamente cinco o seis horas para cpu, y la tasa de precisión en el conjunto de prueba alcanza el 94,15 %.

6. Análisis de resultados de predicción (matriz de confusión)

1. Escritura de la función de predicción

def predict(net,data,return_labels = False, labels = None):
    net.eval()
    with torch.no_grad():
        outputs = net(data)
        y_pred = outputs.argmax(axis = 1)
        if return_labels and labels != None:
            pred_labels = [labels[i] for i in y_pred]
            # 返回预测标签:语义标签
            return pred_labels
        # 返回预测标签:数字标签
        return y_pred.cpu()
    
def get_pred_targets(net,loader):
    pred_targets = np.array([])
    true_targets = np.array([])
    device = use_gpu(net)
    for data,targets in loader:
        pred_targets = np.hstack((pred_targets,predict(net.to(device),data.to(device))))
        true_targets = np.hstack((true_targets,targets))
    # 返回预测标签
    return (pred_targets, true_targets)

test_pred,test_true = get_pred_targets(max_net,testloader)

2. Matriz de confusión

labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
# 绘制混淆矩阵
def conf_mat_plot(y,y_pred,labels):
    fig = plt.figure(figsize = (8,5))
    ax = fig.add_subplot(111)
    conf_mat = confusion_matrix(y,y_pred)
    heatmap = sns.heatmap(conf_mat,annot=True,fmt ='d',cmap = "YlGnBu",xticklabels = labels,yticklabels=labels) #画热力图
    heatmap.xaxis.set_ticklabels(heatmap.xaxis.get_ticklabels(),rotation = 30)
    ax.set_title('confusion matrix',size = 20) #标题
    ax.set_xlabel('predict label') #x轴
    ax.set_ylabel('true label') #y轴
    plt.show()
conf_mat_plot(mnist_test.targets,test_pred,labels)

 7. Guarda el modelo

1. Guarde los parámetros del modelo: Nota: La estructura del modelo al extraer los parámetros debe coincidir

# 保存模型参数,注:提取参数时的net必须与保存的参数结构匹配
save_path = 'net_params.pkl'
torch.save(net.state_dict(),save_path)
# 提取参数
net.load_state_dict(torch.load(save_path))

2. Guarde el modelo:

# 保存整个模型
save_path = 'max_net.pkl'
torch.save(net,save_path)
# 提取
net_ = torch.load(save_path)

Supongo que te gusta

Origin blog.csdn.net/weixin_46707493/article/details/122624655
Recomendado
Clasificación