【论文阅读】- 我对“AlexNet”的理解

欢迎浏览本博客
大家好,我是:我菜就爱学一名刚刚入行的小白
从事方向:计算机视觉 我菜就爱学,分享有误,欢迎大佬指出
本篇介绍:深度学习简单的入门之后,学习经典网络模型——AlexNet

论文题目: 嗯- ImageNet Classification with Deep Convolutional Neural Networks -嗯

个人理解: 这边论文虽然已经过时了,里面的很多技术也都改进了。但是作为以后所有高级模型的改进,新手还是可以看一下的。

自我解读

摘要:

主要讲作者们训练了一个大型的深度卷积神经网络,将ImageNet LSVRC-2010竞赛中的120万张高分辨率图像分类为1000个不同的类别。测试一下数据上,我们实现了37.5% 和17.0% 的前1和前5错误率,这比以前的最新技术要好得多。神经网络具有6000万的参数和650,000的神经元,由五个卷积层组成,其中一些是max池层,以及三个具有最终1000 softmax的全连接层。为了使训练更快,我们使用了非饱和神经元和卷积操作的非常有效的GPU实现。为了减少全连接层中的过拟合,我们采用了最近开发的称为 “dropout” 的正则化方法,该方法被证明非常有效。

Top-1:预测的label中,概率向量最大的作为预测的结果,分类结果正确则正确,错误则错误
Top-5: 预测的label中,概率向量最大的前5个最为预测结果只有五个全部预测错误,则分类错误

对数据集的解释

ImageNet是属于大致22,000个类别的超过1500万个标记的高分辨率图像的数据集。大致有120万训练图像、50,000验证图像和150,000测试图像。因为之前跑过一个最近发表的论文代码,他的数据集是自己打标签的。但是作为AlexNet的标签则是以文件名命名,然后在文件里面存放大量的这种类别的图片。我自己训练的时候图片比较少,然后最后测试效果也不咋滴。

一个B站Up主对于数据集的理解:训练集可以看成“小测” 。 验证集可以看成:“模拟考” 。测试集可以看成:‘高考”

网络结构

【论文阅读】- 我对“AlexNet”的理解_第1张图片
一个GPU训练如下:
【论文阅读】- 我对“AlexNet”的理解_第2张图片

字有点丑,见谅:
【论文阅读】- 我对“AlexNet”的理解_第3张图片

减少过拟合的方法:

  • 数据增强:从原始图片中生成转化后的图像,转换后的图像在CPU中的python代码直接生成,GPU此刻正在处理前一批图像
  • Dropout激活: 减少神经元之间的联合依赖;随机掐死一片神经元。

代码解析:

MyModel.py

import torch
from torch import nn

