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

文書内の 2 つの空白を 1 つの空白に置き換えます。

次に、以下のコードを使用して必要な顔属性を抽出できます。

#!/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 は、私が 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
  }
}

出力が 3 つあり、slice_point は 2 まで削除します。

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

このネットワーク構造は bn2 の後に 6 つのグループに分かれており、それぞれのグループには異なる数の出力があります。また、各グループの前には同じ構造の層があり、各タスクの全結合層と最終出力層に至ります。必要のないタスク層とグループを削除します。私のこの 3 つのカテゴリについて、gender は単独のグループであり、眼鏡は 4 番目のグループ、前髪は 6 番目のグループにあります。パラメータの数を減らすために、眼鏡と前髪を 6 番目のグループにまとめ、4 番目のグループの前のネットワークを削除しました。第一グループの gender については、3 つのタスクを 1 つのグループにまとめると収束しない可能性があるため、今のところ変更していません。しかし、将来的にはテストを行う予定です。

(トレーニング出力は良好で、検証セットでの精度は非常に高いですが、実際の検出時には単独のグループの性別は正確ですが、眼鏡と前髪はそれぞれ正確ではありません。次のステップでは、眼鏡と前髪をそれぞれ別のグループにし、全結合層をグローバル平均プーリングに変更する予定です。)

(前髪と眼鏡をそれぞれ別のグループにし、全結合層を削除しました。モデルは小さくなり、わずか 8M になりました。検証セットの精度はかなり高く、98% 程度ですが、実際の実験結果は非常に悪いです。次に、コアネットワークを mobilenet v2 または squeezenet に変更してみる予定です。また、ネットワークの問題だけではないかもしれないと考え、データセットを観察したところ、前髪や眼鏡をかけた画像が非常に少ないことがわかりました。ネットワークを変更しても効果がない場合、次のステップでは一部のデータに対してデータ拡張を行う必要があります。)


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

検証セットとテストセットでの結果は非常に良好ですが、カメラやビデオを使用した実際のアプリケーションでは、効果が非常に悪いです。

原因がわかりました。テスト時の前処理方法が間違っていたためです。


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

いくつかの心得:

  1. 全畳み込み + グローバルプーリングを全結合層の代わりに使用しても、効果に大きな影響はなく、モデルのパラメータ量は変わりません。

  2. 全結合層はパラメータ量が大きいですが、実行時間は非常に速いです。つまり、全結合層はモデルの実行時間に大きな影響を与えず、モデルのサイズには大きな影響を与えます。

  3. 各層の実行時間を確認したところ、大きな畳み込みカーネルの効率が非常に低いため、すべて 3*3 の小さな畳み込みカーネルに変更するのが最良です。

  4. 畳み込み層の出力数はできるだけ 2^n にするのが良いです。


最後に loss_weight を変更し、すべてのタスクの loss_weight を合計して 1 にします。私には 3 つのタスクしかないので、loss_weight はすべて 0.3333 に設定しました。

残りの solver.prototxt については、単一タスクのものと同じなので、説明しません。

最後にトレーニング出力のスクリーンショットを 1 枚貼ります:

1668715386436.jpg

後で継続的に更新します。。。#

1. 可視化コード 2018.08.21 GitHub にアップロード済み、show.py

2. caffe-python 推論コード 2018.08.21 GitHub にアップロード済み、face_attri.py

  1. ncnn-C++ デプロイコード
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。