P6:好莱坞明星识别

2023-10-13 22:30
文章标签 识别 好莱坞 明星 p6

本文主要是介绍P6:好莱坞明星识别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍦 参考文章:Pytorch实战 | 第P6周:好莱坞明星识别
  • 🍖 原作者:K同学啊 | 接辅导、项目定制
  • 🚀 文章来源:K同学的学习圈子

一、前期准备

1、设置GPU

import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib,warningswarnings.filterwarnings("ignore")             #忽略警告信息device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

关于忽略警告信息这一行,我在想为什么要设置一个“ignore”,有警告不看看?然后查资料发现是因为python有时会将能运行的代码报错,然后我想起来平时用pycharm时,确实会有很多那种黄色的小三角警告符显示“weak warning”,但是程序在运行后也没有错误,确实是可以ignore一下

device(type=‘cuda’)

2、导入数据

import os,PIL,random,pathlibdata_dir = './48-data/'
data_dir = pathlib.Path(data_dir)data_paths  = list(data_dir.glob('*'))
classeNames = [str(path).split("\\")[1] for path in data_paths]
classeNames

[‘Angelina Jolie’,
‘Brad Pitt’,
‘Denzel Washington’,
‘Hugh Jackman’,
‘Jennifer Lawrence’,
‘Johnny Depp’,
‘Kate Winslet’,
‘Leonardo DiCaprio’,
‘Megan Fox’,
‘Natalie Portman’,
‘Nicole Kidman’,
‘Robert Downey Jr’,
‘Sandra Bullock’,
‘Scarlett Johansson’,
‘Tom Cruise’,
‘Tom Hanks’,
‘Will Smith’]

train_transforms = transforms.Compose([ #compose将transforms的一系列方法进行包装,我们调用这个以进行依次有序地对数据进行处理。transforms模块包含了一系列的图像处理方法,数据的标准化、中心化、旋转、翻转等,都是为了增强数据,增强模型的泛化能力。transforms.Resize([224, 224]),  # 这里开始数据预处理了,对于深度学习来说,数据的量和分布很重要。# transforms.RandomCrop(  ,padding=  )#这是我在查阅Compose时另外查到的一个处理模块,它是将图片进行随机裁剪。transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间# transforms.RandomHorizontalFlip(), # 随机水平翻转,之前我不理解这个的作用,其实这些都是数据处理的一些方法罢了,毕竟现实识别时实际情况与标准数据差别很大,这些工具的存在也是很有必要的。transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛mean=[0.485, 0.456, 0.406], #在送入网络之前将图片减去均值,消除公共部分,凸显特征和差异。std=[0.229, 0.224, 0.225])  # 这里我之前在想为什么平均值和标准差这里的数值一直都是一样的,然后查到这里是运用的imagenet的均值和标准差,他们是通过几百万张图片总结出来的数字,对很多图像处理模型都适用。
])total_data = datasets.ImageFolder("./48-data/",transform=train_transforms)
total_data

Dataset ImageFolder
Number of datapoints: 1800
Root location: ./48-data/
StandardTransform
Transform: Compose(
Resize(size=[224, 224], interpolation=bilinear, max_size=None, antialias=None)
ToTensor()
Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
)

total_data.class_to_idx #将类别名称化为索引,以便模型的训练和预测。

{‘Angelina Jolie’: 0,
‘Brad Pitt’: 1,
‘Denzel Washington’: 2,
‘Hugh Jackman’: 3,
‘Jennifer Lawrence’: 4,
‘Johnny Depp’: 5,
‘Kate Winslet’: 6,
‘Leonardo DiCaprio’: 7,
‘Megan Fox’: 8,
‘Natalie Portman’: 9,
‘Nicole Kidman’: 10,
‘Robert Downey Jr’: 11,
‘Sandra Bullock’: 12,
‘Scarlett Johansson’: 13,
‘Tom Cruise’: 14,
‘Tom Hanks’: 15,
‘Will Smith’: 16}

3、划分数据集

train_size = int(0.8 * len(total_data)) #这里我尝试改过,从0.7到0.9,发现效果都不是很好,应该百分十八十的量九十比较好的训练集比例了。
test_size  = len(total_data) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])#pytorch里的随机分化数据集的函数,刚刚查到这个效果相当于设置随机种子
"""昨天晚上我提问的时候有人告诉我我的准确率波动可能是种子没设置,我还现查了种子是什么东西,
然后查怎么设定种子,但是看了一大篇回答一头雾水。
"""
train_dataset, test_dataset

(<torch.utils.data.dataset.Subset at 0x2570a8b6680>,
<torch.utils.data.dataset.Subset at 0x2570a8b67a0>)

