訂閱
糾錯
加入自媒體

使用 CNN 進(jìn)行面部情緒識別

面部表情是人類之間交流的重要方式。

人工智能研究中,深度學(xué)習(xí)技術(shù)已成為增強(qiáng)人機(jī)交互的強(qiáng)大工具。心理學(xué)中面部表情和情緒的分析和評估涉及評估預(yù)測個人或群體情緒的決定。

本研究旨在開發(fā)一種能夠使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)算法和特征提取技術(shù)預(yù)測和分類面部情緒的系統(tǒng)。

該過程包括三個主要階段:數(shù)據(jù)預(yù)處理、面部特征提取和面部情緒分類。通過采用卷積神經(jīng)網(wǎng)絡(luò)(CNN)算法,系統(tǒng)準(zhǔn)確預(yù)測面部表情,成功率為62.66%。

該算法的性能使用FER2013數(shù)據(jù)庫進(jìn)行評估,該數(shù)據(jù)庫是一個公開可用的數(shù)據(jù)集,包含35,887張48x48灰度面部圖像,每張圖像代表一種不同的情緒。

現(xiàn)在讓我們從編碼開始。

!pip install scikit-plot

此代碼使用 pip 安裝 scikit-plot 包,pip 是一個 Python 包,提供了一系列有用的工具來可視化機(jī)器學(xué)習(xí)模型的性能。

具體來說,scikit-plot提供了多種函數(shù)來生成模型評估中使用的常見圖,例如ROC曲線,精度召回率曲線,混淆矩陣等。

在Python環(huán)境中執(zhí)行命令“!pip install scikit-plot”后,你應(yīng)該能夠在代碼中導(dǎo)入和使用scikit-plot函數(shù)。

import pandas as pd

import numpy as np

import scikitplot

import random

import seaborn as sns

import keras

import os

from matplotlib import pyplot

import matplotlib.pyplot as plt

import tensorflow as tf

from tensorflow.keras.utils import to_categorical

import warnings

from tensorflow.keras.models import Sequential

from keras.callbacks import EarlyStopping

from keras import regularizers

from keras.callbacks import ModelCheckpoint,EarlyStopping

from tensorflow.keras.optimizers import Adam,RMSprop,SGD,Adamax

from keras.preprocessing.image import ImageDataGenerator,load_img

from keras.utils.vis_utils import plot_model

from keras.layers import Conv2D, MaxPool2D, Flatten,Dense,Dropout,BatchNormalization,MaxPooling2D,Activation,Input

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import StandardScaler

warnings.simplefilter("ignore")

from keras.models import Model

from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score

from keras.regularizers import l1, l2

import plotly.express as px

from matplotlib import pyplot as plt

from sklearn.metrics import confusion_matrix

from sklearn.metrics import classification_report

該代碼導(dǎo)入機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)中常用的各種 Python 庫和模塊。

這些庫包括pandas,numpy,scikit-plot,random,seaborn,keras,os,matplotlib,tensorflow和scikit-learn。

每個 import 語句導(dǎo)入一組執(zhí)行機(jī)器學(xué)習(xí)或深度學(xué)習(xí)任務(wù)所需的特定工具或函數(shù),例如數(shù)據(jù)操作、數(shù)據(jù)可視化、模型構(gòu)建和性能評估。

總體而言,此代碼準(zhǔn)備了執(zhí)行各種機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)(如數(shù)據(jù)預(yù)處理、模型訓(xùn)練和模型評估)所需的必要工具和模塊。

從這里下載代碼:http://onepagecode.s3-website-us-east-1.amazonaws.com/

加載數(shù)據(jù)集data = pd.read_csv("/input/fer2013/fer2013.csv")

data.shape

此代碼使用 pandas 的read_csv()函數(shù)讀取名為“fer2013.csv”的 CSV 文件,該文件位于“/input/fer2013/“ 目錄,并將生成的數(shù)據(jù)幀分配給名為data的變量。

然后,在數(shù)據(jù)幀上調(diào)用shape屬性以檢索其維度,這將返回表單的元組。這行代碼將輸出數(shù)據(jù)幀data中的行數(shù)和列數(shù)(rows, columns)。

data.isnull().sum()

此代碼將返回數(shù)據(jù)幀data的每一列中所有缺失值的總和。

數(shù)據(jù)幀的isnull()方法返回一個布爾數(shù)據(jù)幀,該幀指示原始數(shù)據(jù)幀中的每個元素是否丟失。然后將sum()方法應(yīng)用于此布爾數(shù)據(jù)幀,該幀返回每列中缺失值的總和。

這是檢查數(shù)據(jù)幀中是否存在任何缺失值的快速方法。如果存在缺失值,則可能需要在將數(shù)據(jù)用于建模之前插補(bǔ)或刪除這些值。

data.head()

此代碼將返回數(shù)據(jù)幀data的前 5 行。

數(shù)據(jù)幀的head()方法返回數(shù)據(jù)幀的前n行(默認(rèn)情況下為n=5 )。這是快速瀏覽數(shù)據(jù)幀中的數(shù)據(jù)的有用方法,尤其是在處理大型數(shù)據(jù)集時。

輸出將顯示數(shù)據(jù)幀data的前 5 行,其中可能包括列名稱和前幾行數(shù)據(jù),具體取決于數(shù)據(jù)幀的結(jié)構(gòu)。

數(shù)據(jù)頭的輸出

