# Machine Learning Face Recognization
## :memo:環境架設
這次的作業我選擇使用虛擬環境,如此可以盡情的測試,而且不用擔心會將自己電腦搞亂或用壞,在開發時啟動專屬的虛擬環境,就不用擔心會干擾到別的專案。
我所採用的是**Anaconda**虛擬環境:
它是免費且開源的,提供快速建置Python資料科學及機器學習環境,可以方便地安裝、更新、解除安裝工具包,而且安裝時能自動安裝相應的依賴包,同時還能使用不同的虛擬環境隔離不同要求的專案,因此對於我這個初心者來說是容易上手的。
## :memo:步驟分析
1. 處理數據
從train.csv及test.csv載入數據
1. 切分數據
將測試數據和訓練數據切分,測試訊練結果否正確
1. 創建模組:
建立卷積神經網路模型
3. 存取模組:
將訓練完的模組存取,以方便後續GUI直接載入使用
1. 結果預測:
評估模組的預測準確性是否可以使用
## :memo:人臉辨識程式碼
```python=
import tensorflow as tf
import csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Flatten, Dense, Dropout, BatchNormalization, Conv2D, MaxPool2D
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing import image
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from keras.utils.np_utils import *
from keras import models
from keras.models import load_model
#讀取csv
data = pd.read_csv('train_label.csv')
X = []
for i in range(data.shape[0]):
path = 'train/trn_img'+data['file_id'][i].astype('str').zfill(5)+'.jpg'
img = image.load_img(path, target_size=(192, 168, 3))
img = image.img_to_array(img)
img = img/255.0
X.append(img)
X = np.array(X)
y = data['label']
y = y.to_numpy()
y = to_categorical(y,41)
#切割數據
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1, test_size = 0.15)
#創建model
model = Sequential()
model.add(Conv2D(16, (3,3), activation='relu', input_shape = X_train[0].shape))
model.add(BatchNormalization())
model.add(MaxPool2D(2,2))
model.add(Dropout(0.3))
model.add(Conv2D(32, (3,3), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(2,2))
model.add(Dropout(0.3))
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(2,2))
model.add(Dropout(0.4))
model.add(Conv2D(128, (3,3), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(2,2))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(41, activation='softmax'))
#編譯驗證訓練集
model.compile(optimizer = 'rmsprop', loss = 'categorical_crossentropy', metrics = ['accuracy'])
model.fit(X_train, y_train, batch_size = 64, epochs = 50, validation_data = (X_test, y_test))
#get loss value檢查model是否正常
#loss, accuracy = model.evaluate(X_test, y_test, batch_size = 128)
#測試print('test ')
#測試print('loss %s\n accuracy %s' % (loss, accuracy))
#將訓練好的model存起來
model.save('./CNN_Model.h5')
testdata = pd.read_csv('test.csv')
Test = []
for i in range(testdata.shape[0]):
path = 'test/tst_img'+testdata['file_id'][i].astype('str').zfill(5)+'.jpg'
img = image.load_img(path, target_size=(192, 168, 3))
img = image.img_to_array(img)
img = img/255.0
Test.append(img)
Test = np.array(Test)
#進行預測
pred = model.predict(Test)
prediction = []
for i in range(len(pred)):
top = np.argmax(pred[i])#取得答案
if top == 40: #自己的照片沒有要放進csv檔中
top = 410711225
else:
prediction.append(top)
#print("Prediction {0} : {1}".format((i+1), top))
#將prediction存進csv檔
file = open('face_410711225.csv', 'w', newline='')
writer = csv.writer(file, delimiter=',')
writer.writerow(['Id', 'Category'])
for i in range(0, len(prediction)):
writer.writerow([i+1,int(prediction[i])])
#測試print("Successful create")
```
## :memo:GUI程式碼
```python=
import tkinter as tk
import tensorflow as tf
import csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tkinter as tk
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Flatten, Dense, Dropout, BatchNormalization, Conv2D, MaxPool2D
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing import image
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from keras.utils.np_utils import *
from keras import models
from keras.models import load_model
from tkinter import ttk
from tkinter import simpledialog as sd
from tkinter import filedialog
from tkinter import *
from PIL import ImageTk, Image
#取得檔案位置
def path():
global Path
Path = filedialog.askopenfilename()
print("Path:{}".format(Path))
img = Image.open(Path)
img = img.resize((192, 168), Image.ANTIALIAS)
img = ImageTk.PhotoImage(img)
panel = Label(window, image=img)
panel.image = img
panel.pack(padx=10,pady=100)
#載入model和圖片進行辨識
def reco():
model = load_model('./CNN_Model.h5')
img = image.load_img(Path, target_size=(192, 168, 3))
img = image.img_to_array(img)
img = img/255.0
Test = []
Test.append(img)
Test = np.array(Test)
pred = model.predict(Test)
for i in range(len(pred)):
top = np.argmax(pred[i])
if(top == 40):
print("Prediction:{0}".format("410711225"))
t = "Prediction:"+str("410711225")
else:
print("Prediction:{0}".format(top))
t = "Prediction:"+str(top)
label= tk.Label(window,text = t).pack()
#建立視窗、設定視窗名稱大小等
window=tk.Tk()
window.title('Face Recognize')
window.geometry('500x500')
window.resizable(0,0)
window.configure(background='grey')
#加入按鈕(選擇要辨識的圖片、進行預測)
ttk.Button(window, text="Select Image", command=path).pack(side=tk.BOTTOM)
ttk.Button(window, text="Predict", command=reco).pack(side=tk.BOTTOM)
#不斷執行視窗程式
window.mainloop()
```
## :memo:執行成果
:point_down: (圖一)成功創建csv檔
> 
:point_down: (圖二)測試model準確率
>
:point_down: (圖三)成功預測自己的照片
>
:point_down: (圖四)加入GUI執行成果
>
:point_down: (圖五)選擇圖片成功預測人像
>
:point_down: (影片)GUI程式介面執行成果
> <iframe src="https://drive.google.com/file/d/1YvhHayC1T0a-xvH8UfFg6QBuBllhvRq0/preview" width="640" height="320"></iframe>
## :memo:心得分享
這份人臉辨識作業可以說是到目前為止進資工系接觸過最難的,在撰寫程式時常常會遇到"**不知道現在在寫什麼**"的情況,所以我學會畫在紙上一步一步的切分工作,就如同上述提到的步驟分析,把大框架列出來,在一步步細分內容,有助於更清楚了解整個程式架構。
一個學期要過了,但我仍然對於python語法相當不熟悉,在寫這份作業時真的是困難重重,常常出現語法錯誤,逐字逐句地上網找資料還是糾正不出來,還好同學大力相助修改語法才稍稍有進展。
臉部辨識的model試了好多次,不管是層數還是參數調整等等,都耗費了相當大的心思與力氣,除了程式外,訓練的過程真的是相當艱辛,由於我的電腦效能沒那麼好,訓練50次整整耗費了近一個小時的時間結果也沒有訓練出來,後來修改後又將訓練次數調整成20次,卻發現準確度太低只有30%左右,但訓練過程實在太費時無聊,後來只好借用同學的電腦訓練50次,成果相當不錯,只耗時5分鐘不到,並且準確率也來到0.96(如圖二)。
處理完臉部辨識,但距離截止日期還有一些時間,於是就來試試GUI怎麼寫,畢竟可視覺化的視窗還是比較平易近人。完全沒有接觸這個東西的我就上網找了找資料看看怎麼做,我就找了個簡易的GUI來修改成我要的介面,調整了一下視窗顏色和按鈕的位置,如圖四所示。
最後我選擇加入了Jolin的照片做測試,我從google上找了10照片放入train資料夾中做為訓練集,並從這10張照片中放一張至test做為測試用,並在train.csv中加入這10張照片的labal"40",最後的成果如圖五所示,成功載入圖片並正確辨識出我的學號。