batch_size = 1
"""
我在开始尝试怎么做才能优化准确率的时候,搜到增大batch_size可以增大准确率,结果就在
那里增加,然后等。结果发现根本没用。然后我意识到这是一个整体我,我仅仅这样改一个是
没有办法直接得到优化结果的。然后我查到batch就是相当于把数据分成多少份,batch_size
就是每份的大小。要想增加准确率其实该减小batch_size。这样增加了运算次数,延长了运算
时间。提高batch_size主要还是提高效率,提升GPU使用效率而已。
"""
train_dl = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,
"""
我查到的shuffer=Ture表示在每一次epoch中都打乱所有数据的顺序,然后以batch为单位从头
到尾按顺序取用数据。这样的结果就是不同epoch中的数据都是乱序的。刚刚又查到就是在这里
设置随机种子就能使每一次运行的数据是乱的,但是不同次之间都是一样的乱序,感觉就是这里
了,之后好好试试。
"""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

Shape of X [N, C, H, W]: torch.Size([1, 3, 224, 224])
Shape of y: torch.Size([1]) torch.int64

二、调用官方的VGG-16模型

from torchvision.models import vgg16device = "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)  
model

之前专门找了卷积和池化的知识点看,感觉大致懂了。但是将他们合并起来过后我就有点懵了。卷积是通过卷积核和权重将图片特征提取。我感觉就是将卷积核依次选取的部分进行一定程度的“模糊化”,好让以后识别到其他有类似的特征的图片能识别,就像人名之间重复很少,但是提取出来姓氏就能匹配到一大批相同姓氏的人,然后后面再经过平均池化啊最大池化这些再将提取出来的特征筛选,然后再全连接,就拼接成了相同姓氏的可能和你有关系的人的一个大的一维数据,我是这么理解的。但是实际上看了很多解释感觉都说的云里雾里的。最近找到一些“Pytorch学习笔记”之类标题的文章,这些就是分享他们自己的理解,我感觉看了这些感觉好了很多。

Using cuda device

VGG(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace=True)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace=True)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace=True)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace=True)
(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): ReLU(inplace=True)
(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace=True)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace=True)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): ReLU(inplace=True)
(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): ReLU(inplace=True)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace=True)
(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=17, bias=True)
)
)

三、训练模型

1. 编写训练函数

# 训练循环
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与losstrain_acc  += (pred.argmax(1) == y).type(torch.float).sum().item()train_loss += loss.item()train_acc  /= sizetrain_loss /= num_batchesreturn train_acc, train_loss

我理解的损失函数是在每一次正向传播完了过后倒过来反向传播时,评判前一次正向传播好不好的东西。我感觉我能理解损失函数的原理,就是到了代码这里想不明白到底是怎么进行评估的,看了很多回答,有一种似懂非懂的感觉。

2.编写测试函数

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)# 计算losstarget_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  /= sizetest_loss /= num_batchesreturn test_acc, test_loss

3. 设置动态学习率

learn_rate = 1e-6

这个东西我好好看了,因为都说这个很重要。我现在掌握的概念是学习率相当于一种探测,它在那个函数两侧跳来跳去不断向下知道最低谷也就是最优值,学习率大了会一直反复横跳,难以下降到谷底,相当于步子跨大了,老是把那个最优值给跨过去。但是学习率过于小有导致步子太小,效率底下。这里之前我想的是我设的足够小大不了就是运算时间长一点罢了,但是我实际运算发现过分小了过后还是会有准确率在每一个epoch之间波动特别大的问题,而且越小越离谱,这个目前我还没想明白为什么。

# 调用官方动态学习率接口时使用
lambda1 = lambda epoch: 0.92 ** (epoch // 4)
optimizer = torch.optim.SGD(model.parameters(), lr=learn_rate)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1) #选定调整方法
import copyloss_fn    = nn.CrossEntropyLoss() # 创建损失函数
epochs     = 40train_loss = []
train_acc  = []
test_loss  = []
test_acc   = []best_acc = 60    # 设置一个最佳准确率,作为最佳模型的判别指标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_modelif epoch_test_acc > best_acc:best_acc   = epoch_test_accbest_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 = './best_model.pth'  # 保存的参数文件名
torch.save(model.state_dict(), PATH)print('Done')

我现在仔细看了这一段发现其实改这一段其实才是最最主要的,我一直以为这里是一个封装好的固定模型,我不能轻易改,但现在看来好像这里的损失函数,设置的epoch数都挺重要的。主要是以前一直都在查前面的知识。我应该改变一下思路,不能一点一点学。有时候先学后面说不定前面就懂了,感觉我现在的学习思维和能力还停留在中学,必须要手把手的教,但是后面应该会好起来的,我感觉学这个的过程中我走了超级多弯路,每天都在看从零开始学深度学习的书和文章,一直没有往前走,但是现在逐渐有了眉目了。接下来要把这些代码好好的亲手打一遍,就知道哪些可以改了。