數(shù)據(jù)預(yù)處理CLASS_LABELS  = ['Anger', 'Disgust', 'Fear', 'Happy', 'Neutral', 'Sadness', "Surprise"]

fig = px.bar(x = CLASS_LABELS,

             y = [list(data['emotion']).count(i) for i in np.unique(data['emotion'])] , 

             color = np.unique(data['emotion']) ,

             color_continuous_scale="Emrld") 

fig.update_xaxes(title="Emotions")

fig.update_yaxes(title = "Number of Images")

fig.update_layout(showlegend = True,

    title = {

        'text': 'Train Data Distribution ',

        'y':0.95,

        'x':0.5,

        'xanchor': 'center',

        'yanchor': 'top'})

fig.show()

此代碼使用 Plotly Express 庫創(chuàng)建條形圖,該條形圖顯示數(shù)據(jù)幀data中情緒的分布。

首先,在CLASS_LABELS中定義一個類標(biāo)簽列表,它對應(yīng)于數(shù)據(jù)集中的不同情緒。

然后,調(diào)用px.bar()函數(shù),其中 x 軸表示類標(biāo)簽,y 軸表示每個情緒的圖像數(shù)量。顏色參數(shù)設(shè)置為不同的情感類,color_continuous_scale參數(shù)設(shè)置為“Emrld”,這是 Plotly Express 中預(yù)定義的色階。

接下來,調(diào)用各種update_方法來修改繪圖的布局和外觀。例如,update_xaxes()和update_yaxes()用于分別設(shè)置 x 軸和 y 軸標(biāo)題。 update_layout()用于設(shè)置打印標(biāo)題及其位置。

最后,在圖形對象上調(diào)用show()方法以顯示繪圖。

輸出將顯示一個條形圖,該條形圖顯示數(shù)據(jù)幀data中每個情緒的圖像數(shù),每個情緒根據(jù)指定的色階進(jìn)行顏色編碼。

隨機(jī)打亂數(shù)據(jù)data = data.sample(frac=1)

DataFrame 的sample()方法用于隨機(jī)采樣數(shù)據(jù)幀中行的一小部分,并指定frac要返回的行部分(在本例中為 frac=1,這意味著將返回所有行)。當(dāng)frac=1時,sample()方法有效地對數(shù)據(jù)幀中的行進(jìn)行洗牌。

這是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)中的常見操作,隨機(jī)打亂數(shù)據(jù)以防止在數(shù)據(jù)具有任何固有順序或結(jié)構(gòu)時可能引入的任何偏差非常重要。

One Hot編碼labels = to_categorical(data[['emotion']], num_classes=7)

輸出是一個形狀為(n_samples, n_classes)的 numpy 數(shù)組,其中:

n_samples是數(shù)據(jù)幀中的樣本數(shù)n_classes是數(shù)據(jù)中唯一類的數(shù)量(在本例中為 7)數(shù)組data的每一行表示數(shù)據(jù)幀中單個樣本的One Hot編碼標(biāo)簽。train_pixels = data["pixels"].astype(str).str.split(" ").tolist()

train_pixels = np.uint8(train_pixels)

此代碼對數(shù)據(jù)DataFrame的像素列中的像素值進(jìn)行預(yù)處理。

首先,astype()方法用于將pixels列轉(zhuǎn)換為字符串?dāng)?shù)據(jù)類型,這允許在列的每一行上調(diào)用split()方法。

接下來,對pixels列的每一行調(diào)用split()方法,以將像素值拆分為字符串列表。然后使用tolist()將生成的列表轉(zhuǎn)換為 numpy 數(shù)組。

最后,對 numpy 數(shù)組調(diào)用np.uint8(),將像素值從字符串轉(zhuǎn)換為無符號 8 位整數(shù),這是通常用于表示圖像像素值的數(shù)據(jù)類型。

輸出是一個形狀為(n_samples, n_pixels)的 numpy 數(shù)組,其中n_samples是數(shù)據(jù)幀中的樣本數(shù),n_pixels是數(shù)據(jù)中每個圖像的像素數(shù)。數(shù)組data的每一行表示數(shù)據(jù)幀中單個圖像的像素值。

標(biāo)準(zhǔn)化pixels = train_pixels.reshape((35887*2304,1))

此代碼將train_pixels numpy數(shù)組從形狀的三維數(shù)組(n_samples,n_rows,n_columns)重新整形為形狀的二維數(shù)組(n_samples*n_row,1)。

numpy數(shù)組的reshape()方法用于更改其形狀。在這種情況下,train_pixels陣列通過將其重塑為具有一列的2D陣列而被展平。

得到的像素陣列的形狀為(n_samples*n_rows,1),其中n_samples是DataFrame中的樣本數(shù),n_rows是每個圖像的行數(shù),1 表示DataFrame中每個圖像的展平像素值。陣列的每一行表示DataFrame中單個圖像的單個像素值。

scaler = StandardScaler()

pixels = scaler.fit_transform(pixels)

此代碼使用scikit learn的StandardScaler()函數(shù)將標(biāo)準(zhǔn)化應(yīng)用于像素numpy數(shù)組。

StandardScaler()函數(shù)是一個預(yù)處理步驟,用于縮放數(shù)據(jù)的每個特征(在本例中為每個像素值),使其均值為 0,方差為 1。這是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)中常用的技術(shù),可確保每個特征對模型的貢獻(xiàn)相同。

