hans

hans

【Caffe】多標籤訓練、人臉屬性多任務訓練


前言#

參考了 https://zhuanlan.zhihu.com/p/22190532

細節有一些問題,我這裡過一遍整個流程,涉及到的問題都會做講解。包括部署問題,最後我也會講講。

文中涉及到的我用的代碼都在這裡: https://github.com/HansRen1024/Face-Attributes-MultiTask-Classification

正文#

去原作者 github 網站下載 https://github.com/HolidayXue/CodeSnap
這個項目。

將 convert_multilabel.cpp 放到 caffe/tools/ 目錄下。

修改 81 行:

‘>>’ should be ‘> >’

然後註釋掉 149 行。

命令行在 caffe / 下運行:

make clean
make all -j8
make py

我是用的 CelebA 數據集,都是人臉屬性的。

下載地址: https://pan.baidu.com/s/17rp2gKqtvuT48yuPfJK3sA

在 Anno 目錄下找到 list_attr_celeba.txt

先命令行運行:

sed -i 's/  / /g' list_attr_celeba.txt

將文檔中兩個空格都替換為一個空格。

然後可以通過下面代碼提取你想要的人臉屬性

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 20 16:57:52 2018

@author: hans
"""

ReadTxt = 'list_attr_celeba.txt'
WriteTxt = 'train.txt'
r = open(ReadTxt,'r')
w = open(WriteTxt,'w')
rLine = r.readline().split('\n')[0]
while rLine:
    rLine = r.readline().split('\n')[0]
    if not rLine:
        break
#    image,bangs,eyeglasses,gender,
    wLine = rLine.split(' ')[0]+' '+rLine.split(' ')[6]+' '+rLine.split(' ')[16]+' '+rLine.split(' ')[21]+'\n'
    w.write(wLine)
r.close()
w.close()

接著命令行運行:

sed -i 's/-1/0/g' train.txt

將 train.txt 文檔中 - 1 改成索引 0。

對比了一下原圖片,提取的屬性是對的。

然後從 train.txt 拿出了一部分放到 val.txt 中

運行腳本,生成可供訓練用的 lmdb 數據:

echo "Creating train lmdb..."
~/caffe-multi/build/tools/convert_multilabel \
-resize_height=227 \
-resize_width=227 \
-shuffle=false \
/home/hans/data/face/CelebA/Img/img_align_celeba/ \
train.txt \
./train_db \
./train_lb \
3

echo "Creating val lmdb..."
~/caffe-multi/build/tools/convert_multilabel \
-resize_height=227 \
-resize_width=227 \
-shuffle=false \
/home/hans/data/face/CelebA/Img/img_align_celeba/ \
val.txt \
./val_db \
./val_lb \
3

img_align_celeba 是切好人臉的數據集

後面參數 3 表示我這邊提取了三種人臉屬性。

最後是修改 mcnn_Attri.prototxt,均值,歸一化,數據路徑,還有一個很重要,backend 一定要改成 LMDB!

name: "MCNN_Attri"
layer {
  name: "data"
  type: "Data"
  top: "data"
  transform_param {
  	 scale: 0.007843
     mean_value: 127.5
     mean_value: 127.5
     mean_value: 127.5
     crop_size: 227     
  }  
  include {
    phase: TRAIN
  }
  data_param {
    source: "/home/hans/data/face/CelebA/attri/doc/train_db"
    batch_size: 192
    backend: LMDB
   }
}

layer {
  name: "labels"
  type: "Data"
  top: "labels"
  include {
     phase: TRAIN
  }
  data_param {
    source: "/home/hans/data/face/CelebA/attri/doc/train_lb"
    batch_size: 192
	backend: LMDB
  }
}

layer {
  name: "data"
  type: "Data"
  top: "data"
  transform_param {
  	scale: 0.007843
    mean_value: 127.5
    mean_value: 127.5
    mean_value: 127.5
    crop_size: 227   
  }
  include {
    phase: TEST
  }
  data_param {
    source: "/home/hans/data/face/CelebA/attri/doc/val_db"
    batch_size: 128
    backend: LMDB
  }
}

layer {
  name: "labels"
  type: "Data"
  top: "labels"
  include {
    phase: TEST
  }
  data_param {
    source: "/home/hans/data/face/CelebA/attri/doc/val_lb"
    batch_size: 128
    backend: LMDB
  }
}

layer {
  name: "sliceL"
  type: "Slice"
  bottom: "labels"
  top: "label_attr6"
  top: "label_attr16"
  top: "label_attr21"
  slice_param {
    slice_dim: 1  
	slice_point: 1
	slice_point: 2
  }
}

有三個輸出,slice_point 刪到 2。

【2018.08.22 更新】-----------------------------------------------

這個網絡結構在 bn2 後分成了六組,每一組都有不同個輸出。並且每一組前面都有結構一樣的層,然後到各個任務的全連接層和最終輸出層。將對應不需要的任務層和組刪掉。對於我這三個類別,我發現 gender 是單獨一組的,眼鏡在第四組,劉海在第六組。為了減少參數量,我將眼鏡和劉海都放到了第六組,刪除了第四組的前面網絡。第一組 gender 的我暫時沒改,擔心三個任務都放到一組裡出現不收斂的情況。不過以後我肯定會做測試。

(訓練輸出很好,在驗證集上準確率非常高,但是實際檢測的時候發現對單獨在一組的性別分別準確,對眼鏡和劉海分別不準確。我下一步還是要將眼鏡和劉海分別放在一組,並且將全連接層改成全局平均池化。)

(將劉海和眼鏡分別放在了一組,同時刪了全連接層。模型是變小了,只有 8M 了。驗證集準確率還挺高,98% 左右,但是實際實驗效果太差。接下來嘗試換換核心網絡,用 mobilenet
v2 或者 squeezenet 試試。同時我考慮到可能不一定是網絡的原因,觀察了一下數據集,有劉海和戴眼鏡的圖片很少。如果換網絡也不行,那麼下一步應該要對部分數據做 argument 了。)


【2018.08.29 更新】-----------------------------------------------

在驗證集和測試集上結果都很美好,但是拿攝像頭或者視頻實際應用的時候效果差的離譜。

找到原因了,是我測試時候的預處理方式不對導致的。


【2018.09.04 更新】-----------------------------------------------

幾點心得:

  1. 用全卷積 + 全局池化替代全連接層,效果影響不大,模型參數量不變。

2. 全連接層參數量大,但執行時間很快。也就是說全連接層對模型執行時間影響不大,對模型大小影響較大。

3. 查看了每一層的執行時間,發現大卷積核效率很低,最好都改用 3*3 的小卷積核。

4. 卷積層輸出數量最好是 2^n。


最後改 loss_weight,所有任務的 loss_weight 加一起等於 1。我這裡只有三個任務,所以 loss_weight 我都設置為 0.3333 了。

剩下的 solver.prototxt 我就不說了,跟單任務的一樣。

最後放一張訓練輸出截圖:

1668715386436.jpg

後面我會持續更新。。。#

1. 可視化代碼 2018.08.21 已上傳到 github, show.py

2.caffe-python 推理代碼 2018.08.21 已上傳到 github, face_attri.py

3.ncnn-C++ 部署代碼

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。