这个图我当时测了很多次才出来,我还很高兴,想着终于通过自己的努力提高了准确率了,但是现在看来问题太多了,背后的逻辑我完全没有搞懂,但是在改这个文章的过程中我也在不断地查资料,感觉思路突然清晰了很多。果然学这些东西还是要勤上手,光看理论很难有进步。

四、 结果可视化

1. Loss与Accuracy图

import matplotlib.pyplot as plt#这个是导入了python的一个库,从而能将我们训练的过程和数据通过图表的方式显示出来,便于分析和查看,我理解为matlab的同级别存在。
#隐藏警告
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        #分辨率epochs_range = range(epochs)plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
"""
这些东西就很好理解了就是设置图片大小和标题、各轴的标示等。这里学好了生成的图
也很美观,要是要是有机会发论文那么会很有帮助。
"""
plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

PS:由于当时忘记保存,在这个准确率出来的时候我就把内核叫停了,然后拿去讨论为什么会出现准确率在每个EPOCH之间波动这么大去了,也没有用seed,后来才知道不断调参中断内核在继续本身就会对结果造成影响,现在再怎么测试也弄不出这个结果了,故而也没有这个图了。

2.指定图片进行预测

from PIL import Image classes = list(total_data.class_to_idx)def predict_one_image(image_path, model, transform, classes):test_img = Image.open(image_path).convert('RGB') #转换为三通道plt.imshow(test_img)  # 展示预测的图片test_img = transform(test_img)img = test_img.to(device).unsqueeze(0) #扩展维度model.eval()output = model(img)_,pred = torch.max(output,1)pred_class = classes[pred]print(f'预测结果是:{pred_class}')
# 预测训练集中的某张照片
predict_one_image(image_path='./48-data/Angelina Jolie/001_fe3347c0.jpg', model=model, transform=train_transforms, classes=classes)

预测结果是:Angelina Jolie

3.模型评估

best_model.eval()
epoch_test_acc, epoch_test_loss = test(test_dl, best_model, loss_fn)
epoch_test_acc, epoch_test_loss
# 查看是否与我们记录的最高准确率一致
epoch_test_acc

故以下这些数据都没有了

这篇关于P6:好莱坞明星识别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/206292

相关文章

使用PyTorch实现手写数字识别功能

《使用PyTorch实现手写数字识别功能》在人工智能的世界里,计算机视觉是最具魅力的领域之一,通过PyTorch这一强大的深度学习框架,我们将在经典的MNIST数据集上,见证一个神经网络从零开始学会识... 目录当计算机学会“看”数字搭建开发环境MNIST数据集解析1. 认识手写数字数据库2. 数据预处理的

Pytorch微调BERT实现命名实体识别

《Pytorch微调BERT实现命名实体识别》命名实体识别(NER)是自然语言处理(NLP)中的一项关键任务,它涉及识别和分类文本中的关键实体,BERT是一种强大的语言表示模型,在各种NLP任务中显著... 目录环境准备加载预训练BERT模型准备数据集标记与对齐微调 BERT最后总结环境准备在继续之前,确

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

使用Python开发一个图像标注与OCR识别工具

《使用Python开发一个图像标注与OCR识别工具》:本文主要介绍一个使用Python开发的工具,允许用户在图像上进行矩形标注,使用OCR对标注区域进行文本识别,并将结果保存为Excel文件,感兴... 目录项目简介1. 图像加载与显示2. 矩形标注3. OCR识别4. 标注的保存与加载5. 裁剪与重置图像

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

从希腊神话到好莱坞大片,人工智能的七大历史时期值得铭记

本文选自historyextra,机器之心编译出品,参与成员:Angulia、小樱、柒柒、孟婷 你可能听过「技术奇点」,即本世纪某个阶段将出现超级智能,那时,技术将会以人类难以想象的速度飞速发展。同样,黑洞也是一个奇点,在其上任何物理定律都不适用;因此,技术奇点也是超越未来理解范围的一点。 然而,在我们到达那个奇点之前(假设我们能到达),还存在另一个极大的不连续问题,我将它称之

Clion不识别C代码或者无法跳转C语言项目怎么办?

如果是中文会显示: 此时只需要右击项目,或者你的源代码目录,将这个项目或者源码目录标记为项目源和头文件即可。 英文如下:

BERN2(生物医学领域)命名实体识别与命名规范化工具

BERN2: an advanced neural biomedical named entity recognition and normalization tool 《Bioinformatics》2022 1 摘要 NER和NEN:在生物医学自然语言处理中,NER和NEN是关键任务,它们使得从生物医学文献中自动提取实体(如疾病和药物)成为可能。 BERN2:BERN2是一个工具,