然后在像素numpy數(shù)組上調(diào)用StandardScaler()對象的fit_transform()方法,該方法計算數(shù)據(jù)的平均值和標(biāo)準(zhǔn)偏差,并相應(yīng)地縮放數(shù)據(jù)。然后將得到的縮放數(shù)據(jù)分配回像素numpy數(shù)組。

輸出是一個與原始pixels數(shù)組形狀相同的 numpy 數(shù)組,但每個像素值都已標(biāo)準(zhǔn)化。

重塑數(shù)據(jù) (48,48)pixels = train_pixels.reshape((35887, 48, 48,1))

此代碼將train_pixels numpy數(shù)組從2維形狀數(shù)組(n_samples*n_rows,1)重新整形為4維形狀陣列(n_samples,n_rows、n_columns、n_channels)。

numpy數(shù)組的reshape()方法用于更改其形狀。在這種情況下,train_pixels陣列被重塑為具有1個通道的4D陣列。

得到的像素陣列的形狀為(n_samples,n_rows,n_columns,n_channels),其中n_samples是DataFrame中的樣本數(shù)量,n_row是每個圖像的行數(shù),n_column是每個圖像中的列數(shù),n_channel表示每個圖像中顏色通道的數(shù)量。

由于原始數(shù)據(jù)集是灰度級的,因此n_channels設(shè)置為1。像素陣列的每個元素表示DataFrame中單個灰度圖像的像素值。

訓(xùn)練測試驗證拆分

現(xiàn)在,我們有 35887 張圖像,每張圖像包含 48x48 像素。我們將數(shù)據(jù)拆分為訓(xùn)練、測試和驗證數(shù)據(jù),以 10% 的比例提供、評估和驗證我們的數(shù)據(jù)。

X_train, X_test, y_train, y_test = train_test_split(pixels, labels, test_size=0.1, shuffle=False)

X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.1, shuffle=False)

該代碼使用scikit-learn的train_test_split()函數(shù)將經(jīng)過預(yù)處理的圖像數(shù)據(jù)像素和一個熱編碼的標(biāo)簽標(biāo)簽拆分為訓(xùn)練集、驗證集和測試集。

函數(shù)train_test_split()根據(jù)test_size參數(shù)將數(shù)據(jù)隨機(jī)拆分為訓(xùn)練和測試子集,test_size指定應(yīng)用于測試的數(shù)據(jù)部分。在這種情況下,test_size=0.1,這意味著10%的數(shù)據(jù)將用于測試。

shuffle參數(shù)設(shè)置為False以保留DataFrame中樣本的原始順序。

生成的X_train、X_val和X_test數(shù)組分別包含訓(xùn)練集、驗證集和測試集的像素值。y_train、y_val和y_test數(shù)組包含對應(yīng)集合的one hot編碼標(biāo)簽。

再次使用train_test_split()將訓(xùn)練集進(jìn)一步拆分為訓(xùn)練集和驗證集,test_size=0.1。這將數(shù)據(jù)分成80%用于訓(xùn)練,10%用于驗證,10%用于測試。

print(X_train.shape)

print(X_test.shape)

print(X_val.shape)

在將數(shù)據(jù)拆分為訓(xùn)練集、驗證集和測試集之后,這些代碼行打印X_train、X_test和X_val數(shù)組的形狀。

numpy數(shù)組的shape屬性返回數(shù)組維度的元組。在這種情況下,X_train、X_test和X_val數(shù)組的形狀將取決于每個集合中的樣本數(shù)量和每個樣本的維度。

輸出將以格式(n_samples、n_rows、n_columns、n_channel)顯示陣列的形狀,其中n_samples是集合中的樣本數(shù),n_rows是每個圖像的行數(shù),n_columns是每個圖像中的列數(shù),n_channel表示每個圖像中顏色通道的數(shù)量。

在這個繪圖代碼的幫助下,我們可以看到一些包含每個類的一個樣本的訓(xùn)練數(shù)據(jù)。

plt.figure(figsize=(15,23))

label_dict = {0 : 'Angry', 1 : 'Disgust', 2 : 'Fear', 3 : 'Happiness', 4 : 'Sad', 5 : 'Surprise', 6 : 'Neutral'}

i = 1

for i in range (7):

    img = np.squeeze(X_train[i])

    plt.subplot(1,7,i+1)

    plt.imshow(img)

    index = np.argmax(y_train[i])

    plt.title(label_dict[index])

    plt.axis('off')

    i += 1

plt.show()

此代碼使用 matplotlib 的plt.subplots()函數(shù)從訓(xùn)練集中創(chuàng)建圖像的 7x1 子圖網(wǎng)格。

numpy數(shù)組的scruze()方法用于從數(shù)組的形狀中刪除任何一維條目,有效地將4D數(shù)組轉(zhuǎn)換為3D數(shù)組。

對于每個子圖,imshow()函數(shù)用于顯示相應(yīng)的圖像,title()函數(shù)用來顯示相應(yīng)的標(biāo)簽。

axis()函數(shù)用于關(guān)閉每個子圖的軸。

輸出是訓(xùn)練集中的前 7 個圖像的可視化,以及它們對應(yīng)的標(biāo)簽。

使用圖像數(shù)據(jù)生成器進(jìn)行數(shù)據(jù)增強(qiáng)

我們可以進(jìn)行數(shù)據(jù)增強(qiáng),以獲得更多數(shù)據(jù)來訓(xùn)練和驗證我們的模型,以防止過度擬合。數(shù)據(jù)增強(qiáng)可以在訓(xùn)練集和驗證集上完成,因為它有助于模型變得更加通用和健壯。

