Sử dụng CNN trong bài toán nhận dạng mặt người ( Phần 2 )

Ở phần trước mình đã giới thiệu qua về thuật toán CNN, phần này hãy cùng áp dụng nó vào bài toán nhận dạng mặt người.

Cài đặt môi trường

Để thực hiện, mọi người cần cài đặt môi trường như sau:

Chuẩn bị dataset và tạo tập train + test

Về cơ bản, chúng ta sẽ chia tập dữ liệu thành 2 tệp, 1 tệp gồm các ảnh có xuất hiện mặt người, tệp còn lại bao gồm các ảnh không có mặt người. Bạn có thể tham khảo dataset có chứa mặt người tại đây: https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge/data Sau khi đã chuẩn bị xong dataset, tiến hành tạo tập train + test:

import tensorflow as tf
import cv2,os
import numpy as np
from sklearn import preprocessing
from sklearn.model_selection import train_test_split

n_classes=2
path_pos='data/Face/Positive' # tập dữ liệu chứa mặt người 
path_neg='data/Face/Negative' # tập dữ liệu không chứa mặt người

def read_data(path,label):
    images = []
    labels = []
    dirs = os.listdir( path )
    for files in dirs:
        file_name=path+"/"+files
        image = cv2.imread(file_name,0)
        image=np.reshape(image, 40*100)
        images.append(image)
        labels.append(label)  
    return images, labels

images_pos,labels_pos=read_data(path_pos,1)
images_neg,labels_neg=read_data(path_neg,0)

images=images_pos+images_neg
labels=labels_pos+labels_neg

x_train, x_test,y_train,y_test = train_test_split(images, labels,test_size=0.1, random_state=41)

x_train=np.asarray(x_train)
y_train=np.asarray(y_train)

Thiết lập mạng CNN

Thông thường, một CNN gồm một stack các convolutional module, mỗi một module thực hiện việc extract feature. Mỗi module cũng bao gồm một convolutional layer theo sau là một pooling layer. Module convolutional cuối cùng bao gồm một hoặc nhiều các dense layer thực hiện việc phân lớp. Layer dense cuối cùng trong một CNN bao gồm một single node cho mỗi một lớp cụ thể trong model (tất cả các class khả thi mà model có thể dự đoán được). Với mỗi một node, ta sử dụng hàm kích hoạt softmax để generate ra giá trị predict (từ 0 - 1). Cụ thể như sau:

def conv_net(x):
    x = tf.reshape(x, shape=[-1, 28, 28, 1]) # input layer, image size input có kích thước 28x28
    conv1 = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu,padding="SAME") # convolutional layer 1 
    conv1 = tf.layers.max_pooling2d(conv1, 2, 2,padding="SAME") # pooling layer 1
    conv2 = tf.layers.conv2d(conv1, 64, 5, activation=tf.nn.relu,padding="SAME") # convolutional layer 2
    conv2 = tf.layers.max_pooling2d(conv2, 2, 2,padding="SAME") # pooling layer 2
    
    # tạo dense layer
    fc1 = tf.contrib.layers.flatten(conv2)
    fc1 = tf.layers.dense(fc1, 512,activation=tf.nn.relu)
    out = tf.layers.dense(fc1, num_classes,name="output")
    
    return out

Như vậy, ta đã tạo được một hàm chung cho việc xây dựng mạng CNN. Tiếp theo, ta sẽ optimize mạng CNN bằng Adam optimizer:

Tìm correct và accuracy để đánh giá độ chính xác của mạng CNN.

x = tf.placeholder(tf.float32, [None, n_input],name="x")
y = tf.placeholder(tf.int32, [None],name="y")
pred = conv_net(x)

xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pred, labels=y)
cost = tf.reduce_mean(xentropy)

optimizer = tf.train.AdamOptimizer()
training_op=optimizer.minimize(cost)

