VGG16实现人脸识别


🍨 本文为🔗365天深度学习训练营 中的学习记录博客
🍖 原作者:K同学啊 | 接辅导、项目定制

一、代码

import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib,warnings
import os,PIL,random,pathlib
from torchvision.models import vgg16

warnings.filterwarnings("ignore")             #忽略警告信息

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")



data_dir = '/home/kaijiang/zlf/CSDN task/the six week/48-data/'
data_dir = pathlib.Path(data_dir)

data_paths  = list(data_dir.glob('*'))
classeNames = [str(path).split("\\")[0] for path in data_paths]


train_transforms = transforms.Compose([
    transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸
    # transforms.RandomHorizontalFlip(), # 随机水平翻转
    transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
        mean=[0.485, 0.456, 0.406], 
        std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])

total_data = datasets.ImageFolder("/home/kaijiang/zlf/CSDN task/the six week/48-data/",transform=train_transforms)

train_size = int(0.8 * len(total_data))
test_size  = len(total_data) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])


batch_size = 32

train_dl = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True,
                                           num_workers=1)
test_dl = torch.utils.data.DataLoader(test_dataset,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          num_workers=1)

for X, y in test_dl:
    print("Shape of X [N, C, H, W]: ", X.shape)
    print("Shape of y: ", y.shape, y.dtype)
    break


device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))
    
# 加载预训练模型,并且对模型进行微调
model = vgg16(pretrained = True).to(device) # 加载预训练的vgg16模型

for param in model.parameters():
    param.requires_grad = False # 冻结模型的参数,这样子在训练的时候只训练最后一层的参数

# 修改classifier模块的第6层(即:(6): Linear(in_features=4096, out_features=2, bias=True))
# 注意查看我们下方打印出来的模型
model.classifier._modules['6'] = nn.Linear(4096,len(classeNames)) # 修改vgg16模型中最后一层全连接层,输出目标类别个数
model.to(device)  


def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 训练集的大小
    num_batches = len(dataloader)   # 批次数目, (size/batch_size,向上取整)

    train_loss, train_acc = 0, 0  # 初始化训练损失和正确率
    
    for X, y in dataloader:  # 获取图片及其标签
        X, y = X.to(device), y.to(device)
        
        # 计算预测误差
        pred = model(X)          # 网络输出
        loss = loss_fn(pred, y)  # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
        
        # 反向传播
        optimizer.zero_grad()  # grad属性归零
        loss.backward()        # 反向传播
        optimizer.step()       # 每一步自动更新
        
        # 记录acc与loss
        train_acc  += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()
            
    train_acc  /= size
    train_loss /= num_batches

    return train_acc, train_loss


def test (dataloader, model, loss_fn):
    size        = len(dataloader.dataset)  # 测试集的大小
    num_batches = len(dataloader)          # 批次数目, (size/batch_size,向上取整)
    test_loss, test_acc = 0, 0
    
    # 当不进行训练时,停止梯度更新,节省计算内存消耗
    with torch.no_grad():
        for imgs, target in dataloader:
            imgs, target = imgs.to(device), target.to(device)
            
            # 计算loss
            target_pred = model(imgs)
            loss        = loss_fn(target_pred, target)
            
            test_loss += loss.item()
            test_acc  += (target_pred.argmax(1) == target).type(torch.float).sum().item()

    test_acc  /= size
    test_loss /= num_batches

    return test_acc, test_loss



def adjust_learning_rate(optimizer, epoch, start_lr):
    # 每 2 个epoch衰减到原来的 0.98
    lr = start_lr * (0.92 ** (epoch // 2))
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

learn_rate = 1e-3 # 初始学习率
optimizer  = torch.optim.SGD(model.parameters(), lr=learn_rate)


import copy

loss_fn    = nn.CrossEntropyLoss() # 创建损失函数
epochs     = 40

train_loss = []
train_acc  = []
test_loss  = []
test_acc   = []

best_acc = 0    # 设置一个最佳准确率,作为最佳模型的判别指标

for epoch in range(epochs):
    # 更新学习率(使用自定义学习率时使用)
    # adjust_learning_rate(optimizer, epoch, learn_rate)
    
    model.train()
    epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)
    scheduler.step() # 更新学习率(调用官方动态学习率接口时使用)
    
    model.eval()
    epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
    
    # 保存最佳模型到 best_model
    if epoch_test_acc > best_acc:
        best_acc   = epoch_test_acc
        best_model = copy.deepcopy(model)
    
    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)
    
    # 获取当前的学习率
    lr = optimizer.state_dict()['param_groups'][0]['lr']
    
    template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')
    print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, 
                          epoch_test_acc*100, epoch_test_loss, lr))
    
# 保存最佳模型到文件中
PATH = '/home/kaijiang/zlf/CSDN task/the six week/best_model.pth'  # 保存的参数文件名
torch.save(model.state_dict(), PATH)

print('Done')

二、模型评估

1、恒定learn_rate = 1e-4,epoch=40

在这里插入图片描述
在这里插入图片描述

2、动态 learn_rate = 1e-4,epoch=40

在这里插入图片描述
在这里插入图片描述

3、恒定学习率 learn_rate = 1e-3,epoch=40

在这里插入图片描述
在这里插入图片描述

4、 动态 learn_rate = 1e-3,epoch=40

在这里插入图片描述
在这里插入图片描述

5、动态 learn_rate = 1e-2,epoch=30

在这里插入图片描述
在这里插入图片描述

6、恒定 learn_rate = 1e-2,epoch=40

在这里插入图片描述
在这里插入图片描述

