はじめに
本プロジェクトは、mini_Xceptionという深層学習ネットワークモデルに基づく顔表情認識システムです。CNN畳み込みニューラルネットワークをコア技術として構築し、データセット処理、モデル構築、トレーニングコード、そしてPyQt5ベースのアプリケーションインターフェース設計について詳細に説明します。本アプリケーションでは、画像、ビデオ、リアルタイムカメラからの顔表情認識をサポートしています。ここでは、完全なアプリケーションインターフェース設計、深層学習モデルのコード、学習用データセットのダウンロードリンクを提供しています。
完全なリソースダウンロードリンク:開発者が提供するリソースページ
プロジェクトデモ動画:
【プロジェクト共有】ディープラーニングを用いた顔表情認識システム(PyQtインターフェース付き)
一、データセット
1.1 データセット概要
Fer2013顔表情データセットは35,886枚の顔表情画像で構成されています。そのうち、学習用画像(Training)が28,708枚、公開検証用画像(PublicTest)と非公開検証用画像(PrivateTest)が各3,589枚あります。各画像は48×48ピクセルの固定サイズのグレースケール画像で、7種類の表情に対応しており、それぞれ0から6の数値ラベルが割り当てられています。具体的な表情とラベルの対応は以下の通りです:0 怒り; 1 嫌悪; 2 恐怖; 3 幸せ; 4 悲しみ;5 驚き; 6 中性。
1.2 データ前処理
データセットはCSVファイル形式で提供されており、表情データは直接画像としてではなくピクセル値として格納されています。そこで、整理しながら画像に変換する必要があります。ここではcreate_images.pyを使用します。
# create_images.py 画像データ生成
import codecs
import cv2
from tqdm import tqdm
import numpy as np
# CSVファイルの読み込み
csv_file = codecs.open('fer2013.csv', 'r', 'utf8').readlines()[1:]
label_file = codecs.open('labels.txt', 'w', 'utf8')
image_index = 0
for line in tqdm(csv_file):
# 行データの分割
data_parts = line.split(',')
expression_label = data_parts[0]
pixel_values = data_parts[1].split(' ')
# ピクセル値の変換
pixels = [int(pixel) for pixel in pixel_values]
pixels_array = np.array(pixels)
image = pixels_array.reshape((48, 48))
# 画像の保存
cv2.imwrite('emotion_images/' + str(image_index) + '.png', image)
label_file.write(str(image_index) + '\t' + expression_label + '\n')
image_index += 1
ピクセル値を[0, 1]の範囲に正規化することで、モデルのトレーニング時の勾配が安定し、より良い解に収束しやすくなります。この正規化は、特定のピクセル値が大きすぎたり小さすぎたりすることによる勾配爆発や勾配消失の問題を防ぎます。preprocessing.pyを使用して画像を前処理し、ニューラルネットワークで使用できるようにします。
# preprocessing.py
def normalize_image(image, use_zero_centering=True):
"""
画像データの前処理を行います
引数:
image: 入力画像(numpy配列)
use_zero_centering: ゼロ中心化を行うかどうか
戻り値:
前処理された画像
"""
# データ型の変換
processed_image = image.astype('float32')
# 正規化(0-1の範囲)
processed_image = processed_image / 255.0
# ゼロ中心化(オプション)
if use_zero_centering:
processed_image = processed_image - 0.5
processed_image = processed_image * 2.0
return processed_image
この前処理メソッドは主に2つのステップで構成されています:正規化とゼロ中心化。正規化:ピクセル値を255.0で割ることで、入力画像データを[0, 1]の範囲に正規化します。このステップにより、すべてのピクセル値が類似した数値範囲内に収まり、モデルトレーニングの安定性が向上します。ゼロ中心化:パラメータuse_zero_centeringがTrueの場合、画像のゼロ中心化を行います。ゼロ中心化のプロセスには2つの操作が含まれます:ピクセル値から0.5を引くことで、ピクセル値を0.5を中心にシフトさせ、平均値を0.5にします。このステップにより、画像データの中心点がゼロ付近になり、モデルの収束速度が向上します。ピクセル値に2.0を掛けることで、ピクセル値を[-1, 1]の範囲にスケーリングします。このステップにより、対称的な入力データを必要とするモデルに適した値域が確保され、モデルの入力データに対するロバスト性が向上します。
最後に、dataset_builder.pyファイルを使用して処理済みのデータセットをdata.hdf5ファイルにパッケージ化し、後のモデルトレーニングで使用できるようにします。
# dataset_builder.py
import codecs
import cv2
import numpy as np
from data_utils import Detecttwo
from tqdm import tqdm
# パス設定
image_directory = '/datasets/fer2013/emotion_images/'
label_file_path = '/datasets/fer2013/labels.txt'
# ラベルファイルの読み込み
with codecs.open(label_file_path, 'r', 'utf8') as f:
labels = [line.split('\t') for line in f.readlines()]
# ラベルデータの整形
processed_labels = [[item[0], int(item[1])] for item in labels]
# データリストの初期化
image_data = []
expression_labels = []
# 画像データの読み込みと前処理
for image_info in tqdm(processed_labels):
image_name = image_directory + image_info[0] + '.png'
image = cv2.imread(image_name, 0)
# 画像の次元拡張とリサイズ
image = np.expand_dims(image, axis=2)
image = cv2.resize(image, (48, 48), interpolation=cv2.INTER_LINEAR)
image = np.expand_dims(image, axis=2)
# 画像データの追加
image_data.append(image)
# ラベルデータのワンホットエンコーディング
label_vector = [0] * 7
label_vector[image_info[1]] = 1
expression_labels.append(label_vector)
# numpy配列への変換
image_data = np.array(image_data)
expression_labels = np.array(expression_labels)
print("画像データ形状:", image_data.shape, "ラベルデータ形状:", expression_labels.shape)
print("サンプル画像データ:", image_data[0], "サンプルラベルデータ:", expression_labels[0:5])
# HDF5ファイルへの保存
with h5py.File("processed_data.hdf5", 'w') as hdf5_file:
hdf5_file.create_dataset('images', data=image_data)
hdf5_file.create_dataset('labels', data=expression_labels)
二、モデル構築
CNNに基づくネットワークモデルmini_XCEPTIONを使用します。XceptionネットワークモデルはGoogleが提案したもので、Inception v3をさらに最適化したものです。主な変更点として、Inception v3の畳み込み操作を深さ分離可能な畳み込み(depthwise separable convolution)に置き換えています。Xceptionのネットワーク構造はImageNetデータセット(Inception v3の設計対象)ではInception v3をわずかに上回り、3億5000万枚の画像を含むより大きな画像分類データセットでは明らかに優れています。両方の構造は同じ数のパラメータを維持していますが、性能の向上はモデルパラメータをより効果的に使用することから来ています。詳細は論文「Real-time Convolutional Neural Networks for Emotion and Gender Classification–O Arriaga」を参照してください。
CNNベースのモデル実装コードは以下の通りです:
# モデル実装コード
def create_mini_xception(input_dimensions, expression_classes, l2_penalty=0.01):
"""
mini_Xceptionモデルを構築します
引数:
input_dimensions: 入力画像の形状(高さ, 幅, チャネル数)
expression_classes: 表情クラスの数
l2_penalty: L2正則化のペナルティ
戻り値:
構築されたモデル
"""
from keras import regularizers
from keras.layers import Input, Conv2D, BatchNormalization, Activation, SeparableConv2D, MaxPooling2D, GlobalAveragePooling2D, Dense
from keras.models import Model
# L2正則化の設定
l2_regularization = regularizers.l2(l2_penalty)
# 入力層の定義
input_layer = Input(input_dimensions)
# 基本ブロックの構築
x = Conv2D(8, (3, 3), strides=(1, 1), padding='same',
use_bias=False, kernel_regularizer=l2_regularization)(input_layer)
x = BatchNormalization()(x)
x = Activation('relu')(x)
# 深さ分離可能な畳み込みブロック
x = SeparableConv2D(16, (3, 3), padding='same',
use_bias=False, kernel_regularizer=l2_regularization)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2, 2))(x)
# 追加の畳み込みブロック
x = SeparableConv2D(32, (3, 3), padding='same',
use_bias=False, kernel_regularizer=l2_regularization)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = SeparableConv2D(64, (3, 3), padding='same',
use_bias=False, kernel_regularizer=l2_regularization)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2, 2))(x)
# 最終畳み込みブロック
x = SeparableConv2D(128, (3, 3), padding='same',
use_bias=False, kernel_regularizer=l2_regularization)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
# 分類ヘッド
x = GlobalAveragePooling2D()(x)
x = Dense(128, activation='relu')(x)
output_layer = Dense(expression_classes, activation='softmax')(x)
# モデルの定義
model = Model(inputs=input_layer, outputs=output_layer)
return model