Reconocimiento de 1 rostro de la aplicación de aprendizaje profundo de Keras basado en la red neuronal convolucional (CNN) (abajo)


Aplicación de aprendizaje profundo de Keras Reconocimiento de 1 rostro basado en la red neuronal convolucional (CNN) (Parte 1) . El blog anterior describió en detalle la base teórica de CNN. Este blog describe específicamente el código específico para usar Keras para lograr el reconocimiento facial .

Descarga de código

Dirección de descarga del código fuente de Github:
https://github.com/Kyrie-leon/CNN-FaceRec-keras

Tres, conjunto de datos de reconocimiento facial

La base de datos de rostros de MegaFace es una base de datos de rostros de un millón de niveles publicada y mantenida por la Universidad de Washington, y actualmente es uno de los indicadores de rendimiento de reconocimiento facial más autorizados del mundo. La base de datos de rostros tiene las características de una gran cantidad de datos y aleatoriedad de imágenes. Algunos de los conjuntos de datos faciales tienen un intervalo de edad amplio, lo que aumenta la dificultad de reconocimiento. Para usar esta base de datos de rostros, primero debe enviar una solicitud y luego puede descargar el conjunto de datos después de obtener la cuenta de descarga y la contraseña. Este documento selecciona algunas caras de la base de datos de caras de MegaFace como el conjunto de datos experimentales.
Enlace del sitio web oficial del conjunto de datos faciales MegaFace
: https://pan.baidu.com/s/1aCjxQnKrnGY6hG-Mifdm2g Código de extracción: w5wu
Descargue el
enlace de la imagen del conjunto de entrenamiento facial : https://pan.baidu.com/s/1rQEUk0toOSDYoG-frK4wBg Código de extracción: 73uy descargar imagen del conjunto de prueba facial

3.1 División del conjunto de datos

Este experimento selecciona 6127 imágenes de 40 personas en la base de datos de caras de MegaFace como el conjunto de datos experimentales, incluidas 4742 imágenes en el conjunto de entrenamiento, 1185 imágenes en el conjunto de verificación y 200 imágenes en el conjunto de prueba.

Name_label = [] #姓名标签
path = './data/face/'   #数据集文件路径
dir = os.listdir(path)  #列出所有人
label = 0   #设置计数器

#数据写入
with open('./data/train.txt','w') as f:
    for name in dir:
        Name_label.append(name)
        print(Name_label[label])
        after_generate = os.listdir(path +'\\'+ name)
        for image in after_generate:
            if image.endswith(".png"):
                f.write(image + ";" + str(label)+ "\n")
        label += 1

A través del código anterior, el conjunto de datos experimentales se escribe en el archivo train.txt para realizar la lectura iterativa de los datos, lo que reduce el uso de memoria y mejora la velocidad de entrenamiento.

 # 打开数据集的txt
    with open(r".\data\train.txt","r") as f:
        lines = f.readlines()
    #打乱数据集
    np.random.seed(10101)
    np.random.shuffle(lines)
    np.random.seed(None)
    # 80%用于训练,20%用于测试。
    num_val = int(len(lines)*0.2)   #
    num_train = len(lines) - num_val  #4715

El código anterior se usa para dividir el conjunto de datos y establecer una semilla aleatoria para que el mismo tipo de datos no se concentre demasiado para afectar la precisión del experimento.

3.2 Mejora de datos

Al desenfocar, rotar y agregar ruido a las imágenes faciales del conjunto de entrenamiento original, se crean una variedad de "entornos" complejos y la cantidad de datos se expande sobre la base de los datos originales, mejorando así la precisión del reconocimiento; mediante la simulación de entornos de imágenes deficientes Además de la interferencia, cuanto mayor sea la adaptabilidad de la red neuronal convolucional al reconocimiento facial en diferentes condiciones adversas, el código es el siguiente:

def rand(a=0, b=1):
    return np.random.rand()*(b-a) + a

def get_random_data(image, input_shape, random=True, jitter=.1, hue=.1, sat=1.2, val=1.2, proc_img=True):
    h, w = input_shape

    new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
    scale = rand(.7, 1.3)
    if new_ar < 1:
        nh = int(scale*h)
        nw = int(nh*new_ar)
    else:
        nw = int(scale*w)
        nh = int(nw/new_ar)
    image = image.resize((nw,nh), Image.BICUBIC)


    # place image
    dx = int(rand(0, w-nw))
    dy = int(rand(0, h-nh))
    new_image = Image.new('RGB', (w,h), (0,0,0))
    new_image.paste(image, (dx, dy))
    image = new_image



    # flip image or not
    flip = rand()<.5
    if flip:
        image = image.transpose(Image.FLIP_LEFT_RIGHT)

    # distort image
    hue = rand(-hue, hue)
    sat = rand(1, sat) if rand()<.5 else 1/rand(1, sat)
    val = rand(1, val) if rand()<.5 else 1/rand(1, val)
    x = rgb_to_hsv(np.array(image)/255.)
    x[..., 0] += hue
    x[..., 0][x[..., 0]>1] -= 1
    x[..., 0][x[..., 0]<0] += 1
    x[..., 1] *= sat
    x[..., 2] *= val
    x[x>1] = 1
    x[x<0] = 0
    image_data = hsv_to_rgb(x)*255 # numpy array, 0 to 1

    return image_data

