欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

CV算法复现(分类算法3/6):VGG(2014年 牛津大学)

发布时间:2023/11/27 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 CV算法复现(分类算法3/6):VGG(2014年 牛津大学) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

致谢:霹雳吧啦Wz:https://space.bilibili.com/18161609

目录

致谢:霹雳吧啦Wz:https://space.bilibili.com/18161609

1 本次要点

1.1 Python库语法

1.2 深度学习理论

2 网络简介

2.1 历史意义

2.2 网络亮点

2.3 网络架构

3 代码结构

3.1 mode.py

3.2 train.py

3.3 predict.py


1 本次要点

1.1 Python库语法

  1. python中定义函数,参数分为一般参数,默认参数,非关键字参数和关键字参数
    1. 非关键字参数(或称可变参数*args
      1. 定义:可变参数就是传入的参数个数是可变的,可以是0个,1个,2个,……很多个。
      2. 作用:就是可以一次给函数传很多的参数
      3. 特征:*args
    2. 关键字参数**kw
      1. 定义:关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。在调用函数时,可以只传入必选参数。
      2. 作用:扩展函数的功能
      3. 特征:**kw

1.2 深度学习理论

  • 感受野:在卷积神经网络中,决定某一层输出结果中一个元素所对应的输入层的区域大小,被称作 感受野(receptive field)。
  • imageNet所有图片的RGB均值:[123.68, 116.78, 103.94]。如果使用ImageNet的预训练模型,那么后续训练时图片要减去此均值
    • 使用ImageNet预训练模型的标准化方法:transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    • 不使用预训练模型:transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

2 网络简介

2.1 历史意义

  • VGG在2014年由牛津大学著名研究组VGG (Visual Geometry Group) 提出,斩获该年ImageNet竞赛中 Localization Task (定位任务) 第一名 和 Classification Task (分类任务) 第二名。

2.2 网络亮点

  1. 通过堆叠(中间没有跟池化层)多个3x3的卷积核来替代大尺度卷积核(目的:减少网络参数量)(2层3*3卷积代替1层5*5卷积,3层3*3卷积代替1层7*7卷积)

2.3 网络架构

3 代码结构

  • mode.py
  • train.py
  • predict.py

3.1 mode.py

import torch.nn as nn
import torchclass VGG(nn.modules):def __init__(self, features, class_num=1000, init_weights=False):super(VGG, self).__init__()self.features = featuresself.classifier = nn.Sequential(nn.Dropout(p=0.5),nn.Linear(512*7*7, 2048),nn.ReLU(True),nn.Dropout(p=0.5),nn.Linear(2048, 2048),nn.ReLU(True),nn.Linear(2048, class_num))if init_weights:self._initialize_weights()def forward(self, x):# N * 3 * 224 * 224x = self.features(x)# N * 512 * 7 * 7x = torch.flatten(x, start_dim=1)# N * 512 * 7 * 7x = self.classifier(x)return xdef _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):# nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')nn.init.xavier_normal_(m.weight)if m.bias is not None:nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight)# nn.init.normal_(m.weight, 0, 0.01)nn.init.constant_(m.bias, 0)def make_features(cfg:list): #传入一个配置变量,list类型layers = []in_channels = 3for v in cfg:if v == 'M':layers += [nn.MaxPool2d(kernel_size=2, stride=2)]else:conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)layers += [conv2d, nn.ReLU(inplace=True)]in_channels = vreturn nn.Sequential(*layers) # “*”:通过非关键字参数形式传入进去。# 数字代表卷积核个数。M代表池化层。
cfgs = {'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}# 此函数功能:实例化VGG类
#**kwargs可变长度的字典变量,这个字典变量可能就包含分类个数、是否初始化等。
#**kwargs意思是该函数可以接受任意多个输入变量。
def vgg(model_name="vgg16", **kwargs):try:cfg = cfgs[model_name]except:print("Warning: model number {} not in cfgs dict!".format(model_name)exit(-1)model = VGG(make_features(cfg), **kwargs) return model

3.2 train.py

import torch.nn as nn
from torchvision import transforms, datasets
import json
import os
import torch.optim as optim
from model import vgg
import torchdef main():device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")print("using {} device.".format(device))data_transform = {"train": transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),"val": transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root pathimage_path = os.path.join(data_root, "data_set", "flower_data")  # flower data set pathassert os.path.exists(image_path), "{} path does not exist.".format(image_path)train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),transform=data_transform["train"])train_num = len(train_dataset)# {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}flower_list = train_dataset.class_to_idxcla_dict = dict((val, key) for key, val in flower_list.items())# write dict into json filejson_str = json.dumps(cla_dict, indent=4)with open('class_indices.json', 'w') as json_file:json_file.write(json_str)batch_size = 32nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workersprint('Using {} dataloader workers every process'.format(nw))train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size, shuffle=True,num_workers=nw)validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),transform=data_transform["val"])val_num = len(validate_dataset)validate_loader = torch.utils.data.DataLoader(validate_dataset,batch_size=batch_size, shuffle=False,num_workers=nw)print("using {} images for training, {} images fot validation.".format(train_num,val_num))# test_data_iter = iter(validate_loader)# test_image, test_label = test_data_iter.next()model_name = "vgg16"net = vgg(model_name=model_name, num_classes=5, init_weights=True)net.to(device)loss_function = nn.CrossEntropyLoss()optimizer = optim.Adam(net.parameters(), lr=0.0001)best_acc = 0.0save_path = './{}Net.pth'.format(model_name)for epoch in range(30):# trainnet.train()running_loss = 0.0for step, data in enumerate(train_loader, start=0):images, labels = dataoptimizer.zero_grad()outputs = net(images.to(device))loss = loss_function(outputs, labels.to(device))loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()# print train processrate = (step + 1) / len(train_loader)a = "*" * int(rate * 50)b = "." * int((1 - rate) * 50)print("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss), end="")print()# validatenet.eval()acc = 0.0  # accumulate accurate number / epochwith torch.no_grad():for val_data in validate_loader:val_images, val_labels = val_dataoptimizer.zero_grad()outputs = net(val_images.to(device))predict_y = torch.max(outputs, dim=1)[1]acc += (predict_y == val_labels.to(device)).sum().item()val_accurate = acc / val_numif val_accurate > best_acc:best_acc = val_accuratetorch.save(net.state_dict(), save_path)print('[epoch %d] train_loss: %.3f  test_accuracy: %.3f' %(epoch + 1, running_loss / step, val_accurate))print('Finished Training')if __name__ == '__main__':main()

3.3 predict.py

import torch
from model import vgg
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import jsondata_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# load image
img = Image.open("../tulip.jpg")
plt.imshow(img)
# [N, C, H, W]
img = data_transform(img)
# expand batch dimension
img = torch.unsqueeze(img, dim=0)# read class_indict
try:json_file = open('./class_indices.json', 'r')class_indict = json.load(json_file)
except Exception as e:print(e)exit(-1)# create model
model = vgg(model_name="vgg16", num_classes=5)
# load model weights
model_weight_path = "./vgg16Net.pth"
model.load_state_dict(torch.load(model_weight_path))
model.eval()
with torch.no_grad():# predict classoutput = torch.squeeze(model(img))predict = torch.softmax(output, dim=0)predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)])
plt.show()

 

 

总结

以上是生活随笔为你收集整理的CV算法复现(分类算法3/6):VGG(2014年 牛津大学)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。