• 【论文阅读】- 我对“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主对于数据集的理解:训练集可以看成“小测” 。 验证集可以看成:“模拟考” 。测试集可以看成:‘高考”

    网络结构

    在这里插入图片描述
    一个GPU训练如下:
    在这里插入图片描述

    字有点丑,见谅:
    在这里插入图片描述

    减少过拟合的方法:
    • 数据增强:从原始图片中生成转化后的图像,转换后的图像在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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    然后是训练集,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")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    最后是测试集,这个我读取每一张图片是用的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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    TouchGFX之字体缓存
    车间调度|基于遗传算法的柔性车间调度(Matlab代码实现)
    【Android 从入门到出门】第一章:Android开发技能入门指南
    【RuoYi-Cloud-Plus】学习笔记 05 - Spring Cloud Gateway(一)关于配置文件参数
    基于遗传算法的自主式水下潜器路径规划问题(Matlab代码实现)
    中项2022
    【TensorRT】Win10系统python/c++安装tensorrt库
    金山云:基于 JuiceFS 的 Elasticsearch 温冷热数据管理实践
    网桥、路由器和网关有什么区别?
    c语言强制类型转换
  • 原文地址:https://blog.csdn.net/qq_44859533/article/details/127831212