datagen = ImageDataGenerator(  width_shift_range = 0.1,

                               height_shift_range = 0.1,

                               horizontal_flip = True,

                               zoom_range = 0.2)

valgen = ImageDataGenerator(   width_shift_range = 0.1,

                               height_shift_range = 0.1,

                               horizontal_flip = True,

                               zoom_range = 0.2)

此代碼創(chuàng)建兩個ImageDataGenerator對象,datagen和valgen,它們將用于訓(xùn)練和驗證期間的數(shù)據(jù)擴(kuò)充。

ImageDataGenerator類是一個Keras預(yù)處理實用程序,可以實時執(zhí)行各種類型的圖像增強(qiáng),如移位、翻轉(zhuǎn)、旋轉(zhuǎn)和縮放。

datagen對象包括許多增強(qiáng)技術(shù):

width_shift_range和height_shift_range分別將圖像在水平和垂直方向上隨機(jī)移動圖像寬度和高度的最大10%。horizontal_flip隨機(jī)水平翻轉(zhuǎn)圖像。zoom_range將圖像隨機(jī)縮放高達(dá)20%的倍數(shù)。

valgen對象包含與datagen相同的擴(kuò)充技術(shù),但僅在訓(xùn)練期間應(yīng)用于驗證集。

通過在訓(xùn)練過程中應(yīng)用數(shù)據(jù)擴(kuò)充,模型將暴露于更大、更多樣的訓(xùn)練數(shù)據(jù)集,這有助于防止過度擬合,并提高模型泛化到新數(shù)據(jù)的能力。

datagen.fit(X_train)

valgen.fit(X_val)

這幾行代碼分別將ImageDataGenerator對象datagen和valgen與訓(xùn)練數(shù)據(jù)和驗證數(shù)據(jù)相匹配。

ImageDataGenerator對象的fit()方法計算執(zhí)行數(shù)據(jù)擴(kuò)充所需的任何內(nèi)部統(tǒng)計信息,例如像素值的平均值和方差。在這種情況下,在datagen和valgen上調(diào)用fit()方法,并將訓(xùn)練集和驗證集作為輸入來計算這些統(tǒng)計數(shù)據(jù)。

將ImageDataGenerator對象擬合到數(shù)據(jù)后,可以使用它們在訓(xùn)練和驗證期間實時應(yīng)用數(shù)據(jù)增強(qiáng)。

train_generator = datagen.flow(X_train, y_train, batch_size=64)

val_generator = datagen.flow(X_val, y_val, batch_size=64)

這些代碼行創(chuàng)建了兩個ImageDataGenerator迭代器,train_generator和val_generator,可用于在訓(xùn)練和驗證期間生成一批增強(qiáng)數(shù)據(jù)。

ImageDataGenerator對象的flow()方法接收輸入數(shù)據(jù)和標(biāo)簽的numpy數(shù)組,并動態(tài)生成一批增強(qiáng)數(shù)據(jù)。

在這種情況下,使用datagen上的flow()方法創(chuàng)建train_generator,輸入訓(xùn)練數(shù)據(jù)X_train和y_train,批量大小為64。val_generator在valgen上使用相同的方法創(chuàng)建,輸入驗證數(shù)據(jù)X_val和y_val,批量大小為64。

在訓(xùn)練期間,train_generator(迭代器)將用于為每個訓(xùn)練時期動態(tài)生成一批增強(qiáng)數(shù)據(jù)。類似地,val_generator迭代器將用于為每個驗證epoch生成一批增強(qiáng)數(shù)據(jù)。

代碼下載

http://onepagecode.s3-website-us-east-1.amazonaws.com/

設(shè)計模型卷積神經(jīng)網(wǎng)絡(luò)(CNN)模型

CNN模型有許多層,具有不同的單元,例如卷積層,最大池化層,批量歸一化和退出層,以規(guī)范模型。

def cnn_model():

  model= tf.keras.models.Sequential()

  model.add(Conv2D(32, kernel_size=(3, 3), padding='same', activation='relu', input_shape=(48, 48,1)))

  model.add(Conv2D(64,(3,3), padding='same', activation='relu' ))

  model.add(BatchNormalization())

  model.add(MaxPool2D(pool_size=(2, 2)))

  model.add(Dropout(0.25))

  model.add(Conv2D(128,(5,5), padding='same', activation='relu'))

  model.add(BatchNormalization())

  model.add(MaxPool2D(pool_size=(2, 2)))

  model.add(Dropout(0.25))

      

  model.add(Conv2D(512,(3,3), padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.01)))

  model.add(BatchNormalization())

  model.add(MaxPool2D(pool_size=(2, 2)))

  model.add(Dropout(0.25))

  model.add(Conv2D(512,(3,3), padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.01)))

  model.add(BatchNormalization())

  model.add(MaxPool2D(pool_size=(2, 2)))

  model.add(Dropout(0.25))

  model.add(Conv2D(512,(3,3), padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.01)))

  model.add(BatchNormalization())

  model.add(MaxPool2D(pool_size=(2, 2)))

  model.add(Dropout(0.25))

  model.add(Flatten()) 

  model.add(Dense(256,activation = 'relu'))

  model.add(BatchNormalization())

  model.add(Dropout(0.25))

      

  model.add(Dense(512,activation = 'relu'))

  model.add(BatchNormalization())

  model.add(Dropout(0.25))

  model.add(Dense(7, activation='softmax'))

  model.compile(

    optimizer = Adam(lr=0.0001), 

    loss='categorical_crossentropy', 

    metrics=['accuracy'])

  return model

