在自定义数据集上使用 Detectron2 和 PyTorch 进行人脸检测

news2025/1/12 22:48:25

本文讲讲述如何使用Python在自定义人脸检测数据集上微调预训练的目标检测模型。学习如何为Detectron2和PyTorch准备自定义人脸检测数据集,微调预训练模型以在图像中找到人脸边界。

人脸检测是在图像中找到(边界的)人脸的任务。这在以下情况下很有用:

  • 安全系统(识别人员的第一步)

  • 为拍摄出色的照片进行自动对焦和微笑检测

  • 检测年龄、种族和情感状态以用于营销

1b5f0fcaea773df53fcb08e057aff96f.png

历史上,这是一个非常棘手的问题。大量的手动特征工程、新颖的算法和方法被开发出来以改进最先进技术。

如今,人脸检测模型已经包含在几乎每个计算机视觉包/框架中。其中一些表现最佳的模型使用了深度学习方法。例如,OpenCV提供了各种工具,如级联分类器。

在本指南中,您将学习如何:

  • 准备一个用于人脸检测的自定义数据集,以用于Detectron2

  • 使用(接近)最先进的目标检测模型在图像中查找人脸

  • 您可以将这项工作扩展到人脸识别

Detectron2

Detectron2是一个用于构建最先进的目标检测和图像分割模型的框架,由Facebook Research团队开发。Detectron2是第一个版本的完全重写。Detectron2使用PyTorch(与最新版本兼容),并且允许进行超快速训练。您可以在Facebook Research的入门博客文章中了解更多信息。

Detectron2的真正强大之处在于模型动物园中提供了大量的预训练模型。但是,如果您不能在自己的数据集上对其进行微调,那又有什么好处呢?幸运的是,这非常容易!在本指南中,我们将看到如何完成这项工作。

安装Detectron2

在撰写本文时,Detectron2仍处于alpha阶段。虽然有官方版本,但我们将从主分支克隆和编译。这应该等于版本0.1。让我们首先安装一些要求:

!pip install -q cython pyyaml == 5.1 
!pip install -q -U 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'

然后,下载、编译和安装Detectron2包: 

!git clone https://github.com/facebookresearch/detectron2 detectron2_repo 
!pip install -q -e detectron2_repo

此时,您需要重新启动笔记本运行时以继续!

%reload_ext watermark %watermark -v -p numpy,pandas,pycocotools,torch,torchvision,detectron2
CPython 3.6.9
IPython 5.5.0
numpy 1.17.5
pandas 0.25.3
pycocotools 2.0
torch 1.4.0
torchvision 0.5.0
detectron2 0.1
import torch, torchvision
import detectron2
from detectron2.utils.logger import setup_logger
setup_logger()


import glob


import os
import ntpath
import numpy as np
import cv2
import random
import itertools
import pandas as pd
from tqdm import tqdm
import urllib
import json
import PIL.Image as Image


from detectron2 import model_zoo
from detectron2.engine import DefaultPredictor, DefaultTrainer
from detectron2.config import get_cfg
from detectron2.utils.visualizer import Visualizer, ColorMode
from detectron2.data import DatasetCatalog, MetadataCatalog, build_detection_test_loader
from detectron2.evaluation import COCOEvaluator, inference_on_dataset
from detectron2.structures import BoxMode


import seaborn as sns
from pylab import rcParams
import matplotlib.pyplot as plt
from matplotlib import rc


%matplotlib inline
%config InlineBackend.figure_format='retina'


sns.set(style='whitegrid', palette='muted', font_scale=1.2)


HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#ADFF02", "#8F00FF"]


sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))


rcParams['figure.figsize'] = 12, 8


RANDOM_SEED = 42
np.random.seed(RANDOM_SEED)
torch.manual_seed(RANDOM_SEED)

人脸检测数据

该数据集在公共领域免费提供。它由Dataturks提供,并托管在Kaggle上:图像中标有边界框的人脸。有大约500张图像,通过边界框手动标记了大约1100个人脸。

我已经下载了包含注释的JSON文件,并将其上传到了Google Drive。让我们获取它:

!gdown --id 1K79wJgmPTWamqb04Op2GxW0SW9oxw8KS

让我们将文件加载到Pandas数据框中:

faces_df = pd.read_json('face_detection.json', lines=True)