三、理论基础

VGG是牛津大学视觉组(Visual Geometry Group)在2014年提出来的,并取得了 ImageNet 2014比赛分类组的第二名和定位任务的第一名。
在这里插入图片描述
VGG的改进
1.采用3*3的小尺寸的卷积核,步长为1,参数量更少;
2.去掉了LRN层
  LRN是Local Response Normalization的缩写,即局部响应归一化。
  LRN层是一种规范化技术,用于增强深度神经网络模型的泛化性能。它在卷积层之后被应用,旨在提高网络对于不同位置的特征响应强度的鲁棒性。
  局部响应归一化通过对每个神经元及其相邻神经元的输出进行归一化来实现。具体而言,对于给定的神经元,它将其输出除以一个归一化参数,该归一化参数由该神经元的邻近神经元输出的平方和加上一个较小的常数来计算。
LRN层的目的是提供一种竞争机制,使得输出较大的神经元能够在邻近神经元的竞争中更为突出。这样可以增强网络对于局部特征的感知能力,并提高网络的鲁棒性。
  需要注意的是,在后续的卷积神经网络的研究和实践中,LRN层并不常见,有时会被其他正则化技术(如批标准化)所取代。
3.VGG还 有一个结构特点是重复使用简单的卷积块(Convolution Block)来堆叠得到模型

四、训练结论

1、为什么初始学习率增大以后,VGG测试集的准确率提高了20个百分点?

  始学习率增大后,VGG测试集准确率提高20个百分点可能是由于以下原因之一或者几个因素的结合:

(1)收敛速度更快: 增大初始学习率可能会加快模型的收敛速度,使模型在相同的训练轮次内达到更高的准确率。

(2)学习步长更大: 增大初始学习率会使每次参数更新的步长增加,这有助于跳出局部最优解并更快地找到全局最优解。这可能导致模型更好地捕捉数据集的特征,从而提高测试集的准确率。

(3)泛化能力更好: 一些情况下,增大初始学习率可能会帮助模型更好地泛化到测试集数据。通过在更大的学习率下训练,模型可能更能够适应数据的多样性,从而提高测试集的准确率。

(4)减少过拟合: 在某些情况下,增大初始学习率可能有助于减少模型的过拟合,尤其是在正则化不足的情况下。更大的学习率可能会导致模型更快地达到平滑的参数值,从而减少过拟合的可能性,提高测试集的准确率。
  但是增大初始学习率可能也会带来一些负面影响,如训练过程中的不稳定性、易于跳过最优解等。因此,在调整学习率时需要进行适当的实验和验证,以确保获得最佳的模型性能。

2、为什么在训练VGG16的时候,将学习率从1e-3变为1e-4以后,训练时间变长?

(1)学习率影响收敛速度: 学习率的大小直接影响模型参数在训练过程中的调整步长。较高的学习率(如1e-3)会导致参数在每次更新时发生较大的变化,模型可能更快地收敛到局部最优点或者陷入局部最优点附近的震荡状态。而较低的学习率(如1e-4)则会使参数调整变得更加缓慢,需要更多的训练迭代才能达到相同的收敛程度。

(2)学习率影响训练稳定性: 过高的学习率可能导致训练过程中出现训练不稳定的情况,如发散或者在局部最优点附近震荡。通过降低学习率,训练过程可能更加稳定,但相应地需要更多的迭代次数才能达到较好的训练效果。

(3)调整学习率需要更多迭代: 降低学习率通常需要更多的训练迭代次数才能达到相同的收敛效果。因此,当你将学习率从1e-3降低到1e-4时,模型可能需要更长的训练时间才能达到相同的性能水平。

(4)模型参数调整速度减慢: 较低的学习率意味着模型参数在训练过程中的调整速度减慢,因此需要更多的迭代次数才能达到最优的参数设置。

  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本课程适合具有一定深度学习基础,希望发展为深度学习之计算机视觉方向的算法工程师和研发人员的同学们。基于深度学习的计算机视觉是目前人工智能最活跃的领域,应用非常广泛,如人脸识别和无人驾驶中的机器视觉等。该领域的发展日新月异,网络模型和算法层出不穷。如何快速入门并达到可以从事研发的高度对新手和中级水平的学生而言面临不少的挑战。精心准备的本课程希望帮助大家尽快掌握基于深度学习的计算机视觉的基本原理、核心算法和当前的领先技术,从而有望成为深度学习之计算机视觉方向的算法工程师和研发人员。本课程系统全面地讲述基于深度学习的计算机视觉技术的原理并进行项目实践。课程涵盖计算机视觉的七大任务,包括图像分类、目标检测、图像分割(语义分割、实例分割、全景分割)、人脸识别、图像描述、图像检索、图像生成(利用生成对抗网络)。本课程注重原理和实践相结合,逐篇深入解读经典和前沿论文70余篇,图文并茂破译算法难点, 使用思维导图梳理技术要点。项目实践使用Keras框架(后端为Tensorflow),学员可快速上手。通过本课程的学习,学员可把握基于深度学习的计算机视觉的技术发展脉络,掌握相关技术原理和算法,有助于开展该领域的研究与开发实战工作。另外,深度学习之计算机视觉方向的知识结构及学习建议请参见本人CSDN博客。本课程提供课程资料的课件PPT(pdf格式)和项目实践代码,方便学员学习和复习。本课程分为上下两部分,其中上部包含课程的前五章(课程介绍、深度学习基础、图像分类、目标检测、图像分割),下部包含课程的后四章(人脸识别、图像描述、图像检索、图像生成)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值