使用 CNN 進(jìn)行面部情緒識別
面部表情是人類之間交流的重要方式。
在人工智能研究中,深度學(xué)習(xí)技術(shù)已成為增強(qiáng)人機(jī)交互的強(qiáng)大工具。心理學(xué)中面部表情和情緒的分析和評估涉及評估預(yù)測個(gè)人或群體情緒的決定。
本研究旨在開發(fā)一種能夠使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)算法和特征提取技術(shù)預(yù)測和分類面部情緒的系統(tǒng)。
該過程包括三個(gè)主要階段:數(shù)據(jù)預(yù)處理、面部特征提取和面部情緒分類。通過采用卷積神經(jīng)網(wǎng)絡(luò)(CNN)算法,系統(tǒng)準(zhǔn)確預(yù)測面部表情,成功率為62.66%。
該算法的性能使用FER2013數(shù)據(jù)庫進(jìn)行評估,該數(shù)據(jù)庫是一個(gè)公開可用的數(shù)據(jù)集,包含35,887張48x48灰度面部圖像,每張圖像代表一種不同的情緒。
現(xiàn)在讓我們從編碼開始。
!pip install scikit-plot
此代碼使用 pip 安裝 scikit-plot 包,pip 是一個(gè) 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。
每個(gè) 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()
此代碼將返回?cái)?shù)據(jù)幀data的每一列中所有缺失值的總和。
數(shù)據(jù)幀的isnull()方法返回一個(gè)布爾數(shù)據(jù)幀,該幀指示原始數(shù)據(jù)幀中的每個(gè)元素是否丟失。然后將sum()方法應(yīng)用于此布爾數(shù)據(jù)幀,該幀返回每列中缺失值的總和。
這是檢查數(shù)據(jù)幀中是否存在任何缺失值的快速方法。如果存在缺失值,則可能需要在將數(shù)據(jù)用于建模之前插補(bǔ)或刪除這些值。
data.head()
此代碼將返回?cái)?shù)據(jù)幀data的前 5 行。
數(shù)據(jù)幀的head()方法返回?cái)?shù)據(jù)幀的前n行(默認(rèn)情況下為n=5 )。這是快速瀏覽數(shù)據(jù)幀中的數(shù)據(jù)的有用方法,尤其是在處理大型數(shù)據(jù)集時(shí)。
輸出將顯示數(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中定義一個(gè)類標(biāo)簽列表,它對應(yīng)于數(shù)據(jù)集中的不同情緒。
然后,調(diào)用px.bar()函數(shù),其中 x 軸表示類標(biāo)簽,y 軸表示每個(gè)情緒的圖像數(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()方法以顯示繪圖。
輸出將顯示一個(gè)條形圖,該條形圖顯示數(shù)據(jù)幀data中每個(gè)情緒的圖像數(shù),每個(gè)情緒根據(jù)指定的色階進(jìn)行顏色編碼。
隨機(jī)打亂數(shù)據(jù)data = data.sample(frac=1)
DataFrame 的sample()方法用于隨機(jī)采樣數(shù)據(jù)幀中行的一小部分,并指定frac要返回的行部分(在本例中為 frac=1,這意味著將返回所有行)。當(dāng)frac=1時(shí),sample()方法有效地對數(shù)據(jù)幀中的行進(jìn)行洗牌。
這是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)中的常見操作,隨機(jī)打亂數(shù)據(jù)以防止在數(shù)據(jù)具有任何固有順序或結(jié)構(gòu)時(shí)可能引入的任何偏差非常重要。
One Hot編碼labels = to_categorical(data[['emotion']], num_classes=7)
輸出是一個(gè)形狀為(n_samples, n_classes)的 numpy 數(shù)組,其中:
n_samples是數(shù)據(jù)幀中的樣本數(shù)n_classes是數(shù)據(jù)中唯一類的數(shù)量(在本例中為 7)數(shù)組data的每一行表示數(shù)據(jù)幀中單個(gè)樣本的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ù)類型。
輸出是一個(gè)形狀為(n_samples, n_pixels)的 numpy 數(shù)組,其中n_samples是數(shù)據(jù)幀中的樣本數(shù),n_pixels是數(shù)據(jù)中每個(gè)圖像的像素?cái)?shù)。數(shù)組data的每一行表示數(shù)據(jù)幀中單個(gè)圖像的像素值。
標(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是每個(gè)圖像的行數(shù),1 表示DataFrame中每個(gè)圖像的展平像素值。陣列的每一行表示DataFrame中單個(gè)圖像的單個(gè)像素值。
scaler = StandardScaler()
pixels = scaler.fit_transform(pixels)
此代碼使用scikit learn的StandardScaler()函數(shù)將標(biāo)準(zhǔn)化應(yīng)用于像素numpy數(shù)組。
StandardScaler()函數(shù)是一個(gè)預(yù)處理步驟,用于縮放數(shù)據(jù)的每個(gè)特征(在本例中為每個(gè)像素值),使其均值為 0,方差為 1。這是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)任務(wù)中常用的技術(shù),可確保每個(gè)特征對模型的貢獻(xiàn)相同。
然后在像素numpy數(shù)組上調(diào)用StandardScaler()對象的fit_transform()方法,該方法計(jì)算數(shù)據(jù)的平均值和標(biāo)準(zhǔn)偏差,并相應(yīng)地縮放數(shù)據(jù)。然后將得到的縮放數(shù)據(jù)分配回像素numpy數(shù)組。
輸出是一個(gè)與原始pixels數(shù)組形狀相同的 numpy 數(shù)組,但每個(gè)像素值都已標(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個(gè)通道的4D陣列。
得到的像素陣列的形狀為(n_samples,n_rows,n_columns,n_channels),其中n_samples是DataFrame中的樣本數(shù)量,n_row是每個(gè)圖像的行數(shù),n_column是每個(gè)圖像中的列數(shù),n_channel表示每個(gè)圖像中顏色通道的數(shù)量。
由于原始數(shù)據(jù)集是灰度級的,因此n_channels設(shè)置為1。像素陣列的每個(gè)元素表示DataFrame中單個(gè)灰度圖像的像素值。
訓(xùn)練測試驗(yàn)證拆分
現(xiàn)在,我們有 35887 張圖像,每張圖像包含 48x48 像素。我們將數(shù)據(jù)拆分為訓(xùn)練、測試和驗(yàn)證數(shù)據(jù),以 10% 的比例提供、評估和驗(yàn)證我們的數(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ù)像素和一個(gè)熱編碼的標(biāo)簽標(biāo)簽拆分為訓(xùn)練集、驗(yà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àn)證集和測試集的像素值。y_train、y_val和y_test數(shù)組包含對應(yīng)集合的one hot編碼標(biāo)簽。
再次使用train_test_split()將訓(xùn)練集進(jìn)一步拆分為訓(xùn)練集和驗(yàn)證集,test_size=0.1。這將數(shù)據(jù)分成80%用于訓(xùn)練,10%用于驗(yàn)證,10%用于測試。
print(X_train.shape)
print(X_test.shape)
print(X_val.shape)
在將數(shù)據(jù)拆分為訓(xùn)練集、驗(yàn)證集和測試集之后,這些代碼行打印X_train、X_test和X_val數(shù)組的形狀。
numpy數(shù)組的shape屬性返回?cái)?shù)組維度的元組。在這種情況下,X_train、X_test和X_val數(shù)組的形狀將取決于每個(gè)集合中的樣本數(shù)量和每個(gè)樣本的維度。
輸出將以格式(n_samples、n_rows、n_columns、n_channel)顯示陣列的形狀,其中n_samples是集合中的樣本數(shù),n_rows是每個(gè)圖像的行數(shù),n_columns是每個(gè)圖像中的列數(shù),n_channel表示每個(gè)圖像中顏色通道的數(shù)量。
在這個(gè)繪圖代碼的幫助下,我們可以看到一些包含每個(gè)類的一個(gè)樣本的訓(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ù)組。
對于每個(gè)子圖,imshow()函數(shù)用于顯示相應(yīng)的圖像,title()函數(shù)用來顯示相應(yīng)的標(biāo)簽。
axis()函數(shù)用于關(guān)閉每個(gè)子圖的軸。
輸出是訓(xùn)練集中的前 7 個(gè)圖像的可視化,以及它們對應(yīng)的標(biāo)簽。
使用圖像數(shù)據(jù)生成器進(jìn)行數(shù)據(jù)增強(qiáng)
我們可以進(jìn)行數(shù)據(jù)增強(qiáng),以獲得更多數(shù)據(jù)來訓(xùn)練和驗(yàn)證我們的模型,以防止過度擬合。數(shù)據(jù)增強(qiáng)可以在訓(xùn)練集和驗(yàn)證集上完成,因?yàn)樗兄谀P妥兊酶油ㄓ煤徒选?/p>
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)建兩個(gè)ImageDataGenerator對象,datagen和valgen,它們將用于訓(xùn)練和驗(yàn)證期間的數(shù)據(jù)擴(kuò)充。
ImageDataGenerator類是一個(gè)Keras預(yù)處理實(shí)用程序,可以實(shí)時(shí)執(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)用于驗(yàn)證集。
通過在訓(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ù)和驗(yàn)證數(shù)據(jù)相匹配。
ImageDataGenerator對象的fit()方法計(jì)算執(zhí)行數(shù)據(jù)擴(kuò)充所需的任何內(nèi)部統(tǒng)計(jì)信息,例如像素值的平均值和方差。在這種情況下,在datagen和valgen上調(diào)用fit()方法,并將訓(xùn)練集和驗(yàn)證集作為輸入來計(jì)算這些統(tǒng)計(jì)數(shù)據(jù)。
將ImageDataGenerator對象擬合到數(shù)據(jù)后,可以使用它們在訓(xùn)練和驗(yàn)證期間實(shí)時(shí)應(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)建了兩個(gè)ImageDataGenerator迭代器,train_generator和val_generator,可用于在訓(xùn)練和驗(yà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)建,輸入驗(yàn)證數(shù)據(jù)X_val和y_val,批量大小為64。
在訓(xùn)練期間,train_generator(迭代器)將用于為每個(gè)訓(xùn)練時(shí)期動態(tài)生成一批增強(qiáng)數(shù)據(jù)。類似地,val_generator迭代器將用于為每個(gè)驗(yàn)證epoch生成一批增強(qiáng)數(shù)據(jù)。
代碼下載
http://onepagecode.s3-website-us-east-1.amazonaws.com/
設(shè)計(jì)模型卷積神經(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)由幾個(gè)具有批量歸一化、最大池化和丟棄正則化的卷積層組成,然后是幾個(gè)具有批量規(guī)范化和丟棄的全連接(密集)層。最后一層使用softmax激活函數(shù)來輸出7個(gè)可能的情緒類別上的概率分布。
Conv2D層創(chuàng)建了一個(gè)卷積核,該卷積核與層輸入進(jìn)行卷積,以產(chǎn)生輸出張量。
BatchNormalization層應(yīng)用一個(gè)變換,將平均激活保持在接近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模型的一個(gè)新實(shí)例。
模型對象表示可以在數(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ù)用于計(jì)算預(yù)測標(biāo)簽和實(shí)際標(biāo)簽之間的差異,分類交叉熵是多類分類問題的標(biāo)準(zhǔn)損失函數(shù)。準(zhǔn)確性指標(biāo)用于在訓(xùn)練和驗(yà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)模型中每個(gè)層的信息,包括層類型、輸出形狀、參數(shù)數(shù)和激活函數(shù)(如果適用)。摘要還包括有關(guān)模型中可訓(xùn)練參數(shù)總數(shù)的信息,這對于了解模型復(fù)雜性和過度擬合的可能性非常有用。
提前停止
添加檢查指針以實(shí)現(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)練過程中的各個(gè)階段應(yīng)用的函數(shù),例如在每個(gè)epoch結(jié)束時(shí)或驗(yàn)證精度達(dá)到特定閾值時(shí)。它們可用于執(zhí)行操作,例如保存最佳模型權(quán)重、提前停止以防止過度擬合或在模型未改進(jìn)時(shí)降低學(xué)習(xí)率。
在這種情況下,checkpointer列表包含兩個(gè)回調(diào):
EarlyStopping:此回調(diào)監(jiān)控驗(yà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)致最高驗(yàn)證精度的權(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 個(gè)圖像的批次訓(xùn)練 64 個(gè) epoch。
train_generator和val_generator對象分別用于生成用于訓(xùn)練和驗(yàn)證的一批增強(qiáng)圖像;卣{(diào)參數(shù)設(shè)置為前面定義的檢查指針列表,該列表指定在訓(xùn)練期間要使用的早期停止和模型檢查點(diǎn)回調(diào)。
fit()該方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個(gè)時(shí)期的訓(xùn)練和驗(yàn)證損失和準(zhǔn)確性。此信息可用于可視化模型隨時(shí)間推移的性能,并做出有關(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)練和驗(yàn)證損失。
fit()方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個(gè)時(shí)期的訓(xùn)練和驗(yàn)證損失和準(zhǔn)確性。此信息可用于可視化模型隨時(shí)間推移的性能。
plt.plot()函數(shù)用于繪制紅色的訓(xùn)練損失和藍(lán)色的驗(yàn)證損失,標(biāo)簽參數(shù)指定每行的圖例標(biāo)簽。調(diào)用legend()函數(shù)是為了在繪圖上顯示圖例。
這段代碼允許我們查看模型的學(xué)習(xí)情況,以及它是否過度擬合到訓(xùn)練數(shù)據(jù)。如果驗(yàn)證損失開始增加,而訓(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)練和驗(yàn)證準(zhǔn)確性。
fit()方法返回的history對象包含有關(guān)訓(xùn)練過程的信息,包括每個(gè)時(shí)期的訓(xùn)練和驗(yàn)證損失和準(zhǔn)確性。此信息可用于可視化模型隨時(shí)間推移的性能。
plt.plot()函數(shù)用于繪制紅色的訓(xùn)練精度和藍(lán)色的驗(yàn)證精度,標(biāo)簽參數(shù)指定每行的圖例標(biāo)簽。調(diào)用legend()函數(shù)是為了在繪圖上顯示圖例。
這段代碼允許我們查看模型的學(xué)習(xí)情況,以及它是否過度擬合到訓(xùn)練數(shù)據(jù)。如果驗(yàn)證精度開始下降,而訓(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()方法計(jì)算給定測試集上的損失和指標(biāo)(在模型編譯期間指定)。
X_test和y_test數(shù)組分別包含測試圖像及其相應(yīng)的標(biāo)簽。model.evaluate()方法用于計(jì)算模型在測試集上的損失和準(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ù)組包含每個(gè)測試圖像的每個(gè)類的預(yù)測概率,數(shù)組的每一行對應(yīng)于一個(gè)測試圖像,每列對應(yīng)于一個(gè)類。
np.argmax()函數(shù)用于提取每個(gè)測試圖像具有最高預(yù)測概率的類的索引。這為我們提供了測試集的預(yù)測類標(biāo)簽。
可以將預(yù)測的類標(biāo)簽與真實(shí)的類標(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ī)子集及其真實(shí)和預(yù)測標(biāo)簽的可視化。
label_dict字典將整數(shù)類標(biāo)簽映射到它們對應(yīng)的字符串標(biāo)簽。
然后,該代碼生成一個(gè)包含24個(gè)子圖(4行6列)的圖形,每個(gè)子圖顯示一個(gè)隨機(jī)測試圖像及其預(yù)測和真實(shí)標(biāo)簽。函數(shù)的作用是從X_test數(shù)組中隨機(jī)選擇24個(gè)索引。
對于每個(gè)子圖,使用imshow()顯示測試圖像,并使用set_title()在子圖的標(biāo)題中顯示預(yù)測標(biāo)簽和真實(shí)標(biāo)簽。如果預(yù)測標(biāo)簽與真實(shí)標(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列表包含七個(gè)情感類的名稱。
scikit learn的metrics模塊中的confusion_matrix()函數(shù)用于計(jì)算模型在測試集上的預(yù)測的混淆矩陣。函數(shù)np.argmax()用于將one hot編碼的真實(shí)標(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í)際陽性病例的比例。在數(shù)學(xué)上,它是TP /(TP + FP),其中TP是真陽性的數(shù)量,F(xiàn)P是誤報(bào)的數(shù)量。高精度分?jǐn)?shù)表示模型在預(yù)測正類時(shí)是準(zhǔn)確的。Recall:模型正確預(yù)測為陽性的實(shí)際陽性事例的比例。在數(shù)學(xué)上,它是TP / (TP + FN),其中FN是假陰性的數(shù)量。較高的召回率分?jǐn)?shù)表示模型能夠正確識別陽性病例。F1 分?jǐn)?shù):精度和召回率的調(diào)和平均值。它同時(shí)考慮了精度和召回率,并提供平衡兩者的單一分?jǐn)?shù)。在數(shù)學(xué)上,它是 2 * (precision * recall) / (precision + recall).Support:類在測試數(shù)據(jù)中實(shí)際出現(xiàn)的次數(shù)。
下面是分類報(bào)告中不同行的說明:
Precision:第一行顯示每個(gè)類的精度分?jǐn)?shù)。Recall:第二行顯示每個(gè)班級的召回分?jǐn)?shù)。F1 分?jǐn)?shù):第三行顯示每個(gè)類的 F1 分?jǐn)?shù)。Support:最后一行顯示測試數(shù)據(jù)中每個(gè)類的出現(xiàn)次數(shù)。
請注意,宏觀平均值和加權(quán)平均值也位于報(bào)告底部。
微調(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)練和驗(yàn)證數(shù)據(jù),再次對模型進(jìn)行 30 個(gè)時(shí)期的訓(xùn)練,批量大小為64。
檢查指針回調(diào)還用于保存基于驗(yàn)證準(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)練期間各個(gè)時(shí)期的訓(xùn)練損失(紅色)和驗(yàn)證損失(藍(lán)色)。x 軸表示周期數(shù),y 軸表示損失。它有助于確定模型是過度擬合還是擬合不足。
如果訓(xùn)練損失在減少,但驗(yàn)證損失在增加或不減少,則意味著模型過度擬合。如果訓(xùn)練和驗(yàn)證損失都很高,則意味著模型擬合不足。
從圖中看,訓(xùn)練和驗(yà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 個(gè)epoch,并提前停止回調(diào),耐心等待 10 個(gè)epoch。最佳模型將保存為“best_model.h5”,具有最大的驗(yàn)證精度。
該模型將使用 Adam 優(yōu)化器進(jìn)行編譯,學(xué)習(xí)率為 0.0001,分類交叉熵?fù)p失和準(zhǔn)確性作為指標(biāo)。訓(xùn)練生成器和驗(yà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)行面部情緒識別
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個(gè)字
最新活動更多
-
即日-10.29立即報(bào)名>> 2024德州儀器嵌入式技術(shù)創(chuàng)新發(fā)展研討會
-
10月31日立即下載>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報(bào)名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月14日立即報(bào)名>> 2024工程師系列—工業(yè)電子技術(shù)在線會議
-
12月19日立即報(bào)名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報(bào)名中>> OFweek2024中國智造CIO在線峰會
推薦專題
- 1 Intel宣布40年來最重大轉(zhuǎn)型:年底前裁員15000人、拋掉2/3房產(chǎn)
- 2 因美封殺TikTok,字節(jié)股價(jià)骨折!估值僅Meta1/5
- 3 宏山激光重磅發(fā)布行業(yè)解決方案,助力智能制造產(chǎn)業(yè)新飛躍
- 4 國產(chǎn)AI芯片公司破產(chǎn)!白菜價(jià)拍賣
- 5 具身智能火了,但規(guī)模落地還需時(shí)間
- 6 國產(chǎn)英偉達(dá)們,抓緊沖刺A股
- 7 三次錯(cuò)失風(fēng)口!OpenAI前員工殺回AI編程賽道,老東家捧金相助
- 8 英特爾賦能智慧醫(yī)療,共創(chuàng)數(shù)字化未來
- 9 英偉達(dá)的麻煩在后頭?
- 10 將“網(wǎng)紅”變成“商品”,AI“爆改”實(shí)力拉滿
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市