每行包含一个单独的人脸注释。请注意,多行可能指向单个图像(例如,每个图像有多个人脸)。

数据预处理

数据集仅包含图像URL和注释。我们将不得不下载这些图像。我们还将对注释进行标准化,以便稍后在Detectron2中更容易使用:

os.makedirs("faces", exist_ok=True)


dataset = []


for index, row in tqdm(faces_df.iterrows(), total=faces_df.shape[0]):
    img = urllib.request.urlopen(row["content"])
    img = Image.open(img)
    img = img.convert('RGB')


    image_name = f'face_{index}.jpeg'


    img.save(f'faces/{image_name}', "JPEG")


    annotations = row['annotation']
    for an in annotations:


      data = {}


      width = an['imageWidth']
      height = an['imageHeight']
      points = an['points']


      data['file_name'] = image_name
      data['width'] = width
      data['height'] = height


      data["x_min"] = int(round(points[0]["x"] * width))
      data["y_min"] = int(round(points[0]["y"] * height))
      data["x_max"] = int(round(points[1]["x"] * width))
      data["y_max"] = int(round(points[1]["y"] * height))


      data['class_name'] = 'face'


      dataset.append(data)

让我们将数据放入数据框中,以便我们可以更好地查看:

df = pd.DataFrame(dataset)
print(df.file_name.unique().shape[0], df.shape[0])
409 1132

我们总共有409张图像(比承诺的500张少得多)和1132个注释。让我们将它们保存到磁盘上(以便您可以重用它们):

数据

让我们查看一些示例注释数据。我们将使用OpenCV加载图像,添加边界框并调整大小。我们将定义一个助手函数来完成所有这些操作:

def annotate_image(annotations, resize=True):
  file_name = annotations.file_name.to_numpy()[0]
  img = cv2.cvtColor(cv2.imread(f'faces/{file_name}'), cv2.COLOR_BGR2RGB)


  for i, a in annotations.iterrows():
    cv2.rectangle(img, (a.x_min, a.y_min), (a.x_max, a.y_max), (0, 255, 0), 2)


  if not resize:
    return img


  return cv2.resize(img, (384, 384), interpolation = cv2.INTER_AREA)

让我们首先显示一些带注释的图像:

5cd702ae92b05f2ecba0f1a2e0cdfd68.png

f6740914dcb440fcd84269b6d24ebff5.png

这些都是不错的图像,注释清晰可见。我们可以使用torchvision创建一个图像网格。请注意,这些图像具有不同的大小,因此我们将对其进行调整大小:

2c212409437c164de8cc81fa25a9b218.png

您可以清楚地看到一些注释缺失(第4列)。这就是现实生活中的数据,有时您必须以某种方式处理它。

使用Detectron 2进行人脸检测

现在,我们将逐步介绍使用自定义数据集微调模型的步骤。但首先,让我们保留5%的数据进行测试:

df = pd.read_csv('annotations.csv')


IMAGES_PATH = f'faces'


unique_files = df.file_name.unique()


train_files = set(np.random.choice(unique_files, int(len(unique_files) * 0.95), replace=False))
train_df = df[df.file_name.isin(train_files)]
test_df = df[~df.file_name.isin(train_files)]

在这里,经典的训练测试分割方法不适用,因为我们希望在文件名之间进行分割。

接下来的部分以稍微通用的方式编写。显然,我们只有一个类别-人脸。但是,添加更多类别应该就像向数据框中添加更多注释一样简单:

classes = df.class_name.unique().tolist()

接下来,我们将编写一个将我们的数据集转换为Detectron2:

def create_dataset_dicts(df, classes):
  dataset_dicts = []
  for image_id, img_name in enumerate(df.file_name.unique()):


    record = {}


    image_df = df[df.file_name == img_name]


    file_path = f'{IMAGES_PATH}/{img_name}'
    record["file_name"] = file_path
    record["image_id"] = image_id
    record["height"] = int(image_df.iloc[0].height)
    record["width"] = int(image_df.iloc[0].width)


    objs = []
    for _, row in image_df.iterrows():


      xmin = int(row.x_min)
      ymin = int(row.y_min)
      xmax = int(row.x_max)
      ymax = int(row.y_max)


      poly = [
          (xmin, ymin), (xmax, ymin),
          (xmax, ymax), (xmin, ymax)
      ]
      poly = list(itertools.chain.from_iterable(poly))


      obj = {
        "bbox": [xmin, ymin, xmax, ymax],
        "bbox_mode": BoxMode.XYXY_ABS,
        "segmentation": [poly],
        "category_id": classes.index(row.class_name),
        "iscrowd": 0
      }
      objs.append(obj)


    record["annotations"] = objs
    dataset_dicts.append(record)
  return dataset_dicts