該代碼使用Keras Sequential API定義了卷積神經(jīng)網(wǎng)絡(luò)(CNN)模型。

CNN體系結(jié)構(gòu)由幾個具有批量歸一化、最大池化和丟棄正則化的卷積層組成,然后是幾個具有批量規(guī)范化和丟棄的全連接(密集)層。最后一層使用softmax激活函數(shù)來輸出7個可能的情緒類別上的概率分布。

Conv2D層創(chuàng)建了一個卷積核,該卷積核與層輸入進(jìn)行卷積,以產(chǎn)生輸出張量。

BatchNormalization層應(yīng)用一個變換,將平均激活保持在接近0的水平,將激活標(biāo)準(zhǔn)偏差保持在接近1的水平。

MaxPooling2D層沿著空間維度對輸入進(jìn)行下采樣。

Dropout層在訓(xùn)練過程中隨機(jī)丟棄一些單元,以防止過度擬合。

Dense層展平輸入,然后將其輸入到完全連接的層中。

模型的compile()方法指定了要在訓(xùn)練過程中使用的優(yōu)化器、損失函數(shù)和評估度量。在這種情況下,優(yōu)化器是Adam,學(xué)習(xí)率為0.0001,損失函數(shù)是分類交叉熵,評估指標(biāo)是準(zhǔn)確性。

該函數(shù)返回已編譯的模型對象。

model = cnn_model()

這行代碼通過調(diào)用前面定義的CNN_model()函數(shù)來創(chuàng)建CNN模型的一個新實例。

模型對象表示可以在數(shù)據(jù)上訓(xùn)練的神經(jīng)網(wǎng)絡(luò)模型,以預(yù)測面部圖像的情緒標(biāo)簽。

然后,我們使用Adam優(yōu)化器以0.0001的學(xué)習(xí)率編譯我們的模型,并選擇度量作為準(zhǔn)確性,然后選擇損失作為分類交叉熵

model.compile(

    optimizer = Adam(lr=0.0001), 

    loss='categorical_crossentropy', 

    metrics=['accuracy'])

這行代碼通過指定要在訓(xùn)練期間使用的優(yōu)化器、損失函數(shù)和評估指標(biāo)來編譯 CNN 模型。

Keras 模型的compile()方法用于在訓(xùn)練前配置學(xué)習(xí)過程。在這種情況下,優(yōu)化器是學(xué)習(xí)率為0.0001的Adam,損失函數(shù)是分類交叉熵,評估指標(biāo)是準(zhǔn)確性。

優(yōu)化器負(fù)責(zé)在訓(xùn)練過程中更新模型參數(shù),Adam 是一種流行的優(yōu)化算法,它根據(jù)損失函數(shù)的梯度調(diào)整學(xué)習(xí)率。

損失函數(shù)用于計算預(yù)測標(biāo)簽和實際標(biāo)簽之間的差異,分類交叉熵是多類分類問題的標(biāo)準(zhǔn)損失函數(shù)。準(zhǔn)確性指標(biāo)用于在訓(xùn)練和驗證期間評估模型的性能。

model.summary()

Model: "sequential_1"

_________________________________________________________________

Layer (type)                 Output Shape              Param #   

=================================================================

conv2d_6 (Conv2D)            (None, 48, 48, 32)        320       

_________________________________________________________________

conv2d_7 (Conv2D)            (None, 48, 48, 64)        18496     

_________________________________________________________________

