Alexnet网络与Vgg网络

社会主义新天地 提交于 2019-11-30 00:32:48

迁移学习

使用迁移学习来实现猫狗分类。
迁移学习的个人理解:就是把一个训练好的神经网络从中分开,在拼接到其他的神经网络上,在迁移的过程中,卷积模块的结构不会发生改变,并且权重也不会发生改变。迁移学习分为两种:1.预训练模式,迁移过来的权重作为新网络的初始权重,然后不断训练,改变参数的值。2.固定模式,迁移过来的网络结构和权重都不会改变,训练过程只针对全连接层,在反向传播过程中,在迁移模块停止,不改变迁移模块中的权重,只训练全连接层的参数。

Alexnet网络的结构

  Alexnet网络是由五个卷积层和三个全连接层构成,其中最后的输出被送到1000维的softmax函数
在卷积层的第一、第二和第五层使用了最大池化函数,并且在卷积层的第一和第二层使用了标准化
LRN函数。在全连接层的前两层使用了Dropout函数,来解决神经网络的过拟合问题。Relu激活函
数应用在每个卷积层和全连接层。
  第一个卷积层的输入为224×224×3的图像,对其使用96个大小为11×11×3、步长为4的卷积核来处
输入图像。第二个卷积层将第一个卷积层的输出(响应归一化以及池化)作为输入,并使用256个
卷积核处理图像,每个内核大小为5×5×48。第三个、第四个和第五个卷积层彼此连接而中间没有任
何池化或归一化层。第三个卷积层有384个卷积核,每个的大小为3×3×256,其输入为第二个卷积层
的输出。第四个卷积层有384个内核,每个卷积核大小为3×3×192。第五个卷积层有256个卷积核
每个核大小为3×3×192。全连接层各有4096个神经元。

Alexnet网络的特点

  1. 使用了两个GPU 。由于数据量较大,将网络分配给两个GPU,GPU之间交换数据只会在某些层上发生,不会在所有层上发生第三层从第二层获取数据时会跨GPU,而第四层从第三层获取数据时,只会在同一GPU上进行;
  2. 在数据预处理阶段,将图片随机截取224*224大小,以及他们的水平翻转形成 的图片作为总的样本。在测试时,截取5个224×224的图像块以及它们的水平映射作为样本
  3. 使用了Relu非线性激活函数,训练时间更快;
  4. .在Relu后使用了LRN作为归一化的方法,局部响应归一化;
  5. 使用了最大池化函数,并且重叠池化,池化核为3*3,步长为2,训练效果更好,传统的池化核在平移过程中,区域不会重合;
  6. 在全连接层的前两层使用Dropout,以概率p将某些神经元的值变为0,这些神经元不会参加正向和反向传播;但是对于不同的输入,构建的不同的网络模型使用相同的权重;测试时使用全部的神经元,但是神经元的值会减半

实现Alexnet网络框架

使用pytorch初步实现Alexnet网络结构

