iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
AI & Data

電腦眼中的人臉--論近代人類都用電腦視覺技術在人臉上做了什麼系列 第 8

[第八夜] 人臉偵測 : MTCNN 的實做 Part.2-1 --用 Pytorch 建構自己的 MTCNN Model

  • 分享至 

  • xImage
  •  

前言

接下來我們會仔細講述應該如何訓練並且測試自己的 MTCNN Model,使用的語言為 Pytorch,我們逐步帶著大家實作並且講解每一步。因為是此系列的第一段實作,因此我們還是會比較詳細的講,那等大家習慣了整格流程之後,後續的主題實作則會言簡意賅地跟大家講述。

實作

實作MTCNN(Multi-task Cascaded Convolutional Networks)人臉偵測器需要使用 PyTorch,這是一個強大的深度學習框架。MTCNN是一種用於人臉偵測的前沿技術,它由三個網絡組成,每個網絡都負責不同的任務:檢測(detection)、對齊(alignment)和特徵提取(feature extraction)。在下面的示例中,我們將使用PyTorch實現MTCNN的檢測部分,也就是檢測人臉的網絡。完整的程式之後也會放連結上來給大家參考!

首先,確保你已經安裝了PyTorch,可以通過以下方式進行安裝:

pip install torch torchvision

Step.1 下載資料集

我們在這次實作中會使用到 WiderFace 這個資料集,請從官網下載,要下載Train & Validation 兩包資料集,下載後解壓縮並且放成這樣資料夾格式

./data_set/face_detection/
    |-----WIDER_train/
    |         |----images/
    |-----WIDER_val/
    |         |----images/

並且請下載這一份 label file,裡面包含著 Label ,格式為:

    照片路徑 人臉框左上X 人臉框左上Y 人臉框右下X 人臉框右下Y 

如果是多個人臉則會是:

    照片路徑 第一個人臉框左上X 第一個人臉框左上Y 第一個人臉框右下X 第一個人臉框右下Y 第二個人臉框左上X 第二個人臉框左上Y 第二個人臉框右下X 第二個人臉框右下Y ...

因為檔案要嚇得比較久,所以我們今天資料集先等下載就好!

Step.2 建立 Model

Step.2-1 建立 PNet

我們參考文中格式去使用 Pytorch 去建立以下模型,結構可參考這章提及的:

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import models