batch_normalization_7 (Batch (None, 48, 48, 64)        256       

_________________________________________________________________

max_pooling2d_5 (MaxPooling2 (None, 24, 24, 64)        0         

_________________________________________________________________

dropout_7 (Dropout)          (None, 24, 24, 64)        0         

_________________________________________________________________

conv2d_8 (Conv2D)            (None, 24, 24, 128)       204928    

_________________________________________________________________

batch_normalization_8 (Batch (None, 24, 24, 128)       512       

_________________________________________________________________

max_pooling2d_6 (MaxPooling2 (None, 12, 12, 128)       0         

_________________________________________________________________

dropout_8 (Dropout)          (None, 12, 12, 128)       0         

_________________________________________________________________

conv2d_9 (Conv2D)            (None, 12, 12, 512)       590336    

_________________________________________________________________

batch_normalization_9 (Batch (None, 12, 12, 512)       2048      

_________________________________________________________________

max_pooling2d_7 (MaxPooling2 (None, 6, 6, 512)         0         

_________________________________________________________________

dropout_9 (Dropout)          (None, 6, 6, 512)         0         

_________________________________________________________________

conv2d_10 (Conv2D)           (None, 6, 6, 512)         2359808   

_________________________________________________________________

batch_normalization_10 (Batc (None, 6, 6, 512)         2048      

_________________________________________________________________

max_pooling2d_8 (MaxPooling2 (None, 3, 3, 512)         0         

_________________________________________________________________

dropout_10 (Dropout)         (None, 3, 3, 512)         0         

_________________________________________________________________

conv2d_11 (Conv2D)           (None, 3, 3, 512)         2359808   

_________________________________________________________________

batch_normalization_11 (Batc (None, 3, 3, 512)         2048      

_________________________________________________________________

max_pooling2d_9 (MaxPooling2 (None, 1, 1, 512)         0         

_________________________________________________________________

dropout_11 (Dropout)         (None, 1, 1, 512)         0         

_________________________________________________________________

flatten_1 (Flatten)          (None, 512)               0         

_________________________________________________________________

dense_3 (Dense)              (None, 256)               131328    

_________________________________________________________________

batch_normalization_12 (Batc (None, 256)               1024      

_________________________________________________________________

dropout_12 (Dropout)         (None, 256)               0         

_________________________________________________________________

dense_4 (Dense)              (None, 512)               131584    

_________________________________________________________________

batch_normalization_13 (Batc (None, 512)               2048      

_________________________________________________________________

dropout_13 (Dropout)         (None, 512)               0         

_________________________________________________________________

dense_5 (Dense)              (None, 7)                 3591      

=================================================================

Total params: 5,810,183

Trainable params: 5,805,191

Non-trainable params: 4,992

_________________________________________________________________

這行代碼打印了 CNN 模型體系結(jié)構(gòu)的摘要。

Keras 模型的summary()方法打印模型架構(gòu)的摘要,包括每層中的參數(shù)、每層的輸出形狀以及模型中的參數(shù)總數(shù)。

摘要包括有關(guān)模型中每個層的信息,包括層類型、輸出形狀、參數(shù)數(shù)和激活函數(shù)(如果適用)。摘要還包括有關(guān)模型中可訓(xùn)練參數(shù)總數(shù)的信息,這對于了解模型復(fù)雜性和過度擬合的可能性非常有用。

提前停止

添加檢查指針以實現(xiàn)提前停止以防止過度擬合。

checkpointer = [EarlyStopping(monitor = 'val_accuracy', verbose = 1, 

                              restore_best_weights=True,mode="max",patience = 5),

                ModelCheckpoint('best_model.h5',monitor="val_accuracy",verbose=1,

                                save_best_only=True,mode="max")]

此代碼定義將在 CNN 模型訓(xùn)練期間使用的 Keras 回調(diào)列表。

回調(diào)是可以在訓(xùn)練過程中的各個階段應(yīng)用的函數(shù),例如在每個epoch結(jié)束時或驗證精度達(dá)到特定閾值時。它們可用于執(zhí)行操作,例如保存最佳模型權(quán)重、提前停止以防止過度擬合或在模型未改進(jìn)時降低學(xué)習(xí)率。

在這種情況下,checkpointer列表包含兩個回調(diào):

EarlyStopping:此回調(diào)監(jiān)控驗證精度,如果精度在一定數(shù)量的 epoch(由patience參數(shù)指定)后沒有提高,則停止訓(xùn)練過程。restore_best_weights參數(shù)設(shè)置為 True 以在停止訓(xùn)練后恢復(fù)最佳模型的權(quán)重。ModelCheckpoint:此回調(diào)將訓(xùn)練期間最佳模型的權(quán)重保存到名為best_model.h5的文件中。save_best_only參數(shù)設(shè)置為 True 以僅保存導(dǎo)致最高驗證精度的權(quán)重。history = model.fit(train_generator,

                    epochs=30,

                    batch_size=64,   

                    verbose=1,

                    callbacks=[checkpointer],

                    validation_data=val_generator)

此代碼使用 fit() 方法在訓(xùn)練數(shù)據(jù)上訓(xùn)練 CNN 模型。

Keras 模型的fit()方法在指定數(shù)量的 epoch 的輸入數(shù)據(jù)上訓(xùn)練模型。在這種情況下,模型一次使用 30 個圖像的批次訓(xùn)練 64 個 epoch。

train_generator和val_generator對象分別用于生成用于訓(xùn)練和驗證的一批增強(qiáng)圖像;卣{(diào)參數(shù)設(shè)置為前面定義的檢查指針列表,該列表指定在訓(xùn)練期間要使用的早期停止和模型檢查點回調(diào)。

fit()該方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個時期的訓(xùn)練和驗證損失和準(zhǔn)確性。此信息可用于可視化模型隨時間推移的性能,并做出有關(guān)進(jìn)一步訓(xùn)練或模型調(diào)整的決策。

可視化結(jié)果plt.plot(history.history["loss"],'r', label="Training Loss")

plt.plot(history.history["val_loss"],'b', label="Validation Loss")

plt.legend()

此代碼繪制 CNN 模型在訓(xùn)練過程中的訓(xùn)練和驗證損失。

fit()方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個時期的訓(xùn)練和驗證損失和準(zhǔn)確性。此信息可用于可視化模型隨時間推移的性能。

plt.plot()函數(shù)用于繪制紅色的訓(xùn)練損失和藍(lán)色的驗證損失,標(biāo)簽參數(shù)指定每行的圖例標(biāo)簽。調(diào)用legend()函數(shù)是為了在繪圖上顯示圖例。

這段代碼允許我們查看模型的學(xué)習(xí)情況,以及它是否過度擬合到訓(xùn)練數(shù)據(jù)。如果驗證損失開始增加,而訓(xùn)練損失繼續(xù)減少,則表明過度擬合,這意味著模型正在記憶訓(xùn)練數(shù)據(jù),而不是很好地泛化到新數(shù)據(jù)。

plt.plot(history.history["accuracy"],'r',label="Training Accuracy")

plt.plot(history.history["val_accuracy"],'b',label="Validation Accuracy")

plt.legend()

此代碼繪制 CNN 模型在訓(xùn)練過程中的訓(xùn)練和驗證準(zhǔn)確性。

fit()方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個時期的訓(xùn)練和驗證損失和準(zhǔn)確性。此信息可用于可視化模型隨時間推移的性能。

plt.plot()函數(shù)用于繪制紅色的訓(xùn)練精度和藍(lán)色的驗證精度,標(biāo)簽參數(shù)指定每行的圖例標(biāo)簽。調(diào)用legend()函數(shù)是為了在繪圖上顯示圖例。

這段代碼允許我們查看模型的學(xué)習(xí)情況,以及它是否過度擬合到訓(xùn)練數(shù)據(jù)。如果驗證精度開始下降,而訓(xùn)練精度繼續(xù)增加,則表明過度擬合,這意味著模型正在記憶訓(xùn)練數(shù)據(jù),而不是很好地推廣到新數(shù)據(jù)。

loss = model.evaluate(X_test,y_test) 

print("Test Acc: " + str(loss[1]))

此代碼評估測試集上經(jīng)過訓(xùn)練的 CNN 模型的性能。

Keras 模型的evaluate()方法計算給定測試集上的損失和指標(biāo)(在模型編譯期間指定)。

X_test和y_test數(shù)組分別包含測試圖像及其相應(yīng)的標(biāo)簽。model.evaluate()方法用于計算模型在測試集上的損失和準(zhǔn)確性。evaluate()方法將損失值和精度值作為數(shù)組返回。

測試精度是使用model.eevaluate()返回的loss對象打印的。測試精度讓我們了解了模型在新的、看不見的數(shù)據(jù)上的表現(xiàn)。

preds = model.predict(X_test)

y_pred = np.argmax(preds , axis = 1 )

此代碼使用經(jīng)過訓(xùn)練的 CNN 模型生成測試集的預(yù)測。

Keras 模型的predict()方法為給定的輸入數(shù)據(jù)集X_test生成預(yù)測。在這種情況下,數(shù)組包含我們要對其進(jìn)行預(yù)測的測試圖像。

preds數(shù)組包含每個測試圖像的每個類的預(yù)測概率,數(shù)組的每一行對應(yīng)于一個測試圖像,每列對應(yīng)于一個類。

np.argmax()函數(shù)用于提取每個測試圖像具有最高預(yù)測概率的類的索引。這為我們提供了測試集的預(yù)測類標(biāo)簽。

可以將預(yù)測的類標(biāo)簽與真實的類標(biāo)簽y_test進(jìn)行比較,以評估模型在測試集上的性能。

label_dict = {0 : 'Angry', 1 : 'Disgust', 2 : 'Fear', 3 : 'Happiness', 4 : 'Sad', 5 : 'Surprise', 6 : 'Neutral'}

figure = plt.figure(figsize=(20, 8))

for i, index in enumerate(np.random.choice(X_test.shape[0], size=24, replace=False)):

    ax = figure.add_subplot(4, 6, i + 1, xticks=[], yticks=[])

    ax.imshow(np.squeeze(X_test[index]))

    predict_index = label_dict[(y_pred[index])]

    true_index = label_dict[np.argmax(y_test,axis=1)[index]]

    

    ax.set_title("{} ({})".format((predict_index), 

                                  (true_index)),

                                  color=("green" if predict_index == true_index else "red"))

此代碼生成測試圖像的隨機(jī)子集及其真實和預(yù)測標(biāo)簽的可視化。

label_dict字典將整數(shù)類標(biāo)簽映射到它們對應(yīng)的字符串標(biāo)簽。

然后,該代碼生成一個包含24個子圖(4行6列)的圖形,每個子圖顯示一個隨機(jī)測試圖像及其預(yù)測和真實標(biāo)簽。函數(shù)的作用是從X_test數(shù)組中隨機(jī)選擇24個索引。

對于每個子圖,使用imshow()顯示測試圖像,并使用set_title()在子圖的標(biāo)題中顯示預(yù)測標(biāo)簽和真實標(biāo)簽。如果預(yù)測標(biāo)簽與真實標(biāo)簽匹配,則以綠色突出顯示,否則以紅色突出顯示。

CLASS_LABELS  = ['Anger', 'Disgust', 'Fear', 'Happy', 'Neutral', 'Sadness', "Surprise"]

cm_data = confusion_matrix(np.argmax(y_test, axis = 1 ), y_pred)

cm = pd.DataFrame(cm_data, columns=CLASS_LABELS, index = CLASS_LABELS)

cm.index.name = 'Actual'

cm.columns.name = 'Predicted'

plt.figure(figsize = (15,10))

plt.title('Confusion Matrix', fontsize = 20)

sns.set(font_scale=1.2)

ax = sns.heatmap(cm, cbar=False, cmap="Blues", annot=True, annot_kws={"size": 16}, fmt='g')

此代碼生成測試集上模型預(yù)測的混淆矩陣的熱圖。

CLASS_LABELS列表包含七個情感類的名稱。

scikit learn的metrics模塊中的confusion_matrix()函數(shù)用于計算模型在測試集上的預(yù)測的混淆矩陣。函數(shù)np.argmax()用于將one hot編碼的真實標(biāo)簽和預(yù)測標(biāo)簽轉(zhuǎn)換為整數(shù)標(biāo)簽。

生成的混淆矩陣存儲在pandas DataFrame cm中,類名作為行和列標(biāo)簽。然后使用seaborn的heatmap()函數(shù)將DataFrame顯示為熱圖。熱圖使用混淆矩陣的值進(jìn)行注釋,并使用sns.set(font_scale=1.2)增加字體大小。

from sklearn.metrics import classification_report

print(classification_report(np.argmax(y_test, axis = 1 ),y_pred,digits=3))

classification_report()的輸出含義如下:

Precision:預(yù)測的陽性病例與實際陽性病例的比例。在數(shù)學(xué)上,它是TP /(TP + FP),其中TP是真陽性的數(shù)量,F(xiàn)P是誤報的數(shù)量。高精度分?jǐn)?shù)表示模型在預(yù)測正類時是準(zhǔn)確的。Recall:模型正確預(yù)測為陽性的實際陽性事例的比例。在數(shù)學(xué)上,它是TP / (TP + FN),其中FN是假陰性的數(shù)量。較高的召回率分?jǐn)?shù)表示模型能夠正確識別陽性病例。F1 分?jǐn)?shù):精度和召回率的調(diào)和平均值。它同時考慮了精度和召回率,并提供平衡兩者的單一分?jǐn)?shù)。在數(shù)學(xué)上,它是 2 * (precision * recall) / (precision + recall).Support:類在測試數(shù)據(jù)中實際出現(xiàn)的次數(shù)。

下面是分類報告中不同行的說明:

Precision:第一行顯示每個類的精度分?jǐn)?shù)。Recall:第二行顯示每個班級的召回分?jǐn)?shù)。F1 分?jǐn)?shù):第三行顯示每個類的 F1 分?jǐn)?shù)。Support:最后一行顯示測試數(shù)據(jù)中每個類的出現(xiàn)次數(shù)。