class Alexnet(nn.Module):
    def __init__(self):
        super(Alexnet, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=3,
                      out_channels=96,
                      kernel_size=11,
                      stride=4),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=96,
                      out_channels=256,
                      kernel_size=5,
                      stride=1,
                      padding=2),
            nn.ReLU(),
            nn.
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(in_channels=256,
                      out_channels=384,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU()
        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(in_channels=384,
                      out_channels=384,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU()
        )
        self.conv5 = nn.Sequential(
            nn.Conv2d(in_channels=384,
                      out_channels=256,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        self.fcalex = nn.Sequential(
            nn.Linear(256*6*6, 4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),

            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),

            nn.Linear(4096, 1000)
        )
        

Alexnet实现猫狗分类

import os
import torch
import torch.nn as nn
from torchvision.datasets import ImageFolder
from torch import optim
from torchvision import transforms, models
from torch.autograd import Variable

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
transform = transforms.Compose([
transforms.Resize(size=(227, 227)),
transforms.RandomRotation(20),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalize
])

train_dataset = ImageFolder(root=’./data/train’, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, shuffle=True)
test_dataset = ImageFolder(root=’./data/test’, transform=transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16, shuffle=True)

alexnet = models.alexnet(pretrained=True)
class Alexnetl(nn.Module):
def init(self):
super(Alexnetl, self).init()
self.features = alexnet.features
fc1 = nn.Linear(9216, 4096)
fc1.bias = alexnet.classifier[1].bias
fc1.weight = alexnet.classifier[1].weight

    fc2 = nn.Linear(4096, 4096)
    fc2.bias = alexnet.classifier[4].bias
    fc2.weight = alexnet.classifier[4].weight

    fc31 = nn.Linear(4096, 2)

    self.classifier = nn.Sequential(
        nn.Dropout(),
        fc1,
        nn.ReLU(inplace=True),
        nn.Dropout(),
        fc2,
        nn.ReLU(inplace=True),
        fc31
    )


def forward(self, x):
    x = self.features(x)
    x = x.view(x.size(0), 256 * 6 * 6)
    x = self.classifier(x)
    return x

net = Alexnetl()
“”"
pre_para = alexnet.state_dict()
net_para = net.state_dict()

pre_para = {k: v for k, v in pre_para.items() if k in net_para}
net_para.update(pre_para)
net.load_state_dict(net_para)
print(net)
“”"

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001)

n_epoch = 1
for epoch in range(n_epoch):
for i , data in enumerate(train_loader):

    images, labels = data
    images, labels = Variable(images), Variable(labels)
    output = net(images)

    loss = criterion(output, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    i += 1
    if i % 10 == 0:
        print('epoch:{}, loss: {:.3f}'.format(epoch, loss))

correct = 0
total = 0

for i,data in enumerate(test_loader):
i += 1
images, labels = data
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
if i % 10 ==0:
Accuracy = correct / total
print(‘Accuracy of test is {:.3f}’.format(Accuracy))
结果:
在这里插入图片描述

vggnet网络的结构

相对于Alexnet网络来看,Vgg网络具有 更深的网络结构,一般为16层到19层,其中最后三层为全连接层。卷积时使用了多个小的卷积核堆叠起来,卷积核的大小都为33,步长为1,而且并不是在每个卷积后都跟有池化操作,整个网络包含有五个池化层,采用最大池化操作,池化核大小为22,步长为1。
vgg网络结构图:
在这里插入图片描述

vgg网络的特点:

1.数据预处理只有一个操作,在训练阶段就是每一个的值减去RGB的均值,在测试阶段就是重新定义图片的大小。
2.卷积过程中,使用多个小的卷积核(33)堆叠来代替大的卷积核,其中2个33的可以代替1个55的卷积核。在感受野相同时,卷积核越小,所需要的参数也越少。这样操作使用更少参数,同时使用多次relu函数,有更强的分辨能力。
为什么2个3
3的卷积核可以代替1个55的卷积核:(strid=1)
5
5的感受野:感受野为5,
第1个33的感受野:第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小,就是3,第二个33的感受野:(3-1)1+3=5。感受野相同,或者计算这两者的feature map也是相同的。
参数减少:(通道为3)
2个3
3卷积的参数:3332=54
1个5
5卷积的参数:5531=75
3.在全连接的前两层也使用了Dropout,概率为p将某些神经元置零,这些神经元不会参加正向和反向传播;但是对于不同的输入,构建的不同的网络模型使用相同的权重;测试时使用全部的神经元,但是神经元的值会减半
4.在测试阶段,将最后三层全连接层替换为三个卷积层,卷积核大小分别为7
7,11 ,11,因为卷积核大小为1*1,不会影响输出维度,同时又增加了relu进行非线性处理

实现Vgg网络框架

部分代码:

        self.conv1_1 = nn.Conv2d(3, 64, 3)  
        self.conv1_2 = nn.Conv2d(64, 64, 3, padding=(1, 1))  
        self.maxpool1 = nn.MaxPool2d((2, 2), padding=(1, 1)) 

        self.conv2_1 = nn.Conv2d(64, 128, 3)  # 128 * 110 * 110
        self.conv2_2 = nn.Conv2d(128, 128, 3, padding=(1, 1)) 
        self.maxpool2 = nn.MaxPool2d((2, 2), padding=(1, 1)) 

        out = self.conv1_1(x)
        out = F.relu(out)
        out = self.conv1_2(out) 
        out = F.relu(out)
        out = self.maxpool1(out)

Vgg实现猫狗分类

将vgg16作为预训练好的模型迁移过来,参数保持不变,修改全连接层,将最后一层的输出改为2,对新的模型进行训练。

实现代码:

import torch
import torch.nn as nn
from torchvision.datasets import ImageFolder
from torch import optim
from torchvision import transforms, models
from torch.autograd import Variable

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

transform = transforms.Compose([transforms.CenterCrop(224),
                               transforms.ToTensor(),
                               normalize])
                               
train_dataset = ImageFolder(root='./data/train', transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, shuffle=True)

test_dataset = ImageFolder(root='./data/test', transform=transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16, shuffle=True)

model = models.vgg16(pretrained=True)
model.classifier._modules['6'] = nn.Linear(4096, 2)

loss_func = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)

for epoch in range(2):
    total1 = 0
    correct1 = 0
    model.parameters()
    for i, data in enumerate(train_loader):
        i += 1
        images, labels = data
        images = Variable(images)
        labels = Variable(labels)

        optimizer.zero_grad()
        output = model(images)
        loss = loss_func(output, labels)

        loss.backward()
        optimizer.step()
        _, predicted = torch.max(output.data, 1)
        total1 += labels.size(0)
        correct1 += (predicted == labels).sum()
        if i % 5 == 0:
            print('train loss is : ', loss)

			acc = correct1/total1
			print(' train acc is :', acc)

correct = 0
total = 0
for data in test_loader:
    images, labels = data
    outputs = model(Variable(images))
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum()

print('Accuracy of network test images: %d %%' % (100 * correct / total))

vgg的结果:

Alexnet和vgg比较:
vgg网络具有更深的网络结构,使用的卷积核和池化核都是统一大小,两者对于数据的预处理也是不同的。可以看出,在结果方面,vgg网络的评估结果更好,损失更低,精确度更高,但是vgg网络运行时间更久,由于网络更深,参数更多,耗费了更多的资源,占据了更多的内存。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!