基於卷積神經網路和tensorflow實現的人臉識別
首先貼一下原文地址:http://tumumu.cn/2017/05/02/deep-learning-face/
以前在學習卷積神經網路的時候,發現了很多很有趣的demo,有一次發現了上面這個人臉識別的例子,不過當時還看不懂,經過一段時間之後決定試試能不能將上面的例子改一下,調以調參什麼的,於是就有了這篇文章。本以為我的程式碼和原文沒有什麼太大的區別,應該不會出現什麼錯誤,但是實際自己上手之後才會發現很多的問題。具體的程式安裝,我這裡就不再贅述了,大家可以參考原文,講的很詳細。下面我把我的程式碼貼出來。和原來的程式碼沒有相差很多,就是改了一下中間的卷積層。自己實際操作還是學到了很多東西的。和原文相比,收集人臉和處理其他人臉的程式碼我都沒有做太大的改變,只是去掉了原文程式碼中修改圖片亮度和對比度的部分,所以我收集的圖片都是一樣的亮度和一樣的對比度,這裡就不貼這兩部分的程式碼了。這裡直接貼訓練部分的程式碼和最後使用模型的程式碼。
import tensorflow as tf
import cv2
import numpy as np
import os
import random
import sys
from sklearn.model_selection import train_test_split
my_faces_path = './gray_my_faces'
other_faces_path = './other_faces'
#圖片的大小採集的64*64
size = 64
imgs = []
labs = []#定義兩個陣列用來存放圖片和標籤
#這裡是得到圖片的大小,進行統一處理,將圖片改成統一大小
def getPaddingSize(img):
h,w,_ = img.shape#獲得圖片的寬和高還有深度
top,bottom,left,right = (0,0,0,0)
longest = max(h,w)
if w < longest:
tmp = longest - w
left = tmp // 2
right = tmp - left
elif h < longest:
tmp = longest - h
top = tmp // 2
bottom = tmp - top
else:
pass
return top,bottom,left,right
def readData(path,h=size,w=size):
for filename in os.listdir(path):
if filename.endswith('.jpg'):
filename = path + '/' + filename
img = cv2.imread(filename)
top,bottom,left,right = getPaddingSize(img)
#將圖片放大,擴充圖片邊緣部分,這裡不是很理解為什麼要擴充邊緣部分
#可能是為了實現像padding的作用
img = cv2.copyMakeBorder(img,top,bottom,left,right,cv2.BORDER_CONSTANT,value=[0,0,0])
img = cv2.resize(img,(h,w))
# 將對應的圖片和標籤存進陣列裡面
imgs.append(img)
labs.append(path)
readData(my_faces_path)
readData(other_faces_path)
#將圖片陣列與標籤轉換成陣列,並給圖片做上標籤
imgs = np.array(imgs)
labs = np.array([[0,1] if lab == my_faces_path else [1,0] for lab in labs])
#隨機劃分測試集和訓練集,規定測試集的大小,這裡是可以自己調的
train_x,test_x,train_y,test_y = train_test_split(imgs,labs,test_size=0.05,random_state=random.randint(0,100))
#引數:圖片資料的總數,圖片的高、寬、通道
train_x = train_x.reshape(train_x.shape[0], size, size,3)
test_x = test_x.reshape(test_x.shape[0], size, size, 3)
#將資料轉換為小於1的數
train_x = train_x.astype('float32') / 255.0
test_x = test_x.astype('float32') / 255.0
#輸出一下獲取的訓練圖片和測試圖片的長度,也就是大小
print('train size:%s,test size:%s' % (len(train_x),len(test_x)))
#圖片塊,每次取100張圖片
batch_size = 100
#計算有多少個batch
num_batch = (len(train_x)) // batch_size
input = tf.placeholder(tf.float32,[None,size,size,3])
output = tf.placeholder(tf.float32,[None,2])
#這裡將input在進行處理一下
images = tf.reshape(input,[-1,size,size,3])
keep_prob_5 = tf.placeholder(tf.float32)
keep_prob_75 = tf.placeholder(tf.float32)
#下面開始進行卷積層的處理
#第一層卷積,首先輸入的圖片大小是64*64
def cnnlayer():
conv1 = tf.layers.conv2d(inputs=images,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#輸出大小是(64*64*32)
#第一層池化
pool1 = tf.layers.max_pooling2d(inputs=conv1,
pool_size=[2,2],
strides=2)#輸出大小是(32*32*32)
#第二層卷積
conv2 = tf.layers.conv2d(inputs=pool1,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#輸出大小是(32*32*32)
#第二層池化
pool2 = tf.layers.max_pooling2d(inputs=conv2,
pool_size=[2,2],
strides=2)#輸出大小是(16*16*32)
#第三層卷積
conv3 = tf.layers.conv2d(inputs=pool2,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#(變成16*16*32)
#第三層池化
pool3 = tf.layers.max_pooling2d(inputs=conv3,
pool_size=[2,2],
strides=2)#輸出大小是(8*8*32)
#第四層卷積
conv4 = tf.layers.conv2d(inputs=pool3,
filters=64,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#輸出大小是(變成8*8*64)
# pool3 = tf.layers.max_pooling2d(inputs=conv4,
# pool_size=[2,2],
# strides=2)#輸出大小是(變成4*4*64)
#卷積網路在計算每一層的網路個數的時候要細心一些,不然容易出錯
#要注意下一層的輸入是上一層的輸出
#平坦化
flat = tf.reshape(conv4,[-1,8*8*64])
#經過全連線層
dense = tf.layers.dense(inputs=flat,
units=4096,
activation=tf.nn.relu)
#drop_out處理
drop_out = tf.layers.dropout(inputs=dense,rate=0.5)
#輸出層
logits = tf.layers.dense(drop_out,units=2)
return logits
# yield logits
def cnntrain():
logits = cnnlayer()
# logits = next(cnnlayer())
#交叉熵損失函式
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=output))
#將訓練優化方法改成GradientDescentOptimizer發現並沒有加快收斂所以又改回AdamOptimizer
#train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
train_step = tf.train.AdamOptimizer(0.01).minimize(cross_entropy)
# 比較標籤是否相等,再求的所有數的平均值,tf.cast(強制轉換型別)
accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits,1),tf.argmax(output,1)),tf.float32))
#將loss與accuracy儲存以供tensorboard使用
tf.summary.scalar('loss',cross_entropy)
tf.summary.scalar('accuracy',accuracy)
#合併所有的Op為一個Op
merged_summary_op = tf.summary.merge_all()
#資料儲存器的初始化
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
#把summary Op返回的資料寫到磁碟裡
summary_writer = tf.summary.FileWriter('./tmp',graph=tf.get_default_graph())
for n in range(10):
#每次取100(batch_size)張圖片
for i in range(num_batch):
batch_x = train_x[i*batch_size : (i + 1) * batch_size]
batch_y = train_y[i*batch_size : (i + 1) * batch_size]
#開始訓練資料,同時訓練三個變數,返回三個資料,
_,loss,summary = sess.run([train_step,cross_entropy,merged_summary_op],
feed_dict={input: batch_x, output: batch_y})
summary_writer.add_summary(summary, n * num_batch + i)
# 列印損失
print(n * num_batch + i, loss)
if (n * num_batch + i) % 100 == 0:
# 獲取測試資料的準確率
acc = accuracy.eval({input: test_x, output: test_y,keep_prob_5:1.0,keep_prob_75:1.0})
print("第%f個batch,準確率%f" % (n*num_batch+i, acc))
# 準確率大於0.98時儲存並退出
if acc > 0.98 and n > 2:
saver.save(sess, './train_faces.model', global_step=n * num_batch + i)
sys.exit(0)
print('accuracy less 0.98, exited!')
cnntrain()
再加上最後使用模型的程式碼。
import tensorflow as tf
import cv2
import numpy as np
import os
import random
import sys
from sklearn.model_selection import train_test_split
import dlib
my_faces_path = './my_faces'
other_faces_path = './other_faces'
#將得到的自己的圖片和其他圖片進行處理
size = 64
imgs = []
labs = []#定義兩個陣列用來存放圖片和標籤
def getPaddingSize(img):
h,w,_ = img.shape#獲得圖片的寬和高還有深度
top,bottom,left,right = (0,0,0,0)
longest = max(h,w)
if w < longest:
tmp = longest - w
left = tmp // 2
right = tmp - left
elif h < longest:
tmp = longest - h
top = tmp // 2
bottom = tmp - top
else:
pass
return top,bottom,left,right
def readData(path,h=size,w=size):
for filename in os.listdir(path):
if filename.endswith('.jpg'):
filename = path + '/' + filename
img = cv2.imread(filename)
top,bottom,left,right = getPaddingSize(img)
#將圖片放大,擴充圖片邊緣部分,這裡不是很理解為什麼要擴充邊緣部分
img = cv2.copyMakeBorder(img,top,bottom,left,right,cv2.BORDER_CONSTANT,value=[0,0,0])
img = cv2.resize(img,(h,w))
imgs.append(img)
labs.append(path)#將對應的圖片和標籤存進陣列裡面
readData(my_faces_path)
readData(other_faces_path)
#將圖片陣列與標籤轉換成陣列
imgs = np.array(imgs)
labs = np.array([[0,1] if lab == my_faces_path else [1,0] for lab in labs])
#隨機劃分測試集和訓練集
train_x,test_x,train_y,test_y = train_test_split(imgs,labs,test_size=0.05,random_state=random.randint(0,100))
#引數:圖片資料的總數,圖片的高、寬、通道
train_x = train_x.reshape(train_x.shape[0], size, size,3)
test_x = test_x.reshape(test_x.shape[0], size, size, 3)
#將資料轉換為小於1的數,二值化使處理變得更簡單
train_x = train_x.astype('float32') / 255.0
test_x = test_x.astype('float32') / 255.0
#獲取訓練圖片和測試圖片的長度,也就是大小
print('train size:%s,test size:%s' % (len(train_x),len(test_x)))
#圖片塊,每次取100張圖片
batch_size = 100
num_batch = (len(train_x)) // batch_size#計算總共多少輪
input = tf.placeholder(tf.float32,[None,size,size,3])
output = tf.placeholder(tf.float32,[None,2])#輸出加兩個,true or false
#這裡注意的是tf.reshape不是np.reshape
# images = tf.reshape(input,[-1,size,size,3])
keep_prob_5 = tf.placeholder(tf.float32)
keep_prob_75 = tf.placeholder(tf.float32)
#下面開始進行卷積層的處理
#第一層卷積,首先輸入的圖片大小是64*64
def cnnlayer():
#第一層卷積
conv1 = tf.layers.conv2d(inputs=input,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#(64*64*32)
#第一層池化
pool1 = tf.layers.max_pooling2d(inputs=conv1,
pool_size=[2,2],
strides=2)#(32*32*32)
#第二層卷積
conv2 = tf.layers.conv2d(inputs=pool1,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#(32*32*32)
#第二層池化
pool2 = tf.layers.max_pooling2d(inputs=conv2,
pool_size=[2,2],
strides=2)#(16*16*32)
#第三層卷積
conv3 = tf.layers.conv2d(inputs=pool2,
filters=32,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#(變成16*16*32)
#第三層池化
pool3 = tf.layers.max_pooling2d(inputs=conv3,
pool_size=[2,2],
strides=2)#(8*8*32)
#第四層卷積
conv4 = tf.layers.conv2d(inputs=pool3,
filters=64,
kernel_size=[5,5],
strides=1,
padding='same',
activation=tf.nn.relu)#(變成8*8*64)
# pool3 = tf.layers.max_pooling2d(inputs=conv4,
# pool_size=[2,2],
# strides=2)#(變成4*4*6)
#卷積網路在計算每一層的網路個數的時候要細心一些
#卷積層加的padding為same是不會改變卷積層的大小的
#要注意下一層的輸入是上一層的輸出
#平坦化
flat = tf.reshape(conv4,[-1,8*8*64])
#經過全連線層
dense = tf.layers.dense(inputs=flat,
units=4096,
activation=tf.nn.relu)
#drop_out,flat打錯一次
drop_out = tf.layers.dropout(inputs=dense,rate=0.2)
#輸出層
logits = tf.layers.dense(drop_out,units=2)
return logits
# yield logits
out = cnnlayer()
# out = next(cnnlayer())
predict = tf.argmax(out,1)
saver = tf.train.Saver()
sess = tf.Session()
saver.restore(sess,tf.train.latest_checkpoint('.'))
def is_my_face(image):
res = sess.run(predict, feed_dict={input: [image / 255.0]})
if res[0] == 1:
return True
else:
return False
# 使用dlib自帶的frontal_face_detector作為我們的特徵提取器
detector = dlib.get_frontal_face_detector()
cam = cv2.VideoCapture(0)
while True:
_, img = cam.read()
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dets = detector(gray_image, 1)
if not len(dets):
# print('Can`t get face.')
cv2.imshow('img', img)
key = cv2.waitKey(30) & 0xff
if key == 27:
sys.exit(0)
for i, d in enumerate(dets):
x1 = d.top() if d.top() > 0 else 0
y1 = d.bottom() if d.bottom() > 0 else 0
x2 = d.left() if d.left() > 0 else 0
y2 = d.right() if d.right() > 0 else 0
face = img[x1:y1, x2:y2]
# 調整圖片的尺寸
face = cv2.resize(face, (size, size))
print('Is this my face? %s' % is_my_face(face))
cv2.rectangle(img, (x2, x1), (y2, y1), (255, 0, 0), 3)
cv2.imshow('image', img)
key = cv2.waitKey(30) & 0xff
if key == 27:
sys.exit(0)
sess.close()
總結:經過這一次的學習,對卷積神經網路有了更深的理解,在我修改程式碼的時候,雖然只是修改中間的卷積層,但還是出現了很多的問題,感覺自己不是寫的程式碼而是寫的bug。期間被卡住了很久,不過在Stack Overflow的一些大佬幫助下還是解決了問題(雖然我沒有提問,但是上面之前的一些回答幫助了我很多)。總而言之,自己動手擼一遍程式碼還是比只是看看學到的多啊。
相關文章
- 基於卷積神經網路的人臉識別專案_使用Tensorflow-gpu+dilib+sklearn卷積神經網路GPU
- 基於卷積神經網路的人臉表情識別應用--AR川劇變臉(一)卷積神經網路
- 【Pytorch】基於卷積神經網路實現的面部表情識別PyTorch卷積神經網路
- TensorFlow 卷積神經網路之貓狗識別卷積神經網路
- TensorFlow上實現卷積神經網路CNN卷積神經網路CNN
- TensorFlow 卷積神經網路系列案例(1):貓狗識別卷積神經網路
- 基於深度神經網路的人臉識別相關問題神經網路
- 【Tensorflow_DL_Note6】Tensorflow實現卷積神經網路(1)卷積神經網路
- 【Tensorflow_DL_Note7】Tensorflow實現卷積神經網路(2)卷積神經網路
- 用TensorFlow搭建卷積神經網路識別數字0~9卷積神經網路
- TensorFlow實戰卷積神經網路之LeNet卷積神經網路
- Tensorflow-卷積神經網路CNN卷積神經網路CNN
- 【Python】keras卷積神經網路識別mnistPythonKeras卷積神經網路
- 卷積神經網路進行影像識別卷積神經網路
- 使用tensorflow和cnn(卷積神經網路)識別驗證碼並構建APICNN卷積神經網路API
- 基於卷積神經網路的建築圖紙識別研究方向卷積神經網路
- TensorFlow 一步一步實現卷積神經網路卷積神經網路
- 卷積神經網路—基礎知識(1)卷積神經網路
- 卷積神經網路四種卷積型別卷積神經網路型別
- 基於CNN卷積神經網路的MQAM調製識別matlab模擬CNN卷積神經網路MQMatlab
- [譯] 使用 Python 和 Keras 實現卷積神經網路PythonKeras卷積神經網路
- 深度學習基礎-基於Numpy的卷積神經網路(CNN)實現深度學習卷積神經網路CNN
- Keras上實現卷積神經網路CNNKeras卷積神經網路CNN
- 圖卷積神經網路(GCN)理解與tensorflow2.0程式碼實現卷積神經網路GC
- 卷積神經網路卷積神經網路
- 讓卷積神經網路來辨識馬和人卷積神經網路
- 手寫數字圖片識別-卷積神經網路卷積神經網路
- 卷積神經網路的原理及Python實現卷積神經網路Python
- 《卷積神經網路的Python實現》筆記卷積神經網路Python筆記
- 基於PCA和SVM的人臉識別PCA
- 使用Python+TensorFlow2構建基於卷積神經網路(CNN)的ECG心電訊號識別分類(二)Python卷積神經網路CNN
- 使用Python+TensorFlow2構建基於卷積神經網路(CNN)的ECG心電訊號識別分類(三)Python卷積神經網路CNN
- 使用Python+TensorFlow2構建基於卷積神經網路(CNN)的ECG心電訊號識別分類(四)Python卷積神經網路CNN
- 卷積神經網路概述卷積神經網路
- 解密卷積神經網路!解密卷積神經網路
- 5.2.1 卷積神經網路卷積神經網路
- 卷積神經網路CNN卷積神經網路CNN
- 卷積神經網路-AlexNet卷積神經網路