使用的格式的函数:我们将每个注释行转换为一个具有注释列表的单个记录。您可能还会注意到,我们正在构建一个与边界框完全相同形状的多边形。这对于Detectron2中的图像分割模型是必需的。

您将不得不将数据集注册到数据集和元数据目录中:

for d in ["train", "val"]:
  DatasetCatalog.register("faces_" + d, lambda d=d: create_dataset_dicts(train_df if d == "train" else test_df, classes))
  MetadataCatalog.get("faces_" + d).set(thing_classes=classes)


statement_metadata = MetadataCatalog.get("faces_train")

不幸的是,默认情况下不包含测试集的评估器。我们可以通过编写自己的训练器轻松修复它:

class CocoTrainer(DefaultTrainer):


  @classmethod
  def build_evaluator(cls, cfg, dataset_name, output_folder=None):


    if output_folder is None:
        os.makedirs("coco_eval", exist_ok=True)
        output_folder = "coco_eval"


    return COCOEvaluator(dataset_name, cfg, False, output_folder)

如果未提供文件夹,则评估结果将存储在coco_eval文件夹中。

在Detectron2模型上微调与编写PyTorch代码完全不同。我们将加载配置文件,更改一些值,然后启动训练过程。但是嘿,如果您知道自己在做什么,这真的会有所帮助。在本教程中,我们将使用Mask R-CNN X101-FPN模型。它在COCO数据集上进行了预训练,并且表现非常好。缺点是训练速度较慢。

让我们加载配置文件和预训练的模型权重:

cfg = get_cfg()


cfg.merge_from_file(
  model_zoo.get_config_file(
    "COCO-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_3x.yaml"
  )
)


cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(
  "COCO-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_3x.yaml"
)

指定我们将用于训练和评估的数据集(我们注册了这些数据集):

cfg.DATASETS.TRAIN = ("faces_train",)
cfg.DATASETS.TEST = ("faces_val",)
cfg.DATALOADER.NUM_WORKERS = 4

至于优化器,我们将进行一些魔法以收敛到某个好的值:

cfg.SOLVER.IMS_PER_BATCH = 4
cfg.SOLVER.BASE_LR = 0.001
cfg.SOLVER.WARMUP_ITERS = 1000
cfg.SOLVER.MAX_ITER = 1500
cfg.SOLVER.STEPS = (1000, 1500)
cfg.SOLVER.GAMMA = 0.05

除了标准的内容(批量大小、最大迭代次数和学习率)外,我们还有几个有趣的参数:

  • WARMUP_ITERS - 学习率从0开始,并在此次数的迭代中逐渐增加到预设值

  • STEPS - 学习率将在其检查点(迭代次数)降低的次数

最后,我们将指定类别的数量以及我们将在测试集上进行评估的周期:

cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 64
cfg.MODEL.ROI_HEADS.NUM_CLASSES = len(classes)


cfg.TEST.EVAL_PERIOD = 500

是时候开始训练了,使用我们自定义的训练器:

os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)


trainer = CocoTrainer(cfg)
trainer.resume_or_load(resume=False)
trainer.train()

评估目标检测模型

与评估标准分类或回归模型相比,评估目标检测模型有点不同。您需要了解的主要指标是IoU(交并比)。它测量两个边界之间的重叠程度-预测的和真实的。它可以在0和1之间获得值。

a363c6b48bd9d29d9f2e4509c5cc8eb5.png

使用IoU,可以定义阈值(例如> 0.5)来分类预测是否为真阳性(TP)或假阳性(FP)。现在,您可以通过获取精度-召回曲线下的区域来计算平均精度(AP)现在,AP@X(例如AP50)只是某个IoU阈值下的AP。这应该让您对如何评估目标检测模型有一个工作的了解。

我已经准备了一个预训练模型,因此不必等待训练完成。下载它:

!gdown --id 18Ev2bpdKsBaDufhVKf0cT6RmM3FjW3nL 
!mv face_detector.pth output/model_final.pth

我们可以通过加载模型并设置最低的85%的置信度阈值来开始进行预测,以此来将预测视为正确:

cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, "model_final.pth")
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.85
predictor = DefaultPredictor(cfg)

运行评估器与训练好的模型:

evaluator = COCOEvaluator("faces_val", cfg, False, output_dir="./output/")
val_loader = build_detection_test_loader(cfg, "faces_val")
inference_on_dataset(trainer.model, val_loader, evaluator)

在图像中查找人脸

接下来,让我们创建一个文件夹,并保存测试集中所有带有预测注释的图像:

os.makedirs("annotated_results", exist_ok=True)


test_image_paths = test_df.file_name.unique()
for clothing_image in test_image_paths:
  file_path = f'{IMAGES_PATH}/{clothing_image}'
  im = cv2.imread(file_path)
  outputs = predictor(im)
  v = Visualizer(
    im[:, :, ::-1],
    metadata=statement_metadata,
    scale=1.,
    instance_mode=ColorMode.IMAGE
  )
  instances = outputs["instances"].to("cpu")
  instances.remove('pred_masks')
  v = v.draw_instance_predictions(instances)
  result = v.get_image()[:, :, ::-1]
  file_name = ntpath.basename(clothing_image)
  write_res = cv2.imwrite(f'annotated_results/{file_name}', result)

eaef04c00ad6f46682d79e21682c449c.png

·  END  ·

HAPPY LIFE

c941539f67c96091161bb2db5bd893b7.png

本文仅供学习交流使用,如有侵权请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/897345.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32F40X系列FSMC8路驱动LCD显示屏(LY-TFT30-39P-1509 芯片hx8352)

hx8352_8080_8bit_FMSC板级驱动 1.LCD相关1.1LCD参数1.2 LCD引脚1.3 LCD实物1.4 LCD引脚解释 2.接线关系3.STM32F40x基于FMSC16bit修改1)地址偏移2)删除多余GPIO3)修改FMSC的配置4)LCD初始化寄存器 3.板驱动程序4.运行结果 1.LCD相关 1.1LCD参数 LCD控制芯片&…

C数据结构与算法——无向图(最小生成树) 应用

实验任务 (1) 掌握Kruskal最小生成树算法; (2) 掌握Prim最小生成树算法。 实验内容 (1) 随机生成一个无向网 G ( V, E ),V { A, B, C, D, E, F },| E | 11,边的权值取值范围为 [ 1, 40 ]; (2) 使用Prim算法求出图…

离散化思想——只处理有效数据的优化思想

离散化思想——只处理有效数据的优化思想 什么是离散化离散化题目——校门外的树(超强版,1e9)题目描述输入格式输出格式样例样例输入样例输出 提示 思路分析朴素做法离散化!!代码分析数组循环 什么是离散化 离散化思想…

C语言之浮点数_数据存储篇(2)

目录 浮点数 什么是浮点数呢? 为什么叫浮点数? 浮点数家族 浮点数表示的范围? 浮点数存储的例子 浮点数的存储方式 写成规定形式是怎样的? 那SME在内存中如何分配的呢? 为什么要这样存储? 浮点…

44、TCP报文(二)

接上节内容,本节我们继续TCP报文首部字段含义的学习。上节为止我们学习到“数据偏移”和“保留”字段。接下来我们学习后面的一些字段(暂不包含“检验和”的计算方法和选项字段)。 TCP首部结构(续) “数据偏移”和“保…

人工智能在车牌识别中的应用与影响

引言:车牌识别技术是基于人工智能的一种重要应用,通过对监控视频中的车辆图像进行处理和分析,可以快速、准确地识别车牌号码。这项技术的广泛应用可以帮助交通管理、停车场管理,甚至追踪犯罪嫌疑人的车辆。本文将详细探讨车牌识别…

从LeakCanary看ViewModel生命周期监控

前面两篇文章中已经了解了LeakCanary中Service和Fragment生命周期监控的实现,那么ViewModel生命周期监控又是怎么实现的呢? 同样的,要了解ViewModel生命周期监控,我们首先应该清楚在代码结构中ViewModel是如何存储获取的&#xf…

