AlexNet网络搭建

AlexNet网络模型搭建

环境准备

首先在某个盘符下创建一个文件夹,就叫AlexNet吧,用来存放源代码。

然后新建一个python文件,就叫plot.py吧,往里面写入以下代码,用于下载数据集:

# FashionMNIST里面包含了许多数据集
from click.core import batch
from spacy.cli.train import train
from torchvision.datasets import FashionMNIST
from torchvision import transforms # 处理数据集,归一化
import torch.utils.data as Data
import numpy as np
import matplotlib.pyplot as plt


# 下载FashionMMIST数据集
train_data = FashionMNIST(
    root="./data", # 指定数据集要下载的路径
    train=True,# 要训练集
    # 将数据进行归一化操作
    transform=transforms.Compose([
        transforms.Resize(size=224), # 调整数据的大小
        transforms.ToTensor() # 将数据转换为tensor
    ]),
    download=True # 开启下载
)

# 加载数据集集
train_loader = Data.DataLoader(
    dataset=train_data,# 要加载的数据集
    batch_size=64 ,# 批量数据大小
    shuffle=True, # 打乱数据顺序
    num_workers=0, # 加载数据线程数量
)

# 绘制出训练集
for step,(b_x,b_y) in enumerate(train_loader):
    if step > 0:
        break
    batch_x = b_x.squeeze().numpy() # 将四维张量移除第一维,将数据转换为numpy格式
    batch_y = b_y.numpy() # 将张量数据转成numpy格式
    class_label = train_data.classes # 训练集标签
print("class_label,",class_label)

# 绘图
plt.figure(figsize=(12,5))
for ii in np.arange(len(batch_y)):
    plt.subplot(4,16,ii+1)
    plt.imshow(batch_x[ii, : , :],cmap=plt.cm.gray)
    plt.title(class_label[batch_y[ii]],size=10)
    plt.axis('off')
    plt.subplots_adjust(wspace=0.05)

plt.show()

执行上述代码后,就会开始下载所需要的数据集文件,只不过下载的速度比较慢,然后下载完成,项目的根目录会多出data文件夹,以下是data的目录结构:

--data
  --FashionMNIST
    --raw # 该文件夹下就存放数据集文件

搭建网络模型

创建model.py文件,用于构建模型代码。

import torch
from torch import nn  # nn层
from torchsummary import summary  # 查看网络模型参数
import torch.nn.functional as F  # 用于dropout


# 搭建模型
class AlexNet(nn.Module):
    def __init__(self):
        # 初始化网络层
        super(AlexNet, self).__init__()
        self.ReLU = nn.ReLU()  # ReLU 激活函数
        # kernel_size=11 : 卷积核大小 11*11
        self.c1 = nn.Conv2d(in_channels=1, out_channels=96, kernel_size=11, stride=4)  # 第一层:卷积
        self.s2 = nn.MaxPool2d(kernel_size=3, stride=2)  # 第二层:最大池化层
        self.c3 = nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, padding=2)  # 第三层:卷积层
        self.s4 = nn.MaxPool2d(kernel_size=3, stride=2)  # 第四层:最大池化层
        self.c5 = nn.Conv2d(in_channels=256, out_channels=384, kernel_size=3, padding=1)  # 第五层:卷积层
        self.c6 = nn.Conv2d(in_channels=384, out_channels=384, kernel_size=3, padding=1)  # 第六层:卷积层
        self.c7 = nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, padding=1)  # 第七层:卷积层
        self.s8 = nn.MaxPool2d(kernel_size=3, stride=2)  # 第八层:最大池化层
        self.flatten = nn.Flatten()  # 第九层:平展层
        self.f1 = nn.Linear(6 * 6 * 256, 4096)  # 第十层:全连接层
        self.f2 = nn.Linear(4096, 4096)  # 第十一层:全连接层
        self.f3 = nn.Linear(4096, 10)  # 第十二层:全连接层

    # 前向传播
    def forward(self, x):
        # 卷积完后,然后进行激活函数
        x = self.ReLU(self.c1(x))
        x = self.s2(x)
        x = self.ReLU(self.c3(x))
        x = self.s4(x)
        x = self.ReLU(self.c5(x))
        x = self.ReLU(self.c6(x))
        x = self.ReLU(self.c7(x))
        x = self.s8(x)

        x = self.flatten(x)  # 平展层
        x = self.ReLU(self.f1(x))  # 线性全连接层

        x = F.dropout(x, 0.5)
        x = self.ReLU(self.f2(x))
        x = F.dropout(x, 0.5)

        x = self.f3(x)  # 输出层

        return x