請注意,宏觀平均值和加權(quán)平均值也位于報告底部。

微調(diào)模型model = cnn_model()

model.compile(optimizer=tf.keras.optimizers.SGD(0.001),

                loss='categorical_crossentropy',

                metrics = ['accuracy'])

該模型的優(yōu)化器已從Adam更改為SGD,學(xué)習(xí)率為0.001。損失函數(shù)保持不變,即類別交叉熵。精度度量也是相同的。

history = model.fit(train_generator,

                    epochs=30,

                    batch_size=64,   

                    verbose=1,

                    callbacks=[checkpointer],

                    validation_data=val_generator)

使用train_generator和val_generator分別作為訓(xùn)練和驗證數(shù)據(jù),再次對模型進(jìn)行 30 個時期的訓(xùn)練,批量大小為64。

檢查指針回調(diào)還用于保存基于驗證準(zhǔn)確性的最佳模型。

loss = model.evaluate(X_test,y_test) 

print("Test Acc: " + str(loss[1]))

打印使用SGD優(yōu)化器微調(diào)模型后的測試精度,學(xué)習(xí)率為0.001。

plt.plot(history.history["loss"],'r', label="Training Loss")

plt.plot(history.history["val_loss"],'b', label="Validation Loss")

plt.legend()

該圖顯示了模型訓(xùn)練期間各個時期的訓(xùn)練損失(紅色)和驗證損失(藍(lán)色)。x 軸表示周期數(shù),y 軸表示損失。它有助于確定模型是過度擬合還是擬合不足。