class PNet(nn.Module):
    def __init__(self):
        super(PNet, self).__init__()
        # 網絡層的定義
        self.conv1 = nn.Conv2d(3, 10, kernel_size=3, stride=1, padding=1)
        self.prelu1 = nn.PReLU(10)
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(10, 16, kernel_size=3, stride=1)
        self.prelu2 = nn.PReLU(16)
        self.conv3 = nn.Conv2d(16, 32, kernel_size=3, stride=1)
        self.prelu3 = nn.PReLU(32)
        
        # 檢測人臉的卷積層和輸出層, 預測 人臉/非人臉的分類, 人臉位置的偏移量
        self.conv4_1 = nn.Conv2d(32, 2, kernel_size=1, stride=1)
        self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1, stride=1)

    def forward(self, x):
        """
        Arguments:
            x: a float tensor with shape [batch_size, 3, h, w].
        Returns:
            out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
            out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
        """
        
        # 前向傳播過程
        x = self.conv1(x)
        x = self.prelu1(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = self.prelu2(x)
        x = self.conv3(x)
        x = self.prelu3(x)
        # 檢測人臉的輸出
        out_cls = torch.sigmoid(self.conv4_1(x))  # 人臉/非人臉的分類
        out_offset = self.conv4_2(x)  # 人臉位置的偏移量
        return out_cls, out_offset

# 初始化PNet模型
pnet = PNet()

上述程式定義了PNet,這是MTCNN中的第一個網絡,主要用於粗略檢測圖像中的人臉。這只是MTCNN的一部分,詳細的實做需要包括其他網絡(RNet和ONet)以及後處理步驟。要完整實現MTCNN,需要另外實現RNet和ONet,以及相關的後處理邏輯。

Step.2-2 建立 RNet & ONet

基本上建構邏輯與 PNet 相同我們都是根據原圖結構來建,注意ONet 一定要有預測出人臉關鍵點的分支喔(一個10維)

class RNet(nn.Module):

    def __init__(self,):

        super(RNet, self).__init__()        
        self.conv1 = nn.Conv2d(3, 28, kernel_size=3, stride=1, padding=1)
        self.prelu1 = nn.PReLU(28)
        self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
        
        self.conv2 = nn.Conv2d(28, 48, kernel_size=3, stride=1, padding=1)
        self.prelu2 = nn.PReLU(48)
        self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
        
        self.conv3 = nn.Conv2d(48, 64, kernel_size=2, stride=1, padding=1)
        self.prelu3 = nn.PReLU(64)
        
        self.conv4 = nn.Conv2d(576, 128, kernel_size=2, stride=1, padding=1)
        self.prelu4 = nn.PReLU(128)
        
        # 預測 人臉/非人臉的分類, 人臉位置的偏移量
        self.linear5_1 = nn.Linear(128, 2)
        self.linear5_2 = nn.Linear(128, 4)

    def forward(self, x):
        """
        Arguments:
            x: a float tensor with shape [batch_size, 3, h, w].
        Returns:
            out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
            out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
        """
       
        
        x = self.conv1(x)
        x = self.prelu1(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = self.prelu2(x)
        x = self.conv3(x)
        x = self.prelu3(x)
        
        
        # 攤平方便之後計算
        x = x.transpose(3, 2).contiguous()
        x = x.view(x.size(0), -1)
        
        x = self.conv4(x)
        x = self.prelu4(x)
        
        # 檢測人臉的輸出
        out_cls = torch.sigmoid(self.linear5_1(x))  # 人臉/非人臉的分類
        out_offset = self.linear5_2(x)  # 人臉位置的偏移量
        
        return out_cls, out_offset


class ONet(nn.Module):

    def __init__(self, is_train=False):

        super(ONet, self).__init__()

        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1)
        self.prelu1 = nn.PReLU(32)
        self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True)
        
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
        self.prelu2 = nn.PReLU(64)
        self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True)
        
        self.conv3 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1)
        self.prelu3 = nn.PReLU(64)
        self.pool3 = nn.MaxPool2d(2, 2, ceil_mode=True)
        
        self.conv4 = nn.Conv2d(64, 128, kernel_size=2, stride=1, padding=1)
        self.prelu4 = nn.PReLU(128)
        
        
        self.linear5 = nn.Linear(1152, 256)
        self.drop = nn.Dropout(0.25)
        self.prelu5 = nn.PReLU(256)
       
        # 預測 人臉/非人臉的分類, 人臉位置的偏移量, 人臉5點關鍵點位置
        self.linear6_1 = nn.Linear(256, 2)
        self.linear6_2 = nn.Linear(256, 4)
        self.linear6_3 = nn.Linear(256, 10)

    def forward(self, x):
        
        """
        Arguments:
            x: a float tensor with shape [batch_size, 3, h, w].
        Returns:
            out_cls: a float tensor with shape [batch_size, 2]. # 人臉/非人臉的分類
            out_offset: a float tensor with shape [batch_size, 4]. # 人臉位置的偏移量
            out_landmark: a float tensor with shape [batch_size, 10]. #人臉5點關鍵點位置
        """
       
        
        x = self.conv1(x)
        x = self.prelu1(x)
        x = self.pool1(x)
        
        x = self.conv2(x)
        x = self.prelu2(x)
        x = self.pool2(x)

        x = self.conv3(x)
        x = self.prelu3(x)
        x = self.pool3(x)
        
        x = self.conv4(x)
        x = self.prelu4(x)
        
        
        # 攤平方便之後計算
        x = x.transpose(3, 2).contiguous()
        x = x.view(x.size(0), -1)
        
        x = self.linear5(x)
        x = self.drop(x)
        x = self.prelu5(x)
        
        # 檢測人臉的輸出
        out_cls = torch.sigmoid(self.linear6_1(x))  # 人臉/非人臉的分類
        out_offset = self.linear6_2(x)  # 人臉位置的偏移量
        out_landmark = self.linear6_3(x)  # 人臉5點關鍵點位置
        
        return out_cls, out_offset, out_landmark

結語

我們今天已經下載完資料集跟建好模型了,那明天就要來寫訓練根資料/預測處裡了!

參考

1.https://pytorch.org/
2.http://shuoyang1213.me/WIDERFACE/
3.https://github.com/xuexingyu24/MTCNN_Tutorial/tree/master


上一篇
[第七夜] 人臉偵測 : MTCNN 的實做 Part.1 簡單用 OpenCV 體驗
下一篇
[第九夜] 人臉偵測 : MTCNN 的實做 Part.2-2 -- 使用 NMS 對預測框去蕪存菁
系列文
電腦眼中的人臉--論近代人類都用電腦視覺技術在人臉上做了什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言