# 测试模型的搭建有没有成功(仅测试)
if __name__ == "__main__":
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = AlexNet().to(device)
    print(summary(model, (1, 227, 227)))

模型训练

创建一个model_train.py 文件

import copy
import time

import torch
from torchvision.datasets import FashionMNIST
from torchvision import transforms
import torch.nn as nn
import torch.utils.data as Data
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from model import AlexNet


# 处理训练集核数据集
def train_val_data_process():
    # 加载数据集
    train_data = FashionMNIST(
        root="./data",# 数据集所在路径
        train=True, # 要训练集
        # 将数据进行归一化操作
        transform=transforms.Compose([
            transforms.Resize(size=227), # 修改数据的大小
            transforms.ToTensor() # 将数据转成Tensor格式
        ]),
        download=True # 开启加载
    )

    # 随机 划分训练集 和 验证集
    train_data,val_data = Data.random_split(
        train_data, # 要划分的数据集
        [
            round(0.8*len(train_data)), # 划分80%给训练集
            round(0.2*len(train_data)) # 划分20%给验证集
        ]
    )

    # 加载训练集数据
    train_dataloader = Data.DataLoader(
        dataset=train_data,# 要加载的训练集
        batch_size=32,# 每轮的训练批次数
        shuffle=True,# 打乱数据顺序
        num_workers=2,# 加载数据线程数量
    )

    # 加载验证集数据
    val_dataloader = Data.DataLoader(
        dataset=val_data,# 要加载的验证集
        batch_size=32,# 每轮的训练批数
        shuffle=True,# 打乱数据顺序
        num_workers=2,# 加载数据集的线程数量
    )

    return train_dataloader,val_dataloader



