LetNet、Alex、VggNet分析及其pytorch实现
时间:2021-12-04 作者:GreenOrange
简单分析一下主流的几种神经网络
LeNet
LetNet作为卷积神经网络中的HelloWorld,它的结构及其的简单,1998年由LeCun提出
基本过程:
可以看到LeNet-5跟现有的conv->pool->ReLU的套路不同,它使用的方式是conv1->pool->conv2->pool2再接全连接层,但是不变的是,卷积层后紧接池化层的模式依旧不变。
代码:
import 域名 as nn
import torch
class LeNet(域名le):
def __init__(self):
super(LeNet, self).__init__()
layer1 = 域名ential()
# Convolution with 5x5 kernel+2padding:28×28×6
域名module(\'conv1\', 域名2d(1, 6, kernel_size=(3, 3), padding=1))
# Pool with 2x2 average kernel+2 stride:14×14×6
域名module(\'pool1\', 域名ool2d(kernel_size=2))
域名r1 = layer1
layer2 = 域名ential()
# Convolution with 5x5 kernel (no pad):10×10×16
域名module(\'conv2\', 域名2d(6, 16, kernel_size=(5, 5)))
# Pool with 2x2 average kernel+2 stride: 5x5×16
域名module(\'pool2\', 域名ool2d(kernel_size=2))
域名r2 = layer2
layer3 = 域名ential()
# 5 = ((28/2)-4)/2
域名module(\'fc1\', 域名ar(16 * 5 * 5, 120))
域名module(\'fc2\', 域名ar(120, 84))
域名module(\'fc3\', 域名ar(84, 10))
域名r3 = layer3
def forward(self, x):
x = 域名r1(x)
# print(域名())
x = 域名r2(x)
# print(域名())
# 展平x
x = 域名ten(x, 1)
x = 域名r3(x)
return x
# 测试
test_data = 域名(1, 1, 28, 28)
model = LeNet()
model(test_data)
输出
tensor([[ 域名, -域名, 域名, 域名, 域名, 域名, -域名, -域名,
-域名, -域名]], grad_fn=<AddmmBackward0>)
AlexNet
这个图看起来稍微可能有亿点复杂,其实这个是因为当时的GPU计算能力不太行,而Alex又比较复杂,所以Alex使用了两个GPU并行来做运算,现在已经完全可以用一个GPU来代替了。
相对于LeNet来说,Alex网络层数更深,同时第一次引入了激活层ReLU,又在全连接层引入了Dropout层防止过拟合。
执行流程图在上面,跟LeNet的执行流程图放在一张图上。
代码:
import 域名 as nn
import torch
class AlexNet(域名le):
def __init__(self, num_class):
super(AlexNet, self).__init__()
域名ures = 域名ential(
域名2d(3, 64, kernel_size=(11, 11), stride=(4, 4)),
域名(True),
域名ool2d(kernel_size=3, stride=2),
域名2d(64, 192, kernel_size=(5, 5), padding=2),
域名(True),
域名ool2d(kernel_size=3, stride=2),
域名2d(192, 384, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(384, 256, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(256, 256, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=3, stride=2),
)
域名sifier = 域名ential(
域名out(),
域名ar(256*5*5, 4096),
域名(True),
域名out(),
域名ar(4096, 4096),
域名(True),
域名ar(4096, num_class)
)
def forward(self, x):
x = 域名ures(x)
print(域名())
x = 域名(域名(0), 256 * 5 * 5)
x = 域名sifier(x)
return x
# 测试
test_data = 域名(1, 3, 224, 224)
model = AlexNet(10)
model(test_data)
输出:
域名([1, 256, 5, 5])
tensor([[-域名, 域名, 域名, -域名, 域名, -域名, 域名, -域名,
域名, 域名]], grad_fn=<AddmmBackward0>)
VggNet
VggNet是ImageNet 2014年的亚军,总的来说就是它使用了更小的滤波器,用了更深的结构来提升深度学习的效果,从图里面可以看出来这一点,它没有使用11*11这么大的滤波器,取而代之的使用的都是3*3这种小的滤波器,它之所以使用很多小的滤波器,是因为层叠很多小的滤波器的感受野和一个大的滤波器的感受野是相同的,还能减少参数。
代码实现:
import 域名 as nn
class VGG(域名le):
def __init__(self, num_class):
super(VGG, self).__init__()
域名ures = 域名ential(
域名2d(3, 64, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(64, 64, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=2, stride=2),
域名2d(64, 128, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(128, 128, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=2, stride=2),
域名2d(128, 256, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(256, 256, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(256, 256, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=2, stride=2),
域名2d(256, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(512, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(512, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=2, stride=2),
域名2d(512, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(512, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名2d(512, 512, kernel_size=(3, 3), padding=1),
域名(True),
域名ool2d(kernel_size=2, stride=2),
)
域名sifier = 域名ential(
域名ar(512 * 7 * 7, 4096), 域名(True),
域名out(),
域名ar(4096, 4096), 域名(True),
域名out(),
域名ar(4096, num_class),
)
域名tialize_weights()
def forward(self, x):
x = 域名ures(x)
x = 域名(域名(0), -1)
x = 域名sifier(x)
return x
使用卷积神经网络实现对Minist数据集的预测
代码:
import 域名ot as plt
import 域名
import 域名sets
import os
import 域名 as nn
from torchvision import transforms
class CNN(域名le):
def __init__(self):
super(CNN, self).__init__()
域名r1 = 域名ential(
域名2d(1, 16, kernel_size=(3, 3)),
域名hNorm2d(16),
域名(inplace=True),
)
域名r2 = 域名ential(
域名2d(16, 32, kernel_size=(3, 3)),
域名hNorm2d(32),
域名(inplace=True),
域名ool2d(kernel_size=2, stride=2),
)
域名r3 = 域名ential(
域名2d(32, 64, kernel_size=(3, 3)),
域名hNorm2d(64),
域名(inplace=True)
)
域名r4 = 域名ential(
域名2d(64, 128, kernel_size=(3, 3)),
域名hNorm2d(128),
域名(inplace=True),
域名ool2d(kernel_size=2, stride=2)
)
域名 = 域名ential(
域名ar(128 * 4 * 4, 1024),
域名(inplace=True),
域名ar(1024, 128),
域名ar(128, 10)
)
def forward(self, x):
x = 域名r1(x)
x = 域名r2(x)
x = 域名r3(x)
x = 域名r4(x)
x = 域名(域名(0), -1)
x = 域名(x)
return x
域名ron["KMP_DUPLICATE_LIB_OK"] = "TRUE"
data_tf = 域名ose(
[域名nsor(),
域名alize([0.5], [0.5])]
)
train_dataset = 域名T(root=\'F:/机器学习/pytorch/书/data/mnist\', train=True,
transform=data_tf, download=True)
test_dataset = 域名T(root=\'F:/机器学习/pytorch/书/data/mnist\', train=False,
transform=data_tf, download=True)
batch_size = 100
train_loader = 域名.DataLoader(
dataset=train_dataset, batch_size=batch_size
)
test_loader = 域名.DataLoader(
dataset=test_dataset, batch_size=batch_size
)
model = CNN()
model = 域名()
criterion = 域名sEntropyLoss()
criterion = 域名()
optimizer = 域名(域名meters())
# 节约时间,三次够了
iter_step = 3
loss1 = []
loss2 = []
for step in range(iter_step):
loss1_count = 0
loss2_count = 0
for images, labels in train_loader:
images = 域名()
labels = 域名()
images = 域名ape(-1, 1, 28, 28)
output = model(images)
pred = 域名eze()
域名_grad()
loss = criterion(pred, labels)
域名ward()
域名()
_, pred = 域名(pred, 1)
loss1_count += int(域名(pred == labels)) / 100
# 测试
else:
test_loss = 0
accuracy = 0
with 域名rad():
for images, labels in test_loader:
images = 域名()
labels = 域名()
pred = model(域名ape(-1, 1, 28, 28))
_, pred = 域名(pred, 1)
loss2_count += int(域名(pred == labels)) / 100
域名nd(loss1_count / len(train_loader))
域名nd(loss2_count / len(test_loader))
print(f\'第{step}次训练:训练准确率:{loss1[len(loss1)-1]},测试准确率:{loss2[len(loss2)-1]}\')
域名(loss1, label=\'Training loss\')
域名(loss2, label=\'Validation loss\')
域名nd()
输出:
第0次训练:训练准确率:域名166666666718,测试准确率:域名999999999996
第1次训练:训练准确率:域名833333333389,测试准确率:域名999999999998
第2次训练:训练准确率:域名000000000039,测试准确率:域名999999999994
<域名nd at 0x21f03092fd0>