correct = tf.nn.in_top_k(pred, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
init = tf.global_variables_initializer()

Thực hiện optimize

# Parameters
learning_rate = 0.001
batch_size = 20
display_step = 10
num_steps=200
# Network Parameters
n_input = 4000 
num_classes=2

def random_batch(x_train, y_train, batch_size):
    rnd_indices = np.random.randint(0, len(x_train), batch_size)
    x_batch = x_train[rnd_indices]
    y_batch = y_train[rnd_indices]
    return x_batch, y_batch


saver = tf.train.Saver()
sess= tf.Session() 
sess.run(init)
for step in range(1, num_steps+1):
    batch_x, batch_y = random_batch(x_train, y_train, batch_size)
    sess.run(training_op, feed_dict={x: batch_x, y: batch_y})
    if step % display_step == 0 or step == 1:
        acc = sess.run( accuracy, feed_dict={x: x_train,y: y_train})
        print('Step:',step, ', Accuracy:',acc)

print("Optimization Finished!")

Kết quả sau khi optimize:

  • Step: 1 , Accuracy: 0.525926
  • Step: 10 , Accuracy: 0.898413
  • Step: 20 , Accuracy: 0.660317
  • Step: 30 , Accuracy: 0.857143
  • Step: 40 , Accuracy: 0.928042
  • Step: 50 , Accuracy: 0.967196
  • Step: 60 , Accuracy: 0.982011
  • Step: 70 , Accuracy: 0.98836
  • Step: 80 , Accuracy: 0.991534
  • Step: 90 , Accuracy: 0.991534
  • Step: 100 , Accuracy: 0.990476
  • Step: 110 , Accuracy: 0.991534
  • Step: 120 , Accuracy: 0.990476
  • Step: 130 , Accuracy: 0.996825
  • Step: 140 , Accuracy: 0.997884
  • Step: 150 , Accuracy: 1.0
  • Step: 160 , Accuracy: 0.998942
  • Step: 170 , Accuracy: 0.997884
  • Step: 180 , Accuracy: 0.998942
  • Step: 190 , Accuracy: 1.0
  • Step: 200 , Accuracy: 1.0
  • Optimization Finished!

Vì mình thực hiện demo optimize nên để các param thấp nên optimize đạt kết quả cao, trong thực tế, lượng data lớn đòi hỏi batch_size , step rất lớn 🤔

Test model vừa train

from skimage.transform import pyramid_gaussian
from skimage.io import imread
from skimage.feature import hog
from sklearn.externals import joblib 
import cv2
import matplotlib.pyplot as plt
from mns import nms,sliding_window
import numpy as np
from sklearn import preprocessing
%matplotlib inline

path="data/Face/Test/3.png" # đường dẫn ảnh muốn test

im1=cv2.imread(path)
im = imread(path, as_grey=False)

scale = 0
downscale=1.25
min_wdw_sz = (384, 256) # window size 
step_size = (10, 10)

detections = []
for im_scaled in pyramid_gaussian(im, downscale=downscale):
    cd = []
    if im_scaled.shape[0] < min_wdw_sz[1] or im_scaled.shape[1] < min_wdw_sz[0]:
        break
    for (x, y, im_window) in sliding_window(im_scaled, min_wdw_sz, step_size):
        if im_window.shape[0] != min_wdw_sz[1] or im_window.shape[1] != min_wdw_sz[0]:
            continue
   
        image=np.reshape(im_window, 256*384)

        x_test=[]
        x_test.append(image)
        x_test=np.asarray(x_test)
        y_test=sess.run(index,feed_dict={X: x_test})
        y_conf=sess.run(conf,feed_dict={X: x_test})
        pred=np.asarray(y_test)[0]
        conf_value=y_conf.reshape(-1)[pred]
        if pred == 1:
            print("detection location",x,y)
            detections.append((x, y, conf_value,
                int(min_wdw_sz[0]*(downscale**scale)),
                int(min_wdw_sz[1]*(downscale**scale))))
            cd.append(detections[-1])        
    scale+=1

clone = im1.copy()
k=10000
for (x_tl, y_tl, _, w, h) in detections:
    print(str(k))
    s_file='data/tmp/FalsePos/neg'+str(k)+'.pgm'
    k=k+1
    cv2.rectangle(im1, (x_tl, y_tl), (x_tl+w, y_tl+h), (0, 0, 255), thickness=2)
    img=clone[y_tl:y_tl+h,x_tl:x_tl+w]
    cv2.imwrite(s_file,img)
plt.imshow(cv2.cvtColor(im1, cv2.COLOR_BGR2RGB))

plt.show()

threshold=.3
detections = nms(detections, threshold)
for (x_tl, y_tl, _, w, h) in detections:
    cv2.rectangle(clone, (x_tl, y_tl), (x_tl+w,y_tl+h), (0, 0, 255), thickness=2)
plt.imshow(cv2.cvtColor(clone, cv2.COLOR_BGR2RGB))

plt.show()

Kết

Thay vì cố gắng lập hồ sơ xác minh chính xác khuôn mặt, dự án này là một minh chứng cho khái niệm để chứng minh quá trình đào tạo một mạng lưới hiện có cho một mục tiêu khác. Chúng tôi đã có thể lấy một mô hình được đào tạo trước về bộ dữ liệu liên quan và điều chỉnh nó theo một nhiệm vụ mà chúng tôi chọn. Trong quá trình này, chúng tôi có thể tiết kiệm được hàng tuần hoặc thậm chí hàng tháng trong thời gian phát triển và đào tạo. Chúng ta đã thấy chúng ta có thể giữ lại tất cả các tham số của mỗi lớp, ngoại trừ lớp cuối cùng, tạo ra một lớp đầu ra mới và đào tạo một lớp không đông lạnh duy nhất để đạt được hiệu quả trên khuôn mặt với mô hình được đào tạo ban đầu để phân biệt giữa 1000 đối tượng. Hơn nữa, chúng tôi khám phá thành công khái niệm tăng cường dữ liệu bằng cách chuyển đổi hình ảnh và chúng tôi có thể sử dụng TensorBoard để hiểu đồ thị tính toán (hoặc ít nhất là xem biểu đồ) và để quan sát các đường cong đào tạo đã xác nhận việc sử dụng dữ liệu của chúng tôi. Có nhiều bước bổ sung cho dự án này để cải thiện độ chính xác. Những người có nhiều khả năng nhất có thể có tác động đáng kể là thu thập dữ liệu đào tạo có nhãn hơn hoặc đào tạo nhiều lớp của mạng. Cả hai đều dễ thực hiện nhưng tốn nhiều thời gian. Bây giờ, dự án này phục vụ để xác nhận phương pháp thích ứng cho sự phát triển của CNN.

Quá trình thích ứng này cho thấy một ứng dụng công nghiệp, trong đó một công ty có nhiều khả năng sử dụng một mô hình hiệu suất cao hiện có hơn là bắt đầu từ một slate sạch vì sự phát triển và đào tạo nguồn lực cần thiết cho công việc như vậy. Hơn nữa, học sâu là một lĩnh vực hợp tác, nơi các khám phá mới nhất thiết yếu xây dựng những phát hiện trước đây và các ứng dụng mới cho mạng nơ-ron hiện có phát sinh từ sự chia sẻ. Những ý tưởng tuyệt vời chết chóc một cách độc lập, và chỉ bằng cách cộng tác với các thực thể khác nhau trên khắp các lĩnh vực mà sự đổi mới trên thế giới có thể được phát triển. Trong cách suy nghĩ đó, hãy sử dụng, chia sẻ và điều chỉnh mã này theo bất kỳ cách nào mà bạn thấy phù hợp!