【零基础自用】理解python为什么要用虚拟环境

不知道学过MATLAB或者R的小伙伴刚刚接触python的时候会不会被各种python版本,包版本,虚拟环境之类的搞的头晕眼花。 问题一 包版本 先来假设,我们自己开发了一个包MyPackage 1.0,里面包含一个模块叫PreTrained,然后去…

Python爬虫(十三)_案例:使用XPath的爬虫

本篇是使用XPath的案例 案例:使用XPath的爬虫 现在我们用XPath来做一个简单的爬虫,我们尝试爬取某个贴吧里的所有帖子且将该帖子里每个楼层发布的图片下载到本地。 #-*- coding:utf-8 -*- #tieba_xpath.py"""作用:本案例使用…

【AGC】Publishing api怎么上传绿色认证审核材料

【问题描述】 华为应用市场会对绿色应用标上特有的绿色标识,代表其通过华为终端开放实验室DevEco云测平台的兼容性、稳定性、安全、功耗和性能的检测和认证,是应用高品质的象征。想要自己的应用认证为绿色应用就需要在发布应用时提供绿色认证审核材料&a…

Go语言基础之基本数据类型

Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道(channel)等。Go 语言的基本类型和其他语言大同小异。 基本数据类型 整型 整型分为以下两个大类: 按…

echarts 关于折线统计图常用的属性设置--超详细(附加源码)

文章目录 折线统计图设置x轴字体大小及字体颜色设置y轴字体大小及字体颜色设置背景颜色及设置折线颜色设置折线效果图显示阴影折线图位置及标签位置设置鼠标悬浮折线弹出窗口显示对应的数据设置自动横向滚动 总结 大家好!近期我会分享几篇关于echarts方面的技术点&a…

easy-es 使用

1、pom中引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.14.0</version></dependency><dependency><groupId>org.…

CentOS ens160 显示disconnected

使用nmcli device查看网卡状态&#xff0c;显示如图&#xff1a; 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮&#xff0c;打开计算机管理点击服务

C语言实例_异或校验算法

一、异或校验算法 异或校验算法&#xff08;XOR校验&#xff09;是一种简单的校验算法&#xff0c;用于检测数据在传输或存储过程中是否发生了错误。通过将数据中的所有比特位相异或&#xff0c;生成一个校验码&#xff0c;然后将该校验码与接收到的数据进行比较&#xff0c;以…

如何大幅提高遥感影像分辨率(Python+MATLAB)

前言: 算法:NSCT算法(非下采样变换) 数据:Landsat8 OLI 遥感图像数据 编程平台:MATLAB+Python 论文参考:毛克.一种快速的全色和多光谱图像融合算法[J].测绘科学,2016,41(01):151-153+98.DOI:10.16251/j.cnki.1009-2307.2016.01.028. 左图:未进行融合的多光谱真彩色合…

ChatGPT逐句逐句地解释代码并分析复杂度的提示词prompt

前提安装chrome 插件 AI Prompt Genius&#xff0c; 请参考 3 个 ChatGPT 插件您需要立即下载 你是首席软件工程师。请解释这段代码&#xff1a;{{code}} 添加注释并重写代码&#xff0c;用注释解释每一行代码的作用。最后分析复杂度。快捷键 / 选择 Explain Code 输入代码提…

内网隧道代理技术(十七)之 NPS的使用

NPS的介绍和使用 NPS介绍 nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,可支持任何tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还支持内网http代理、内网socks5代理、p2p等,…

RFID技术助力汽车零配件装配产线,提升效率与准确性

随着科技的不断发展&#xff0c;越来越多的自动化设备被应用到汽车零配件装配产线中。其中&#xff0c;射频识别&#xff08;Radio Frequency Identification&#xff0c;简称RFID&#xff09;技术凭借其独特的优势&#xff0c;已经成为了这一领域的重要技术之一。本文将介绍RF…

Cpp基础Ⅰ之编译、链接

1 C是如何工作的 工具&#xff1a;Visual Studio 1.1 预处理语句 在.cpp源文件中&#xff0c;所有#字符开头的语句为预处理语句 例如在下面的 Hello World 程序中 #include<iostream>int main() {std::cout <"Hello World!"<std::endl;std::cin.get…