如果訓(xùn)練損失在減少,但驗證損失在增加或不減少,則意味著模型過度擬合。如果訓(xùn)練和驗證損失都很高,則意味著模型擬合不足。

從圖中看,訓(xùn)練和驗證損失似乎在減少,這意味著模型正在從數(shù)據(jù)中學(xué)習(xí)。

更改epoch編號model.compile(

    optimizer = Adam(lr=0.0001), 

    loss='categorical_crossentropy', 

    metrics=['accuracy'])

checkpointer = [EarlyStopping(monitor = 'val_accuracy', verbose = 1, 

                              restore_best_weights=True,mode="max",patience = 10),

                              ModelCheckpoint('best_model.h5',monitor="val_accuracy",verbose=1,

                              save_best_only=True,mode="max")]

history = model.fit(train_generator,

                    epochs=50,

                    batch_size=64,   

                    verbose=1,

                    callbacks=[checkpointer],

                    validation_data=val_generator)

更新后的代碼再次訓(xùn)練模型 50 個epoch,并提前停止回調(diào),耐心等待 10 個epoch。最佳模型將保存為“best_model.h5”,具有最大的驗證精度。

該模型將使用 Adam 優(yōu)化器進(jìn)行編譯,學(xué)習(xí)率為 0.0001,分類交叉熵?fù)p失和準(zhǔn)確性作為指標(biāo)。訓(xùn)練生成器和驗證生成器是之前使用數(shù)據(jù)增強(qiáng)技術(shù)定義的。

loss = model.evaluate(X_test,y_test) 

print("Test Acc: " + str(loss[1]))

CLASS_LABELS  = ['Anger', 'Disgust', 'Fear', 'Happy', 'Neutral', 'Sadness', "Surprise"]

cm_data = confusion_matrix(np.argmax(y_test, axis = 1 ), y_pred)

cm = pd.DataFrame(cm_data, columns=CLASS_LABELS, index = CLASS_LABELS)

cm.index.name = 'Actual'

cm.columns.name = 'Predicted'

plt.figure(figsize = (20,10))

plt.title('Confusion Matrix', fontsize = 20)

sns.set(font_scale=1.2)

ax = sns.heatmap(cm, cbar=False, cmap="Blues", annot=True, annot_kws={"size": 16}, fmt='g')

       原文標(biāo)題 : 使用 CNN 進(jìn)行面部情緒識別

聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯
x
*文字標(biāo)題:
*糾錯內(nèi)容:
聯(lián)系郵箱:
*驗 證 碼:

粵公網(wǎng)安備 44030502002758號