<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    我用YOLOv5做情感識別!

    共 21020字,需瀏覽 43分鐘

     ·

    2022-01-19 21:46

    ↑ 點擊藍字 關(guān)注極市平臺

    作者 | 陳信達 
    來源 | Datawhale 
    編輯 | 極市平臺

    極市導(dǎo)讀

     

    今天筆者就教大家如何快速上手目標檢測模型YOLOv5,并將其應(yīng)用到情感識別中。 >>加入極市CV技術(shù)交流群,走在計算機視覺的最前沿

    AI技術(shù)已經(jīng)應(yīng)用到了我們生活中的方方面面,而目標檢測是其中應(yīng)用最廣泛的算法之一,疫情測溫儀器、巡檢機器人、甚至何同學(xué)的airdesk中都有目標檢測算法的影子。下圖就是airdesk,何同學(xué)通過目標檢測算法定位手機位置,然后控制無線充電線圈移動到手機下方自動給手機充電。

    這看似簡單的應(yīng)用背后其實是復(fù)雜的理論和不斷迭代的AI算法,今天筆者就教大家如何快速上手目標檢測模型YOLOv5,并將其應(yīng)用到情感識別中。

    一、背景

    今天的內(nèi)容來源于2019年發(fā)表在T-PAMI上的一篇文章[1],在這之前已經(jīng)有大量研究者通過AI算法識別人類情感,不過本文的作者認為,人們的情感不僅與面部表情和身體動作等有關(guān),還和當前身處的環(huán)境息息相關(guān),比如下圖的男孩應(yīng)該是一個驚訝的表情:

    不過加上周圍環(huán)境后,剛剛我們認為的情感就與真實情感不符:

    本文的主要思想就是將背景圖片和目標檢測模型檢測出的人物信息結(jié)合起來識別情感。

    其中,作者將情感分為離散和連續(xù)兩個維度。下面會解釋以方便理解,已經(jīng)清楚的同學(xué)可以快劃跳過。

    連續(xù)情感解釋
    Valence (V)measures how positive or pleasant an emotion is, ranging from negative to positive(高興程度)
    Arousal (A)measures the agitation level of the person, ranging from non-active / in calm to agitated / ready to act(激動程度)
    Dominance (D)measures the level of control a person feels of the situation, ranging from submissive / non-control to dominant / in-control(氣場大小)
    離散情感解釋
    Affectionfond feelings; love; tenderness
    Angerintense displeasure or rage; furious; resentful
    Annoyancebothered by something or someone; irritated; impatient; frustrated
    Anticipationstate of looking forward; hoping on or getting prepared for possible future events
    Aversionfeeling disgust, dislike, repulsion; feeling hate
    Confidencefeeling of being certain; conviction that an outcome will be favorable; encouraged; proud
    Disapprovalfeeling that something is wrong or reprehensible; contempt; hostile
    Disconnectionfeeling not interested in the main event of the surrounding; indifferent; bored; distracted
    Disquietmentnervous; worried; upset; anxious; tense; pressured; alarmed
    Doubt/Confusiondifficulty to understand or decide; thinking about different options
    Embarrassmentfeeling ashamed or guilty
    Engagementpaying attention to something; absorbed into something; curious; interested
    Esteemfeelings of favourable opinion or judgement; respect; admiration; gratefulness
    Excitementfeeling enthusiasm; stimulated; energetic
    Fatigueweariness; tiredness; sleepy
    Fearfeeling suspicious or afraid of danger, threat, evil or pain; horror
    Happinessfeeling delighted; feeling enjoyment or amusement
    Painphysical suffering
    Peacewell being and relaxed; no worry; having positive thoughts or sensations; satisfied
    Pleasurefeeling of delight in the senses
    Sadnessfeeling unhappy, sorrow, disappointed, or discouraged
    Sensitivityfeeling of being physically or emotionally wounded; feeling delicate or vulnerable
    Sufferingpsychological or emotional pain; distressed; anguished
    Surprisesudden discovery of something unexpected
    Sympathystate of sharing others emotions, goals or troubles; supportive; compassionate
    Yearningstrong desire to have something; jealous; envious; lust

    二、準備工作與模型推理

    2.1 快速入門

    只需完成下面五步即可識別情感!

    1. 通過克隆或者壓縮包將項目下載到本地:git clone https://github.com/chenxindaaa/emotic.git

    2. 將解壓后的模型文件放到emotic/debug_exp/models中。(模型文件下載地址:鏈接:https://gas.graviti.com/dataset/datawhale/Emotic/discussion)

    3. 新建虛擬環(huán)境(可選):

    conda create -n emotic python=3.7
    conda activate emotic
    1. 環(huán)境配置
    python -m pip install -r requirement.txt
    1. cd到emotic文件夾下,輸入并執(zhí)行:
    python detect.py

    運行完后結(jié)果會保存在emotic/runs/detect文件夾下。

    2.2 基本原理

    看到這里可能會有小伙伴問了:如果我想識別別的圖片該怎么改?可以支持視頻和攝像頭嗎?實際應(yīng)用中應(yīng)該怎么修改YOLOv5的代碼呢?

    對于前兩個問題,YOLOv5已經(jīng)幫我們解決,我們只需要修改detect.py中的第158行:

    parser.add_argument('--source', type=str, default='./testImages', help='source')  # file/folder, 0 for webcam

    將'./testImages'改為想要識別的圖像和視頻的路徑,也可以是文件夾的路徑。對于調(diào)用攝像頭,只需要將'./testImages'改為'0',則會調(diào)用0號攝像頭進行識別。

    修改YOLOv5:

    在detect.py中,最重要的代碼就是下面幾行:

    for *xyxy, conf, cls in reversed(det):
        c = int(cls)  # integer class
        if c != 0:
            continue
        pred_cat, pred_cont = inference_emotic(im0, (int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3])))
        if save_img or opt.save_crop or view_img:  # Add bbox to image
            label = None if opt.hide_labels else (names[c] if opt.hide_conf else f'{names[c]} {conf:.2f}')
            plot_one_box(xyxy, im0, pred_cat=pred_cat, pred_cont=pred_cont, label=label, color=colors(c, True), line_thickness=opt.line_thickness)
            if opt.save_crop:
                save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)

    其中det是YOLOv5識別出來的結(jié)果,例如tensor([[121.00000,  7.00000, 480.00000, 305.00000,  0.67680,  0.00000], [278.00000, 166.00000, 318.00000, 305.00000,  0.66222,  27.00000]])就是識別出了兩個物體。

    xyxy是物體檢測框的坐標,對于上面的例子的第一個物體,xyxy = [121.00000,  7.00000, 480.00000, 305.00000]對應(yīng)坐標(121, 7)和(480, 305),兩個點可以確定一個矩形也就是檢測框。conf是該物體的置信度,第一個物體置信度為0.67680。cls則是該物體對應(yīng)的類別,這里0對應(yīng)的是“人”,因為我們只識別人的情感,所以cls不是0就可以跳過該過程。這里我用了YOLOv5官方給的推理模型,其中包含很多類別,大家也可以自己訓(xùn)練一個只有“人”這一類別的模型,詳細過程可以參考:

    在識別出物體坐標后輸入emotic模型就可以得到對應(yīng)的情感,即

    pred_cat, pred_cont = inference_emotic(im0, (int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3])))

    這里我將原來的圖片可視化做了些改變,將emotic的結(jié)果打印到圖片上:

    def plot_one_box(x, im, pred_cat, pred_cont, color=(128128128), label=None, line_thickness=3):
        # Plots one bounding box on image 'im' using OpenCV
        assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to plot_on_box() input image.'
        tl = line_thickness or round(0.002 * (im.shape[0] + im.shape[1]) / 2) + 1  # line/font thickness
        c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
        cv2.rectangle(im, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
        if label:
            tf = max(tl - 11)  # font thickness
            t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
            c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
            cv2.rectangle(im, c1, c2, color, -1, cv2.LINE_AA)  # filled
            #cv2.putText(im, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)
            for id, text in enumerate(pred_cat):
                cv2.putText(im, text, (c1[0], c1[1] + id*20), 0, tl / 3, [225255255], thickness=tf, lineType=cv2.LINE_AA)

    運行結(jié)果:

    完成了上面的步驟,我們就可以開始整活了。眾所周知,特朗普以其獨特的演講魅力征服了許多選民,下面我們就看看AI眼中的特朗普是怎么演講的:

    可以看出自信是讓人信服的必備條件之一。

    三、模型訓(xùn)練

    3.1 數(shù)據(jù)預(yù)處理

    首先通過格物鈦進行數(shù)據(jù)預(yù)處理,在處理數(shù)據(jù)之前需要先找到自己的accessKey(開發(fā)者工具AccessKey新建AccessKey):

    我們可以在不下載數(shù)據(jù)集的情況下,通過格物鈦進行預(yù)處理,并將結(jié)果保存在本地(下面的代碼不在項目中,需要自己創(chuàng)建一個py文件運行,記得填入AccessKey):

    from tensorbay import GAS
    from tensorbay.dataset import Dataset
    import numpy as np
    from PIL import Image
    import cv2
    from tqdm import tqdm
    import os

    def cat_to_one_hot(y_cat):
        cat2ind = {'Affection'0'Anger'1'Annoyance'2'Anticipation'3'Aversion'4,
                   'Confidence'5'Disapproval'6'Disconnection'7'Disquietment'8,
                   'Doubt/Confusion'9'Embarrassment'10'Engagement'11'Esteem'12,
                   'Excitement'13'Fatigue'14'Fear'15'Happiness'16'Pain'17,
                   'Peace'18'Pleasure'19'Sadness'20'Sensitivity'21'Suffering'22,
                   'Surprise'23'Sympathy'24'Yearning'25}
        one_hot_cat = np.zeros(26)
        for em in y_cat:
            one_hot_cat[cat2ind[em]] = 1
        return one_hot_cat

    gas = GAS('填入你的AccessKey')
    dataset = Dataset("Emotic", gas)
    segments = dataset.keys()
    save_dir = './data/emotic_pre'
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    for seg in ['test''val''train']:
        segment = dataset[seg]
        context_arr, body_arr, cat_arr, cont_arr = [], [], [], []
        for data in tqdm(segment):
            with data.open() as fp:
                context = np.asarray(Image.open(fp))
            if len(context.shape) == 2:
                context = cv2.cvtColor(context, cv2.COLOR_GRAY2RGB)
            context_cv = cv2.resize(context, (224224))
            for label_box2d in data.label.box2d:
                xmin = label_box2d.xmin
                ymin = label_box2d.ymin
                xmax = label_box2d.xmax
                ymax = label_box2d.ymax
                body = context[ymin:ymax, xmin:xmax]
                body_cv = cv2.resize(body, (128128))
                context_arr.append(context_cv)
                body_arr.append(body_cv)
                cont_arr.append(np.array([int(label_box2d.attributes['valence']), int(label_box2d.attributes['arousal']), int(label_box2d.attributes['dominance'])]))
                cat_arr.append(np.array(cat_to_one_hot(label_box2d.attributes['categories'])))
        context_arr = np.array(context_arr)
        body_arr = np.array(body_arr)
        cat_arr = np.array(cat_arr)
        cont_arr = np.array(cont_arr)
        np.save(os.path.join(save_dir, '%s_context_arr.npy' % (seg)), context_arr)
        np.save(os.path.join(save_dir, '%s_body_arr.npy' % (seg)), body_arr)
        np.save(os.path.join(save_dir, '%s_cat_arr.npy' % (seg)), cat_arr)
        np.save(os.path.join(save_dir, '%s_cont_arr.npy' % (seg)), cont_arr)

    等程序運行完成后可以看到多了一個文件夾emotic_pre,里面有一些npy文件則代表數(shù)據(jù)預(yù)處理成功。

    3.2 模型訓(xùn)練

    打開main.py文件,35行開始是模型的訓(xùn)練參數(shù),運行該文件即可開始訓(xùn)練。

    四、Emotic模型詳解

    4.1 模型結(jié)構(gòu)

    該模型的思想非常簡單,流程圖中的上下兩個網(wǎng)絡(luò)其實就是兩個resnet18,上面的網(wǎng)絡(luò)負責(zé)提取人體特征,輸入為的彩色圖片,輸出是512個的特征圖。下面的網(wǎng)絡(luò)負責(zé)提取圖像背景特征,預(yù)訓(xùn)練模型用的是場景分類模型places365,輸入是的彩色圖片,輸出同樣是是512個的特征圖。然后將兩個輸出flatten后拼接成一個1024的向量,經(jīng)過兩層全連接層后輸出一個26維的向量和一個3維的向量,26維向量處理26個離散感情的分類任務(wù),3維向量則是3個連續(xù)情感的回歸任務(wù)。

    import torch 
    import torch.nn as nn 

    class Emotic(nn.Module):
      ''' Emotic Model'''
      def __init__(self, num_context_features, num_body_features):
        super(Emotic,self).__init__()
        self.num_context_features = num_context_features
        self.num_body_features = num_body_features
        self.fc1 = nn.Linear((self.num_context_features + num_body_features), 256)
        self.bn1 = nn.BatchNorm1d(256)
        self.d1 = nn.Dropout(p=0.5)
        self.fc_cat = nn.Linear(25626)
        self.fc_cont = nn.Linear(2563)
        self.relu = nn.ReLU()

        
      def forward(self, x_context, x_body):
        context_features = x_context.view(-1, self.num_context_features)
        body_features = x_body.view(-1, self.num_body_features)
        fuse_features = torch.cat((context_features, body_features), 1)
        fuse_out = self.fc1(fuse_features)
        fuse_out = self.bn1(fuse_out)
        fuse_out = self.relu(fuse_out)
        fuse_out = self.d1(fuse_out)    
        cat_out = self.fc_cat(fuse_out)
        cont_out = self.fc_cont(fuse_out)
        return cat_out, cont_out

    離散感情是一個多分類任務(wù),即一個人可能同時存在多種感情,作者的處理方法是手動設(shè)定26個閾值對應(yīng)26種情感,輸出值大于閾值就認為該人有對應(yīng)情感,閾值如下,可以看到engagement對應(yīng)閾值為0,也就是說每個人每次識別都會包含這種情感:

    >>> import numpy as np
    >>> np.load('./debug_exp/results/val_thresholds.npy')
    array([0.0509765 , 0.029371930.034678560.167651280.0307672 ,
           0.135062650.035817310.065816570.030921330.04115443,
           0.026780590.        , 0.040857110.143745240.03058549,
           0.025806780.233895840.137801320.074018640.08617007,
           0.033725830.031054140.029326  , 0.034186470.03770866,
           0.03943525], dtype=float32)

    4.2 損失函數(shù):

    對于分類任務(wù),作者提供了兩種損失函數(shù),一種是普通的均方誤差損失函數(shù)(即self.weight_type == 'mean'),另一種是加權(quán)平方誤差損失函數(shù)(即self.weight_type == 'static‘)。其中,加權(quán)平方誤差損失函數(shù)如下,26個類別對應(yīng)的權(quán)重分別為[0.1435, 0.1870, 0.1692, 0.1165, 0.1949, 0.1204, 0.1728, 0.1372, 0.1620, 0.1540, 0.1987, 0.1057, 0.1482, 0.1192, 0.1590, 0.1929, 0.1158, 0.1907, 0.1345, 0.1307, 0.1665, 0.1698, 0.1797, 0.1657, 0.1520, 0.1537]。


    class DiscreteLoss(nn.Module):
      ''' Class to measure loss between categorical emotion predictions and labels.'''
      def __init__(self, weight_type='mean', device=torch.device('cpu')):
        super(DiscreteLoss, self).__init__()
        self.weight_type = weight_type
        self.device = device
        if self.weight_type == 'mean':
          self.weights = torch.ones((1,26))/26.0
          self.weights = self.weights.to(self.device)
        elif self.weight_type == 'static':
          self.weights = torch.FloatTensor([0.14350.18700.16920.11650.19490.12040.17280.13720.1620,
             0.15400.19870.10570.14820.11920.15900.19290.11580.1907,
             0.13450.13070.16650.16980.17970.16570.15200.1537]).unsqueeze(0)
          self.weights = self.weights.to(self.device)
        
      def forward(self, pred, target):
        if self.weight_type == 'dynamic':
          self.weights = self.prepare_dynamic_weights(target)
          self.weights = self.weights.to(self.device)
        loss = (((pred - target)**2) * self.weights)
        return loss.sum() 

      def prepare_dynamic_weights(self, target):
        target_stats = torch.sum(target, dim=0).float().unsqueeze(dim=0).cpu()
        weights = torch.zeros((1,26))
        weights[target_stats != 0 ] = 1.0/torch.log(target_stats[target_stats != 0].data + 1.2)
        weights[target_stats == 0] = 0.0001
        return weights

    對于回歸任務(wù),作者同樣提供了兩種損失函數(shù),L2損失函數(shù):


    其中, 當 (默認是1) 時, , 否則 。

    L1損失函數(shù):


    其中,當 (默認是1) 時,, 否則 。

    class ContinuousLoss_L2(nn.Module):
      ''' Class to measure loss between continuous emotion dimension predictions and labels. Using l2 loss as base. '''
      def __init__(self, margin=1):
        super(ContinuousLoss_L2, self).__init__()
        self.margin = margin
      
      def forward(self, pred, target):
        labs = torch.abs(pred - target)
        loss = labs ** 2 
        loss[ (labs < self.margin) ] = 0.0
        return loss.sum()


    class ContinuousLoss_SL1(nn.Module):
      ''' Class to measure loss between continuous emotion dimension predictions and labels. Using smooth l1 loss as base. '''
      def __init__(self, margin=1):
        super(ContinuousLoss_SL1, self).__init__()
        self.margin = margin
      
      def forward(self, pred, target):
        labs = torch.abs(pred - target)
        loss = 0.5 * (labs ** 2)
        loss[ (labs > self.margin) ] = labs[ (labs > self.margin) ] - 0.5
        return loss.sum()

    數(shù)據(jù)集鏈接:https://gas.graviti.com/dataset/datawhale/Emotic

    Kosti R, Alvarez J M, Recasens A, et al. Context based emotion recognition using emotic dataset[J]. IEEE transactions on pattern analysis and machine intelligence, 2019, 42(11): 2755-2766.

    YOLOv5項目地址:https://github.com/ultralytics/yolov5

    Emotic項目地址:https://github.com/Tandon-A/emotic


    如果覺得有用,就請分享到朋友圈吧!

    △點擊卡片關(guān)注極市平臺,獲取最新CV干貨

    公眾號后臺回復(fù)“transformer”獲取最新Transformer綜述論文下載~


    極市干貨



    課程/比賽:珠港澳人工智能算法大賽保姆級零基礎(chǔ)人工智能教程
    算法trick目標檢測比賽中的tricks集錦從39個kaggle競賽中總結(jié)出來的圖像分割的Tips和Tricks
    技術(shù)綜述:一文弄懂各種loss function工業(yè)圖像異常檢測最新研究總結(jié)(2019-2020)


    CV技術(shù)社群邀請函 #

    △長按添加極市小助手
    添加極市小助手微信(ID : cvmart4)

    備注:姓名-學(xué)校/公司-研究方向-城市(如:小極-北大-目標檢測-深圳)


    即可申請加入極市目標檢測/圖像分割/工業(yè)檢測/人臉/醫(yī)學(xué)影像/3D/SLAM/自動駕駛/超分辨率/姿態(tài)估計/ReID/GAN/圖像增強/OCR/視頻理解等技術(shù)交流群


    每月大咖直播分享、真實項目需求對接、求職內(nèi)推、算法競賽、干貨資訊匯總、與 10000+來自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺開發(fā)者互動交流~


    覺得有用麻煩給個在看啦~  
    瀏覽 103
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    久久九| 精品成人无码久久久久久 | 国产AV小电影 | 人人摸人人操人人看 | 操阴道福利片视频 |