我对VGG的很多地方还不是很清楚,现在只是知道整个网络用于数据集识别的一个基本流程和一些网络参数的大小,所以很多地方也不敢去详细解释,我对以下我这一周学习VGGNet的学习笔记,大部分截图,代码太长的地方就直接复制了一下
下面是基于VGGNet16,使用pytorch框架实现CIFAR10数据集的识别
先导入这次图像识别的模块和包
接下来是搭建VGG16网络模型
如下图是VGG的整个网络结构和各个部分的输入输出参数
明确VGG16的网络层和最后的全连接层
‘VGG16’: [64, 64, ‘M’, 128, 128, ‘M’, 256, 256, 256, ‘M’, 512, 512, 512, ‘M’, 512, 512, 512, ‘M’],
nn.Module是一个特殊的nn模块,加载nn.Module,这是为了继承父类,super 加载父类中的__init__()函数
第一层和第二层都是两个卷积层一个池化层
两层得到的大小分别是‘64,64’—>‘128,128’
接下来的三层都是三个卷积层和一个池化层
三层得到的大小分别是‘256,256,256’—>‘512, 512, 512’—>‘512,512,512’
创建一个类实现VGGNet的全连接层
将代码补充完整之后,可以打印出模型的结构参数
VGG(
(VGG_layer): Sequential(
(0): Conv2d(1, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(7): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(8): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(9): ReLU(inplace=True)
(10): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(11): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(12): ReLU(inplace=True)
(13): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(14): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(15): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(16): ReLU(inplace=True)
(17): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(18): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(19): ReLU(inplace=True)
(20): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(21): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(22): ReLU(inplace=True)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(25): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(26): ReLU(inplace=True)
(27): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(28): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(29): ReLU(inplace=True)
(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(31): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(32): ReLU(inplace=True)
(33): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(35): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(36): ReLU(inplace=True)
(37): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(38): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(39): ReLU(inplace=True)
(40): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(41): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(42): ReLU(inplace=True)
(43): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(FC_layer): Sequential(
(fc): Sequential(
(0): FlattenLayer()
(1): Linear(in_features=25088, out_features=4096, bias=True)
(2): ReLU()
(3): Dropout(p=0.5, inplace=False)
(4): Linear(in_features=4096, out_features=4096, bias=True)
(5): ReLU()
(6): Dropout(p=0.5, inplace=False)
(7): Linear(in_features=4096, out_features=10, bias=True)
)
)
)
确定模型结构参数之后,来进行数据处理和训练的部分
# 定义的全局变量
# 每次喂入的数据量
batch_size = 32
# batch打印的间隔
num_print = int(50000 // batch_size // 4)
# 总迭代次数50次
epoch_num = 50
# 学习率
lr = 0.01
# 每10个epoch更新一次学习率
step_size = 10
从下图可以看的出,VGG喂入的图片都是2242243的,所以如果是要加载训练自己的数据集,还需要将图片的大小统一resize成224*224的大小
可以选择默认下载CIFAR10数据集,在pytorch中通过利用transform来对图片进行处理
选择训练的device,以及loss函数和优化器
训练数据集部分的代码
for epoch in range(epoch_num):
running_loss = 0.0
for i, (inputs, labels) in enumerate(train_loader, 0):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels).to(device)
loss.backward()
optimizer.step()
running_loss += loss.item()
loss_list.append(loss.item())
if i % num_print == num_print - 1:
print('[%d epoch, %d] loss: %.6f' % (epoch + 1, i + 1, running_loss / num_print))
running_loss = 0.0
lr_1 = optimizer.param_groups[0]['lr']
print('learn_rate : %.15f' % lr_1)
scheduler.step()
end = time.time()
print('time:{}'.format(end-start))
并且在最后保存已经训练好的模型,并在对训练好的模型进行加载
torch.save(model, './model.pkl')
model = torch.load('./model.pkl')
这是可以绘出loss图像的代码部分
下面是我完成一次训练后所得的loss的图像
这是测试部分的代码
model.eval()
correct = 0.0
total = 0
with torch.no_grad(): # 训练集不需要反向传播
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device) # 将输入和目标在每一步都送入GPU
outputs = model(inputs)
pred = outputs.argmax(dim=1) # 返回每一行中最大值元素索引
total += inputs.size(0)
correct += torch.eq(pred, labels).sum().item()
print('Accuracy of the network on the 10000 test images: %.2f %%' % (100.0 * correct / total))
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
pred = outputs.argmax(dim=1) # 返回每一行中最大值元素索引
c = (pred == labels.to(device)).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += float(c[i])
class_total[label] += 1
# 每个类的ACC
for i in range(10):
print('Accuracy of %5s : %.2f %%' % (classes[i], 100 * class_correct[i] / class_total[i]))
这是最后的结果
这些是我觉得这次使用VGG16识别CIFAR10数据集的过程中基础和核心的部分,这篇学习笔记可能有的地方理解也不是很好,仅供参考。