class MyAlexNet(nn.Module):
    def __init__(self):
        super(MyAlexNet, self).__init__()
        self.model=nn.Sequential(
            nn.Conv2d(3,48,11,stride=4,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(48,128,5,stride=1,padding=2),
            nn.ReLU(),
            nn.Conv2d(128,192,3,stride=1,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(192,192,3,stride=1,padding=1),
            nn.ReLU(),
            nn.Conv2d(192,128,3,stride=1,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.classfiler=nn.Sequential(

            nn.Linear(128*6*6,2048),
            nn.Dropout(p=0.5),
            nn.Linear(2048,2048),
            nn.Dropout(p=0.5),
            nn.Linear(2048,1000),
            nn.Dropout(p=0.5),
            nn.Linear(1000,10)
        )

    def forward(self,x):
        x=self.model(x)
        x = torch.flatten(x, start_dim=1) #按照个数推平
        x=self.classfiler(x)
        return x

if __name__ == '__main__':
    input=torch.ones([32,3,224,224])
    aiy=MyAlexNet()
    output=aiy(input)
    print(output.shape)

然后是训练集,train.py

import os
import torchvision
from matplotlib import pyplot as plt
from torchvision.datasets import ImageFolder
from torchvision import transforms
from torch import nn
from torch.utils.data import dataset, DataLoader
from MyModel import *

#画图中文的乱码解决问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

#数据集
train_root=r"data/train"
test_root=r"data/val"

#数据预处理

#1、归一化
normalize=transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])  #三通道图像

train_transforms=transforms.Compose([
#将数据变换包装起来依次执行
    transforms.Resize((224,224)),
    transforms.RandomHorizontalFlip(),#随机垂直翻转,相对于以后的打乱
    transforms.ToTensor(), #归一化到【0-1】
    normalize,  #标准化到【-1,1】
] )
test_transforms=transforms.Compose([
    transforms.Resize((224,224)),
    transforms.ToTensor(), #归一化到【0-1】
    normalize,  #标准化到【-1,1】
])
#默认数据集已经自觉按照要分配的类型分成了不同的文件夹,一种类型的文件夹下面只存放一种类型的图片
# train_data=ImageFolder('../data/train',transform=train_transforms)
train_data=torchvision.datasets.CIFAR10(root='./dataset',train=True,
                                        transform=train_transforms,download=True)
# test_data=ImageFolder("../data/val",transform=test_transforms)

#测试
test_data=torchvision.datasets.CIFAR10(root='./dataset',train=False,
                                        transform=test_transforms,download=True)
# print(test_data.classes)  #根据分的文件夹的名字来确定的类别

train_dataloader=DataLoader(train_data,batch_size=32,shuffle=True)
test_dataloader=DataLoader(test_data,batch_size=32,shuffle=False)

device='cuda' if torch.cuda.is_available() else 'cpu'

#引入模型
model=MyAlexNet().to(device)

#创建损失函数
loss_fn=nn.CrossEntropyLoss().to(device)

#定义优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.001)
#params (iterable) – 待优化参数的iterable(w和b的迭代) 或者是定义了参数组的dict
# lr (float) – 学习率
# momentum (float, 可选) – 动量因子(默认:0)

#让学习率每10轮减半
# lr_scheduler=lr_scheduler.StepLR(optimizer,s)

#定义训练次数
total_train_step=0

#定义测试次数
total_test_step=0

#定义一个画图函数
def matplot_loss(train_loss,val_loss):
    plt.plot(train_loss,label='train_loss')
    plt.plot(val_loss,label='val_loss')
    plt.legend(loc='best')
    plt.xlabel('loss')
    plt.ylabel('epoch')
    plt.title("训练集和验证集的loss值对比图")
    plt.show()
#定义一个画图函数
def matplot_acc(train_acc,val_acc):
    plt.plot(train_acc,label='train_acc')
    plt.plot(val_acc,label='val_acc')
    plt.legend(loc='best')
    plt.xlabel('acc')
    plt.ylabel('epoch')
    plt.title("训练集和验证集的acc值对比图")
    plt.show()

#训练的次数
epoch=10
loss_train=[]
acc_train=[]
loss_val=[]
acc_val=[]
min_vcc=0.0
for i in range(epoch):

    print("-----正在进行第{}轮训练------".format(i + 1))
    model.train()
    total_train_loss=0
    total_train_acc=0
    m=0.0
    for data in train_dataloader:
        images,targets=data
        images=images.to(device)
        targets=targets.to(device)
        # print(images.shape)
        output=model(images)
        loss=loss_fn(output,targets)
        total_train_loss=total_train_loss+loss.item()
        accuracy = (output.argmax(1) == targets).sum() / output.shape[0]  # 1代表横向,0代码代表纵向
        total_train_acc=total_train_acc+accuracy.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step() #调整参数
        total_train_step=total_train_step+1
        if total_train_step % 100 ==0 :
            print("训练次数:{},loss={}".format(total_test_step,loss))
        m=m+1


    #模型转化为验证模式
    model.eval()


    train_loss = total_train_loss / m
    train_acc = total_train_acc / m
    print("整体测试集上的loss:{}".format(train_loss))
    print("整体测试集上的正确率:{}".format(train_acc))
    loss_train.append(train_loss)
    acc_train.append(train_acc)



    total_test_loss=0
    total_accuracy=0
    '''
    在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。
    而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,强制之后的内容不进行计算图构建。
    '''
    #每次运行完之后进行一次测试,类似于参数已经更新完毕,来测试一下
    with torch.no_grad():
        n=0.0
        for data in test_dataloader:
            images, targets = data
            images = images.to(device)
            targets = targets.to(device)
            output = model(images)
            loss=loss_fn(output,targets)
            total_test_loss=total_test_loss+loss.item()
            '''
            1.item()取出张量具体位置的元素元素值
            2.并且返回的是该位置元素值的高精度值
            3.保持原元素类型不变;必须指定位置
            '''
            accuracy=(output.argmax(1)==targets).sum()/output.shape[0]  #1代表横向,0代码代表纵向
            total_accuracy=total_accuracy+accuracy.item()
            n=n+1
    val_loss=total_test_loss/n
    val_acc=total_accuracy/n
    print("整体测试集上的loss:{}".format(val_loss))
    print("整体测试集上的正确率:{}".format(val_acc))
    loss_val.append(val_loss)
    acc_val.append(val_acc)

    #保存最好的模型权重
    if val_acc > min_vcc:
        folder='save_model'
        if not os.path.exists(folder):
            os.mkdir('save_model')
        min_vcc=val_acc
        print("save best model,在第{}轮".format(i))
        torch.save(model.state_dict(),'save_model/best_model.pth')
    if i==epoch-1:
        print("保存最后一轮权重:")
        torch.save(model.state_dict(),'save_model/last_model.pth')


matplot_loss(loss_train,loss_val)
matplot_loss(acc_train,acc_val)

print("目前没有problem")

最后是测试集,这个我读取每一张图片是用的OpenCV,后续会参考其他大佬的写法

import torch
from PIL import Image
from torch import nn
from torchvision.transforms import transforms, ToPILImage
from  torch.autograd import Variable
from MyAlexNet.MyModel import MyAlexNet
import os
import cv2



directory_name=r"F:/NetWork/AlexNet/data_test/"
def read_directory(directory_name):
    for filename in os.listdir(directory_name): #os.listdir()方法用于返回指定文件夹包含的文件或文件夹的名字的列表
        img = cv2.imread(directory_name + "/" + filename)

trans = transforms.Compose([transforms.ToTensor(),transforms.Resize((224, 224))])
classes = ["ants", "bees"]  # 自己是几种,这里就改成自己种类的字符数组
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("using {} device.".format(device))

model=MyAlexNet().to(device)
model.load_state_dict(torch.load("F:/NetWork/AlexNet/MyAlexNet/save_model/best_model.pth"))
model.eval()

for filename in os.listdir(directory_name):  # os.listdir()方法用于返回指定文件夹包含的文件或文件夹的名字的列表
    image = cv2.imread(directory_name + "/" + filename)

    # image = Image.open(img)
    # image = image.convert("RGB")
    image = trans(image)
    # show=ToPILImage()
    # show(image).show()

    image=Variable(torch.unsqueeze(image,dim=0).float()).to(device)
    image=torch.tensor(image).to(device)
    pred=model(image)
    print(pred)
    predicted=classes[torch.argmax(pred,dim=1)]
    print("prdeicted:{}".format(predicted))

你可能感兴趣的:(计算机视觉入门,论文阅读,python,深度学习)