# 模型训练
def train_model_process(model,train_dataloader,val_dataloader,num_epochs):
    # model:需要训练的模型,train_dataloader:训练集数据,val_dataloader:验证集数据,num_epochs:训练轮数
    # 指定设备
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    # 定义优化器
    optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
    # 定义交叉熵损失函数
    criterion = nn.CrossEntropyLoss()
    # 将模型放入到设备中进行训练
    model.to(device)
    # 复制当前模型的参数
    best_model_wts = copy.deepcopy(model.state_dict())

    # 初始化参数,记录模型的的精确度和损失值
    best_acc = 0.0 # 最高精确度

    train_loss_all = [] # 训练集的总损失
    train_acc_all = [] # 训练集的总精度

    val_loss_all = [] # 验证集的总损失
    val_acc_all = [] # 验证集的总精度

    since = time.time() # 记录开始训练的时间

    # 开始训练模型 每轮参数
    for epoch in range(num_epochs):
        print("Epoch {}/{}".format(epoch,num_epochs-1))
        print("-"*10)

        # 初始化参数,记录本轮的模型的损失之和精度
        train_loss = 0.0 # 训练的损失
        train_corrects = 0  # 训练的准确度

        val_loss = 0.0 # 验证集的损失
        val_corrents = 0 # 验证集的准确度

        train_num = 0 # 本轮训练集的数量
        val_num = 0 # 本轮验证集的数量

        # 取出每轮中的数据集进行训练
        for step,(b_x,b_y) in enumerate(train_dataloader):
            b_x = b_x.to(device) # 将训练集数据放入到设备当中
            b_y = b_y.to(device) # 将标签数据放入到设备当中

            model.train() # 开启模型训练模式

            # 将每批次中的标签数据放入到模型中,进行前向传播
            output = model(b_x)

            # 查找每一行中最大值对应的行标,即预测值
            pre_lab = torch.argmax(output,dim=1)

            # 计算当前批次的损失值(模型的输出,标签)
            loss = criterion(output,b_y)

            # 每批次训练完后,将梯度初始化成0
            optimizer.zero_grad()

            # 反向传播计算
            loss.backward()

            # 更新参数
            optimizer.step()

            # 本批次损失值的累加
            train_loss += loss.item() * b_x.size(0)

            # 如果模型预测的结果正确,本批次的准确度+1
            train_corrects += torch.sum(pre_lab == b_y.data)

            # 本此次的训练数据累加
            train_num += b_y.size(0)


        # 取出每轮中的数据进行验证
        for step,(b_x,b_y) in enumerate(val_dataloader):
            # 将数据和标签分别放入到设备中
            b_x = b_x.to(device)
            b_y = b_y.to(device)

            model.eval() # 设置模型为评估模式

            # 前向传播,输入一个批次,输出该批次的对应的预测值
            output = model(b_x)

            # 查找每一行中最大值对应的行标,即预测值
            pre_lab = torch.argmax(output,dim=1)

            # 计算本此次的损失函数
            loss = criterion(output,b_y)

            # 本批次的损失函数累加
            val_loss += loss.item() * b_x.size(0)

            # 如果预测正确,那就本批次的精度度累加
            val_corrents += torch.sum(pre_lab==b_y.data)

            # 当前用于验证的样本数累加
            val_num += b_x.size(0)


        # 计算每轮次的损失值和准确率
        train_loss_all.append(train_loss / train_num) # 本轮训练集的loss值
        train_acc_all.append(train_corrects.double().item() / train_num) # 本轮训练集的准确率

        val_loss_all.append(val_loss / val_num) # 本轮验证集的loss值
        val_acc_all.append(val_corrents.double().item() / val_num) # 本轮验证集的准确率

        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, train_loss_all[-1], train_acc_all[-1]))
        print("{} val loss:{:.4f} val acc: {:.4f}".format(epoch, val_loss_all[-1], val_acc_all[-1]))
        # 寻找最高准确度 和 模型的权重参数
        if val_acc_all[-1] > best_acc:
            best_acc = val_acc_all[-1] # 最高准确度
            best_model_wts = copy.deepcopy(model.state_dict()) # 最佳模型参数

        # 计算训练耗时
        time_use = time.time() - since
        print("训练耗费的时间:{:.0f}m{:.0f}s".format(time_use//60,time_use%60))

    # 将最佳的模型参数保存
    torch.save(best_model_wts,"best_model.pth") # .pth是权重文件的后缀

    # 保存训练好的模型参数
    train_process = pd.DataFrame(
        data={
            "epoch":range(num_epochs),
            "train_loss_all":train_loss_all,
            "train_acc_all":train_acc_all,
            "val_loss_all":val_loss_all,
            "val_acc_all":val_acc_all
        }
    )
    return train_process


# 定义绘图的函数,绘制loss和准确度
def matplot_acc_loss(train_process):
    plt.figure(figsize=(12,4))

    # 绘制训练集和验证集的损失值图像
    plt.subplot(1,2,1) # 一行两列,第一列
    plt.plot(train_process['epoch'],train_process.train_loss_all,"ro-",label="train loss")
    plt.plot(train_process['epoch'],train_process.val_acc_all,"bs-",label="val loss")
    plt.legend() # 图例
    plt.xlabel("epoch") # x轴标签
    plt.ylabel("loss") # y轴标签


    # 绘制训练集和验证集的准确度图像
    plt.subplot(1,2,2) # 一行两列,第二列
    plt.plot(train_process['epoch'],train_process.val_loss_all,"ro-",label="train acc")
    plt.plot(train_process['epoch'],train_process.val_acc_all,"bs-",label="va acc")



if __name__ == '__main__':
    # 实例化自定义模型类
    model = AlexNet()
    # 加载数据集
    train_dataloader,val_dataloader = train_val_data_process()
    # 训练模型
    train_process = train_model_process(model,train_dataloader,val_dataloader,20)
    # 绘制图像
    matplot_acc_loss(train_process)

模型测试

创建一个model_test.py文件,用于模型的测试

import torch
import torch.utils.data as Data
from numpy.random import shuffle
from torchvision import transforms
from torchvision.datasets import FashionMNIST

from model import AlexNet

# 加载要训练的数据
def test_data_process():
    # 加载测试集数据
    test_data = FashionMNIST(
        root="./data",# 指定数据集要下载的路径
        train=False,# 不要训练集数据
        # 数据归一化操作
        transform=transforms.Compose([
            transforms.Resize(size=227), # 将数据转成227*227大小
            transforms.ToTensor(),# 将数据转成Tensor格式
        ]),
        download=True # 加载数据
    )

    # 通过DataLoader加载器 来加载数据
    test_dataloader = Data.DataLoader(
        dataset=test_data,# 要加载的数据
        batch_size=1, # 每轮训练的批次数
        shuffle=True, # 打乱数据集
        num_workers=0, # 加载数据集的线程数量
    )

    return test_dataloader


# 测试模型
def test_model_process(model,test_dataloader):
    # 指定设备
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # 将模型放入设备中
    model.to(device)

    # 初始化模型训练的每轮参数
    test_correct = 0.0 # 准确度
    test_num = 0 # 测试样本数量

    # 只进行前向传播
    with torch.no_grad(): # 将梯度设置为0
        for test_data_x,test_data_y in enumerate(test_dataloader): # 遍历每轮次
            # 由于上面设置批次为1,所以这里就不需要循环批次了

            test_data_x = test_data_x.to(device) # 将测试数据放入到设备中
            test_data_y = test_data_y.to(device) # 将标签数据放入到设备中

            # 模型切换成评估模式
            model.eval()

            # 前向传播 将测试数据放入到模型中
            output = model(test_data_x)

            # 查找每一行中最大值的行标
            pre_lab = torch.argmax(output,dim=1)

            # 模型预测的结果 将pre_lab 与 标签数据 进行比较
            # 如果预测正确,则加1
            test_correct += torch.sum(pre_lab==test_data_y.data)

            # 测试样本数量累加
            test_num += test_data_y.size(0)

    # 计算最终测试的准确率 每轮的准确度 / 总样本数量
    test_acc = test_correct.double().item() / test_num

    print("测试模型的准确率为:",test_acc)





if __name__ == '__main__':
    # 加载模型
    model = AlexNet()
     # 模型具体的训练过程
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print("【当前的设备是】: ",device)

    # 加载训练好的模型最佳参数
    model.load_state_dict(torch.load('best_model.pth',map_location=device))

    # 加载测试的数据集
    test_dataloader = test_data_process()

    # 开始训练
    # test_model_process(model, test_dataloader)

    # 模型具体的训练过程
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    # 将模型放入到设备当中
    model = model.to(device)

    # 数据的类别
    classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot')

    # 梯度设置为0
    with torch.no_grad():
        # 遍历测试集中的 测试数据 和 标签
        for b_x,b_y in test_dataloader:
            # 将数据和标签移动到与模型相同的设备
            b_x = b_x.to(device)
            b_y = b_y.to(device)
            # 将模型设置为评估模式
            model.eval()
            # 将数据放入到模型中,得出预测结果
            output = model(b_x)
            # 获取最大值的行标
            pre_lab = torch.argmax(output,dim=1)
            # 取出张量中的下标
            result = pre_lab.item()
            label = b_y.item()

            print("预测结果为:",classes[result],"标签为:",classes[label])


你可能感兴趣的:(网络,神经网络)