Imagen de efecto:
Inserte la descripción de la imagen aquí

Cuarto, construya un modelo de red de CNN

4.1 Construye un modelo de CNN

El modelo de red neuronal convolucional construido en este artículo se muestra en la figura. El modelo tiene un total de 10 capas, que consta de 1 capa de entrada, 3 capas convolucionales, 3 capas de agrupación máxima, 1 capa aplanar, 1 capa completamente conectada y 1 Consiste en una capa Softmax.
Inserte la descripción de la imagen aquí

Primero, los datos de entrada de la capa de entrada son una matriz de imagen de 200 × 200 × 3, el núcleo de convolución de la primera capa de convolución es 3 × 3 y el tamaño de paso deslizante predeterminado es 1 píxel. Después de que la matriz se somete a la operación de convolución del núcleo de convolución, se forma una matriz de datos de 198 × 198 × 64, y luego la capa de agrupación máxima con un tamaño de 2 × 2 y un paso deslizante predeterminado de 2 se utiliza para el procesamiento de agrupación, y las características se reducen a Datos de matriz de 99 × 99 × 64.

Luego, la salida de datos de matriz de 99 × 99 × 64 por la primera capa de agrupación máxima se utiliza como datos de entrada de la segunda capa convolucional, y pasa a través del segundo núcleo de convolución de tamaño 3 × 3 con un paso deslizante de 1 convolución Después de convolucionar la capa, se obtienen datos de matriz de 97 × 97 × 32, y luego los datos de matriz se agrupan con una capa de agrupación máxima de tamaño 2 × 2 y un tamaño de paso deslizante de 2, y la característica se reduce a 48 × 48 × 32 matriz de características, la matriz de características se pasa a la capa Dropout. La capa de abandono se utiliza para suprimir el sobreajuste del modelo y la probabilidad establecida es del 25%.

En la última capa de la capa convolucional y la capa de agrupación máxima, el proceso de convolución y agrupación es similar a las dos capas anteriores. La matriz de características de 48 × 48 × 32 se convoluciona con el kernel de convolución de tamaño 3 × 3 para obtener Los datos de una matriz de 46 × 46 × 32 se pasan a la capa de agrupación máxima de tamaño 2 × 2 para una operación de agrupación máxima, la característica finalmente se reduce a una matriz de características de 23 × 23 × 3, y la probabilidad de pasar la matriz es del 25% La capa Dropout para actualizar los parámetros.

Una vez que los datos pasan por el proceso de agrupación de convolución mencionado anteriormente, los datos de salida son un vector bidimensional y el modelo debe clasificar los resultados de la operación de convolución, por lo que la matriz bidimensional debe reducirse a una matriz unidimensional, y aquí se usa Faltten. La capa, que hace que los datos de entrada multidimensionales sean unidimensionales, proporciona una transición de la capa convolucional a la capa completamente conectada. En este paso, la matriz de características de 23 × 23 × 32 se "aplana" en un conjunto de matriz unidimensional, que contiene un total de 16.928 valores propios, y estos valores propios se pasan a la capa completamente conectada.

La capa completamente conectada diseñada en este documento contiene 128 neuronas, que conectarán completamente 16928 valores propios con 128 neuronas, y generarán 128 datos característicos después de la activación de la función relu, y luego los pasarán a la capa Dropout con una probabilidad del 50%. Ingrese datos para la capa Softmax.

Finalmente, en este documento, los 128 datos de características de la capa completamente conectada están completamente conectados con el número de etiquetas de clasificación, y la clasificación y el reconocimiento de rostros se realizan a través de la capa Softmax. El código de implementación es el siguiente:

def MmNet(input_shape, output_shape):
    model = Sequential()  # 建立模型
    # 第一层
    model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # 第二层
    model.add(Conv2D(32, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    # 第三层
    model.add(Conv2D(32, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    # 全连接层
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.5))
    # 全连接层
    model.add(Dense(output_shape, activation='softmax'))
    print("-----------模型摘要----------\n")  # 查看模型摘要
    model.summary()

    return model

4.2 Entrenamiento de modelos

Al comienzo del entrenamiento, el método transversal se utiliza para normalizar las imágenes faciales en cada subdirectorio a 200 × 200 píxeles, y las imágenes se convierten en una matriz y se leen en la memoria. El conjunto de datos se divide en conjunto de entrenamiento y Pruebe el conjunto y luego agregue etiquetas de clasificación para el reconocimiento facial al conjunto de entrenamiento y al conjunto de prueba, respectivamente.

A continuación, comience a entrenar el modelo de red neuronal construido. Este artículo selecciona el método de descenso de Adam como optimizador, la tasa de aprendizaje es 0.01 y el método de aceleración de GPU se utiliza para el entrenamiento. Los datos procesados ​​se pasan a la red neuronal de acuerdo con las etiquetas establecidas y se realiza un entrenamiento iterativo. Cada resultado de entrenamiento se evalúa durante cada iteración y el modelo de red entrenado se guarda localmente para que la iteración no se interrumpa. El código de implementación es el siguiente:

#3. 训练模型
def train(model, batch_size):

    model = model   #读取模型
    #定义保存方式,每三代保存一次
    checkpoint_period1 = ModelCheckpoint(
        log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
        monitor='acc',
        save_weights_only=False,
        period=3
    )
    #学习率下降方式,acc三次不下降就下降学习率继续训练
    reduce_lr = ReduceLROnPlateau(
        monitor='val_acc',
        patience=3,
        verbose=1
    )
    #val_loss一直不下降意味模型基本训练完毕,停止训练
    early_stopping = EarlyStopping(
        monitor='val_loss',
        min_delta=0,
        patience=10,
        verbose=1
    )
    #交叉熵
    model.compile(loss = 'categorical_crossentropy',
                  optimizer =Adam(lr=1e-4),
                  metrics=['accuracy'])
    #Tebsorboard可视化
    tb_Tensorboard = TensorBoard(log_dir="./model", histogram_freq=1, write_grads=True)
    
    #开始训练
    history = model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size, True),
            steps_per_epoch=max(1, num_train//batch_size),
            validation_data=generate_arrays_from_file(lines[num_train:], batch_size, False),
            validation_steps=max(1, num_val//batch_size),
            verbose = 1,
            epochs=10,
            initial_epoch=0,
            callbacks=[early_stopping, checkpoint_period1, reduce_lr, tb_Tensorboard])
    return history, model

4.3 Cargar la cara para ser reconocido

El proceso de implementación del código de esta sección es: cargar el modelo de red neuronal entrenado, cargar la imagen de la cara que necesita ser reconocida, reconocer, imprimir el resultado del reconocimiento y mostrar la foto de la cara en la ventana. El título de la ventana es el nombre de la ruta de la imagen. Implementación de código específico

import os
import glob
import h5py
import keras
import numpy as np
from tkinter import *
from tkinter import ttk
from PIL import Image,ImageTk
from keras.models import load_model
from keras.preprocessing.image import load_img, img_to_array
from keras.applications.imagenet_utils import preprocess_input
from keras.models import Model

from Name import *

img_rows = 300 # 高
img_cols = 300 # 宽

def letterbox_image(image, size):
    iw, ih = image.size
    w, h = size
    scale = min(w/iw, h/ih)
    nw = int(iw*scale)
    nh = int(ih*scale)

    image = image.resize((nw,nh), Image.BICUBIC)
    new_image = Image.new('RGB', size, (0,0,0))
    new_image.paste(image, ((w-nw)//2, (h-nh)//2))

    return new_image
def test_accuracy(lines, model):
    t = 0
    n = len(lines)
    i = 0   #计数器
    # 遍历测试集数据
    for i in range(n):
        name = lines[i].split(';')[0]   #人脸图像名字xxx_xxx.png
        label_name = (lines[i].split(';')[1]).strip('\n')   #人脸数字标签0-39
        label_name = int(label_name)
        file_name = str(Name.get(label_name))  #对应人名str
        # 从文件中读取图像
        img = Image.open(r".\data\test" +"\\"+ name)
        img = np.array(letterbox_image(img,[img_rows,img_cols]),dtype = np.float64)
        img = preprocess_input(np.array(img).reshape(-1,img_cols,img_rows,3))
        pre_name = model.predict_classes(img) # 返回预测的标签值
        print(int(pre_name),label_name)
        if int(pre_name) == label_name:
            t+=1
    print(t/n)

def main():
    #获取模型权重h5文件
    model = load_model('./logs/easy1.h5')

    with open('./data/test.txt','r') as f:
        lines = f.readlines()
    for img_location in glob.glob('./data/test/*.png'): # 限制测试图像路径以及图像格式
        img = load_img(img_location)
        img = img_to_array(img)
        #图像处理
        img = preprocess_input(np.array(img).reshape(-1,img_cols,img_rows,3))
        img_name = (img_location.strip("face\\")).rstrip(".png") 
        pre_name = model.predict_classes(img) # 返回预测的标签值
        print(pre_name)

        pre = model.predict(img)

        for i in pre_name:
            for j in pre:
                name = Name.get(i)
                #print(name)
                # if name != "Audrey_Landers":
                acc = np.max(j) * 100
                print("\nPicture name is [%s]\npPredicted as [%s] with [%f%c]\n" %(img_name, name, acc, '%'))
                MainFrame = Tk()
                MainFrame.title(img_name)
                MainFrame.geometry('300x300')
                img = Image.open(img_location)
                img = ImageTk.PhotoImage(img)
                label_img = ttk.Label(MainFrame, image = img)
                label_img.pack()
                MainFrame.mainloop()
 
if __name__ == '__main__':
    main()


Supongo que te gusta

Origin blog.csdn.net/qq_40076022/article/details/109350604
Recomendado
Clasificación