0 前言
?? 這兩年開始畢業(yè)設計和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設題目缺少創(chuàng)新和亮點,往往達不到畢業(yè)答辯的要求,這兩年不斷有學弟學妹告訴學長自己做的項目系統(tǒng)達不到老師的要求。
為了大家能夠順利以及最少的精力通過畢設,學長分享優(yōu)質(zhì)畢業(yè)設計項目,今天要分享的是
?? 基于深度學習的人臉年齡性別識別算法實現(xiàn)
??學長這里給一個題目綜合評分(每項滿分5分)
- 難度系數(shù):4分
- 工作量:4分
- 創(chuàng)新點:3分
1 項目課題介紹
年齡和性別作為人重要的生物特征, 可以應用于多種場景, 如基于年齡的人機交互系統(tǒng)、電子商務中個性營銷、刑事案件偵察中的年齡過濾等。然而基于圖像的年齡分類和性別檢測在真實場景下受很多因素影響, 如后天的生活工作環(huán)境等, 并且人臉圖像中的復雜光線環(huán)境、姿態(tài)、表情以及圖片本身的質(zhì)量等因素都會給識別造成困難。
學長這次設計的項目 基于深度學習卷積神經(jīng)網(wǎng)絡,利用Tensorflow和Keras等工具實現(xiàn)圖像年齡和性別檢測。
2 關(guān)鍵技術(shù)
2.1 卷積神經(jīng)網(wǎng)絡
受到人類大腦神經(jīng)突觸結(jié)構(gòu)相互連接的模式啟發(fā),神經(jīng)網(wǎng)絡作為人工智能領(lǐng)域的重要組成部分,通過分布式的方法處理信息,可以解決復雜的非線性問題,從構(gòu)造方面來看,主要包括輸入層、隱藏層、輸出層三大組成結(jié)構(gòu)。每一個節(jié)點被稱為一個神經(jīng)元,存在著對應的權(quán)重參數(shù),部分神經(jīng)元存在偏置,當輸入數(shù)據(jù)x進入后,對于經(jīng)過的神經(jīng)元都會進行類似于:y=w*x+b的線性函數(shù)的計算,其中w為該位置神經(jīng)元的權(quán)值,b則為偏置函數(shù)。通過每一層神經(jīng)元的邏輯運算,將結(jié)果輸入至最后一層的激活函數(shù),最后得到輸出output。
2.2 卷積層
卷積核相當于一個滑動窗口,示意圖中3x3大小的卷積核依次劃過6x6大小的輸入數(shù)據(jù)中的對應區(qū)域,并與卷積核滑過區(qū)域做矩陣點乘,將所得結(jié)果依次填入對應位置即可得到右側(cè)4x4尺寸的卷積特征圖,例如劃到右上角3x3所圈區(qū)域時,將進行0x0+1x1+2x1+1x1+0x0+1x1+1x0+2x0x1x1=6的計算操作,并將得到的數(shù)值填充到卷積特征的右上角。
2.3 池化層
池化操作又稱為降采樣,提取網(wǎng)絡主要特征可以在達到空間不變性的效果同時,有效地減少網(wǎng)絡參數(shù),因而簡化網(wǎng)絡計算復雜度,防止過擬合現(xiàn)象的出現(xiàn)。在實際操作中經(jīng)常使用最大池化或平均池化兩種方式,如下圖所示。雖然池化操作可以有效的降低參數(shù)數(shù)量,但過度池化也會導致一些圖片細節(jié)的丟失,因此在搭建網(wǎng)絡時要根據(jù)實際情況來調(diào)整池化操作。
2.4 激活函數(shù):
激活函數(shù)大致分為兩種,在卷積神經(jīng)網(wǎng)絡的發(fā)展前期,使用較為傳統(tǒng)的飽和激活函數(shù),主要包括sigmoid函數(shù)、tanh函數(shù)等;隨著神經(jīng)網(wǎng)絡的發(fā)展,研宄者們發(fā)現(xiàn)了飽和激活函數(shù)的弱點,并針對其存在的潛在問題,研宄了非飽和激活函數(shù),其主要含有ReLU函數(shù)及其函數(shù)變體
2.5 全連接層
在整個網(wǎng)絡結(jié)構(gòu)中起到“分類器”的作用,經(jīng)過前面卷積層、池化層、激活函數(shù)層之后,網(wǎng)絡己經(jīng)對輸入圖片的原始數(shù)據(jù)進行特征提取,并將其映射到隱藏特征空間,全連接層將負責將學習到的特征從隱藏特征空間映射到樣本標記空間,一般包括提取到的特征在圖片上的位置信息以及特征所屬類別概率等。將隱藏特征空間的信息具象化,也是圖像處理當中的重要一環(huán)。
3 使用tensorflow中keras模塊實現(xiàn)卷積神經(jīng)網(wǎng)絡
class CNN(tf.keras.Model):
def __init__(self):
super().__init__()
self.conv1 = tf.keras.layers.Conv2D(
filters=32, # 卷積層神經(jīng)元(卷積核)數(shù)目
kernel_size=[5, 5], # 感受野大小
padding='same', # padding策略(vaild 或 same)
activation=tf.nn.relu # 激活函數(shù)
)
self.pool1 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
self.conv2 = tf.keras.layers.Conv2D(
filters=64,
kernel_size=[5, 5],
padding='same',
activation=tf.nn.relu
)
self.pool2 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
self.flatten = tf.keras.layers.Reshape(target_shape=(7 * 7 * 64,))
self.dense1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)
self.dense2 = tf.keras.layers.Dense(units=10)
def call(self, inputs):
x = self.conv1(inputs) # [batch_size, 28, 28, 32]
x = self.pool1(x) # [batch_size, 14, 14, 32]
x = self.conv2(x) # [batch_size, 14, 14, 64]
x = self.pool2(x) # [batch_size, 7, 7, 64]
x = self.flatten(x) # [batch_size, 7 * 7 * 64]
x = self.dense1(x) # [batch_size, 1024]
x = self.dense2(x) # [batch_size, 10]
output = tf.nn.softmax(x)
return output
4 Keras介紹
keras是一個專門用于深度學習的開發(fā)軟件。它的編程語言采用的為現(xiàn)在最流行的python語言,集成封裝了CNTK,Tensorflow或者Theano深度學習框架為計算機后臺進行深度建模,具有易于學習,高效編程的功能,數(shù)據(jù)的運算處理支持GPU和CPU,真正實現(xiàn)了二者的無縫切換。正是keras有如此特殊功能,所以它的優(yōu)點有如下幾個方面:
4.1 Keras深度學習模型
Keras深度學習模型可以分為兩種:一種是序列模型,一種是通用模型。它們的區(qū)別在于其擁有不同的網(wǎng)絡拓撲結(jié)構(gòu)。序列模型是通用模型的一個范例,通常情況下應用比較廣。每層之間的連接方式都是線性的,且在相鄰的兩層之間可以添加任意可用元素構(gòu)建神經(jīng)網(wǎng)絡。通用模型是為了適用于復雜模型而設計的,所以常用于復雜的神經(jīng)網(wǎng)絡中。在使用過程中應用接口模型的要素和結(jié)構(gòu)通常需要用函數(shù)化來定義。其定義的大致過程:首先是輸入層的定義,然后是其他各層及要素的定義,最后到輸出層,并將這個定義過程作為一個模型,進行運行和調(diào)試。
4.2 Keras中重要的預定義對象
Keras預定義了很多對象目的就是構(gòu)造其網(wǎng)絡結(jié)構(gòu),正是有了這么多的預定義對象才讓Keras使用起來非常方便易用。研究中用的最多要數(shù)正則化、激活函數(shù)及初始化對象了。
-
正則化是在建模時防止過度擬合的最常用且效果最有效的手段之一。在神經(jīng)網(wǎng)絡中采用的手段有權(quán)重參數(shù)、偏置項以及激活函數(shù),其分別對應的代碼是kernel_regularizier、bias_regularizier以及activity_regularizier。
-
激活函數(shù)在網(wǎng)絡定義中的選取十分重要。為了方便Keras預定義了豐富的激活函數(shù),以此是適應不同的網(wǎng)絡結(jié)構(gòu)。使用激活對象的方式有兩種:一個是單獨定義一個激活函數(shù)層,二是通利用前置層的激活選項定義激活函數(shù)。
-
初始化對象是隨機給定網(wǎng)絡層激活函數(shù)kernel_initializer or bias_initializer的開始值。權(quán)重初始化值好與壞直接影響模型的訓練時間的長短。
4.3 Keras的網(wǎng)絡層構(gòu)造
在Keras框架中,不同的網(wǎng)絡層(Layer)定義了神經(jīng)網(wǎng)絡的具體結(jié)構(gòu)。在實際網(wǎng)絡構(gòu)建中常見的用Core Layer、Convolution Layer、Pooling Layer、Emberdding Layer等。
5 數(shù)據(jù)集處理訓練
該項目將采集的照片分為男女兩個性別;‘0-9’, ‘10-19’, ‘20-29’, ‘30-39’, ‘40-49’, ‘50-59’, ‘60+’,七個年齡段;分別把性別和年齡段的圖片分別提取出來,并保存到性別和年齡段兩個文件夾下,構(gòu)造如下圖:
5.1 分為年齡、性別
5.2 性別分為兩類
5.3性別訓練代碼
# ----------------------------------------------------------------------------------------------------------------------
# 導入一些第三方包
# ----------------------------------------------------------------------------------------------------------------------
import tensorflow as tf
from nets import net
EPOCHS = 40
BATCH_SIZE = 32
image_height = 128
image_width = 128
model_dir = "./models/age.h5"
train_dir = "./data/age/train/"
test_dir = "./data/age/test/"
def get_datasets():
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1.0 / 255.0
)
train_generator = train_datagen.flow_from_directory(train_dir,
target_size=(image_height, image_width),
color_mode="rgb",
batch_size=BATCH_SIZE,
shuffle=True,
class_mode="categorical")
test_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1.0 /255.0
)
test_generator = test_datagen.flow_from_directory(test_dir,
target_size=(image_height, image_width),
color_mode="rgb",
batch_size=BATCH_SIZE,
shuffle=True,
class_mode="categorical"
)
train_num = train_generator.samples
test_num = test_generator.samples
return train_generator, test_generator, train_num, test_num
# ----------------------------------------------------------------------------------------------------------------------
# 網(wǎng)絡的初始化 --- net.CNN(num_classes=7)
# model.compile --- 對神經(jīng)網(wǎng)絡訓練參數(shù)是設置 --- tf.keras.losses.categorical_crossentropy --- 損失函數(shù)(交叉熵)
# tf.keras.optimizers.Adam(learning_rate=0.001) --- 優(yōu)化器的選擇,以及學習率的設置
# metrics=['accuracy'] --- List of metrics to be evaluated by the model during training and testing
# return model --- 返回初始化之后的模型
# ----------------------------------------------------------------------------------------------------------------------
def get_model():
model = net.CNN(num_classes=7)
model.compile(loss=tf.keras.losses.categorical_crossentropy,
optimizer=tf.keras.optimizers.Adam(lr=0.001),
metrics=['accuracy'])
return model
if __name__ == '__main__':
train_generator, test_generator, train_num, test_num = get_datasets()
model = get_model()
model.summary()
tensorboard = tf.keras.callbacks.TensorBoard(log_dir='./log/age/')
callback_list = [tensorboard]
model.fit_generator(train_generator,
epochs=EPOCHS,
steps_per_epoch=train_num // BATCH_SIZE,
validation_data=test_generator,
validation_steps=test_num // BATCH_SIZE,
callbacks=callback_list)
model.save(model_dir)
# ----------------------------------------------------------------------------------------------------------------------
5.4 年齡分為七個年齡段
文章來源:http://www.zghlxwxcb.cn/news/detail-774635.html
5.5 年齡訓練代碼
# ----------------------------------------------------------------------------------------------------------------------
# 導入一些第三方包
# ----------------------------------------------------------------------------------------------------------------------
import tensorflow as tf
from nets import net
EPOCHS = 20
BATCH_SIZE = 32
image_height = 128
image_width = 128
model_dir = "./models/gender.h5"
train_dir = "./data/gender/train/"
test_dir = "./data/gender/test/"
def get_datasets():
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1.0 / 255.0
)
train_generator = train_datagen.flow_from_directory(train_dir,
target_size=(image_height, image_width),
color_mode="rgb",
batch_size=BATCH_SIZE,
shuffle=True,
class_mode="categorical")
test_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1.0 /255.0
)
test_generator = test_datagen.flow_from_directory(test_dir,
target_size=(image_height, image_width),
color_mode="rgb",
batch_size=BATCH_SIZE,
shuffle=True,
class_mode="categorical"
)
train_num = train_generator.samples
test_num = test_generator.samples
return train_generator, test_generator, train_num, test_num
def get_model():
model = net.CNN(num_classes=2)
model.compile(loss=tf.keras.losses.categorical_crossentropy,
optimizer=tf.keras.optimizers.Adam(lr=0.001),
metrics=['accuracy'])
return model
if __name__ == '__main__':
train_generator, test_generator, train_num, test_num = get_datasets()
model = get_model()
model.summary()
tensorboard = tf.keras.callbacks.TensorBoard(log_dir='./log/gender/')
callback_list = [tensorboard]
model.fit_generator(train_generator,
epochs=EPOCHS,
steps_per_epoch=train_num // BATCH_SIZE,
validation_data=test_generator,
validation_steps=test_num // BATCH_SIZE,
callbacks=callback_list)
model.save(model_dir)
# ----------------------------------------------------------------------------------------------------------------------
6 模型驗證預測
6.1 實現(xiàn)效果
文章來源地址http://www.zghlxwxcb.cn/news/detail-774635.html
6.2 關(guān)鍵代碼
# ----------------------------------------------------------------------------------------------------------------------
# 加載基本的庫
# ----------------------------------------------------------------------------------------------------------------------
import tensorflow as tf
from PIL import Image
import numpy as np
import cv2
import os
# ----------------------------------------------------------------------------------------------------------------------
# tf.keras.models.load_model('./model/age.h5') --- 加載年齡模型
# tf.keras.models.load_model('./model/gender.h5') --- 加載性別模型
# ----------------------------------------------------------------------------------------------------------------------
model_age = tf.keras.models.load_model('./models/age.h5')
model_gender = tf.keras.models.load_model('./models/gender.h5')
# ----------------------------------------------------------------------------------------------------------------------
# 類別名稱
# ----------------------------------------------------------------------------------------------------------------------
classes_age = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60+']
classes_gender = ['female', 'male']
# ----------------------------------------------------------------------------------------------------------------------
# cv2.dnn.readNetFromCaffe --- 加載人臉檢測模型
# ----------------------------------------------------------------------------------------------------------------------
net = cv2.dnn.readNetFromCaffe('./models/deploy.prototxt.txt', './models/res10_300x300_ssd_iter_140000.caffemodel')
# ----------------------------------------------------------------------------------------------------------------------
# os.listdir('./images/') --- 得到文件夾列表
# ----------------------------------------------------------------------------------------------------------------------
files = os.listdir('./images/')
# ----------------------------------------------------------------------------------------------------------------------
# 遍歷信息
# ----------------------------------------------------------------------------------------------------------------------
for file in files:
# ------------------------------------------------------------------------------------------------------------------
# image_path = './images/' + file --- 拼接得到圖片文件路徑
# cv2.imread(image_path) --- 使用opencv讀取圖片
# ------------------------------------------------------------------------------------------------------------------
image_path = './images/' + file
print(image_path)
image = cv2.imread(image_path)
# ------------------------------------------------------------------------------------------------------------------
# (h, w) = image.shape[:2] --- 得到圖像的高度和寬度
# cv2.dnn.blobFromImage --- 以DNN的方式加載圖像
# net.setInput(blob) -- 設置網(wǎng)絡的輸入
# detections = net.forward() --- 網(wǎng)絡前相傳播過程
# ------------------------------------------------------------------------------------------------------------------
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
# ------------------------------------------------------------------------------------------------------------------
# for i in range(0, detections.shape[2]): --- 遍歷檢測結(jié)果
# ------------------------------------------------------------------------------------------------------------------
for i in range(0, detections.shape[2]):
# --------------------------------------------------------------------------------------------------------------
# confidence = detections[0, 0, i, 2] 得到檢測的準確率
# --------------------------------------------------------------------------------------------------------------
confidence = detections[0, 0, i, 2]
# --------------------------------------------------------------------------------------------------------------
# if confidence > 0.85: --- 對置信度的判斷
# --------------------------------------------------------------------------------------------------------------
if confidence > 0.85:
# ----------------------------------------------------------------------------------------------------------
# detections[0, 0, i, 3:7] * np.array([w, h, w, h]) --- 得到檢測框的信息
# (startX, startY, endX, endY) = box.astype("int") --- 將信息分解成左上角的x,y,以及右下角的x,y
# cv2.rectangle --- 將人臉框起來
# ----------------------------------------------------------------------------------------------------------
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 1)
# ----------------------------------------------------------------------------------------------------------
# 提取人臉部分區(qū)域
# ----------------------------------------------------------------------------------------------------------
roi = image[startY-15:endY+15, startX-15:endX+15]
# ----------------------------------------------------------------------------------------------------------
# Image.fromarray(cv2.cvtColor(roi, cv2.COLOR_BGR2RGB)) --- 將opencv專程PIL格式的數(shù)據(jù)
# img.resize((128, 128)) --- 改變圖像的大小
# np.array(img).reshape(-1, 128, 128, 3).astype('float32') / 255 --- 改變數(shù)據(jù)的形狀,以及歸一化處理
# ----------------------------------------------------------------------------------------------------------
img = Image.fromarray(cv2.cvtColor(roi, cv2.COLOR_BGR2RGB))
img = img.resize((128, 128))
img = np.array(img).reshape(-1, 128, 128, 3).astype('float32') / 255
# ----------------------------------------------------------------------------------------------------------
# 調(diào)用年齡識別模型得到檢測結(jié)果
# ----------------------------------------------------------------------------------------------------------
prediction_age = model_age.predict(img)
final_prediction_age = [result.argmax() for result in prediction_age][0]
# ----------------------------------------------------------------------------------------------------------
# 調(diào)用性別識別模型得到檢測結(jié)果
# ----------------------------------------------------------------------------------------------------------
prediction_gender = model_gender.predict(img)
final_prediction_gender = [result.argmax() for result in prediction_gender][0]
# ----------------------------------------------------------------------------------------------------------
# 將識別的信息拼接,然后使用cv2.putText顯示
# ----------------------------------------------------------------------------------------------------------
res = classes_gender[final_prediction_gender] + ' ' + classes_age[final_prediction_age]
y = startY - 10 if startY - 10 > 10 else startY + 10
cv2.putText(image, str(res), (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)
# ------------------------------------------------------------------------------------------------------------------
# 顯示
# ------------------------------------------------------------------------------------------------------------------
cv2.imshow('', image)
if cv2.waitKey(0) & 0xFF == ord('q'):
break
7 最后
到了這里,關(guān)于深度學習畢設項目 深度學習 python opencv 實現(xiàn)人臉年齡性別識別的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!