Try   HackMD

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

實作臉部圖片分析器

臉部圖片分類器是透過CNN(卷積神經網絡)作為模型時做出來的模型,以下內容包含幾個檔案:

Face.py Loadmodel.py GUI.py

第一個 Face.py含有完整的程式碼,包含著怎麼輸入Data,怎麼建立模型,和怎麼將結果寫入csv檔案。Loadmodel.py 的部分,包含著從Face.py產生的預訓練模型的導入,不透過訓練就將結果依照預訓練模型產生。而GUI模型,就以視覺化的方式,並且結合Loadmodel.py產生預測結果。

輸入資料分析

本次測試的題目是臉部的分類問題,在這次資料中包含了兩個圖片的資料夾,分別為train 和 test,另外再加上兩個train 和 test的csv檔案。提供我們在輸入測試資料進入程式時,更加方便。
以下為圖片訓練集和測試集截圖:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

以下也提供測試用csv和訓練用csv,特別提到的是csv中的第一欄是用來存圖片的名稱,第二欄是用來存label的值。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

臉部圖片分析器步驟說明

  1. 數據處理:加載數據並把他們分成訓練數據和測試數據
  2. 匯總數據:匯總訓練數據的概率以便後續計算概率和做預測
  3. 建立模型 : 建立一個CNN模型內容(自製神經連接層)
  4. 結果預測: 通過給定的測試數據和匯總的訓練數據做預測
  5. 評估準確性:使用測試數據來評估預測的準確性

程式分析

Face.py

  1. 預先準備,引入模組
import tensorflow as tf
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

import csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
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

  1. 紀錄程式所需要的參數
img_width = 192
img_height = 168
batch = 64
epoch = 50
  1. 讀取訓練檔案
data = pd.read_csv('train_label.csv')

X = []

for i in tqdm(range(data.shape[0])):
  path = 'train/trn_img'+data['file_id'][i].astype('str').zfill(5)+'.jpg'
  img = image.load_img(path, target_size=(img_width, img_height, 3))
  img = image.img_to_array(img)
  img = img/255.0
  X.append(img)

X = np.array(X)
print(X.shape)
print(X)

y = data['label']
y = y.to_numpy()
y=to_categorical(y,40)

print(y.shape)
print(y)
  1. 切割訓練資料和驗證資料(比例為8.5:1.5)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1, test_size = 0.15)

print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
  1. 建立分類器的模型
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(128, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))


model.add(Dense(128, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))

model.add(Dense(40, activation='softmax'))

print(model.summary())
  1. 編譯和訓練模型
model.compile(optimizer='rmsprop', loss = 'categorical_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, batch_size=batch, epochs=epoch, validation_data=(X_test, y_test))
  1. 取得Loss值和模型正確率
# Test
loss, accuracy = model.evaluate(X_test, y_test, batch_size=128)
print('Test:')
print('Loss: %s\nAccuracy: %s' % (loss, accuracy))
  1. 儲存模型和導入模型
model.save('./CNN_Model.h5')
model = load_model('./CNN_Model.h5')
  1. 輸入測試集數據
testdata = pd.read_csv('test.csv')
Test = []

for i in tqdm(range(testdata.shape[0])):
  path = 'test/tst_img'+testdata['file_id'][i].astype('str').zfill(5)+'.jpg'
  img = image.load_img(path, target_size=(img_width, img_height, 3))
  img = image.img_to_array(img)
  img = img/255.0
  Test.append(img)
Test = np.array(Test)
  1. 預測結果
pred = model.predict(Test)
prediction=[]
for i in range(len(pred)):  
  top = np.argmax(pred[i])
  print("Prediction {1}:{0}".format(top,(i+1)))
  prediction.append(top)
  1. 產生kaggle所需要的submisson.csv檔。
def createCsvFile(prediction):
    file = open('submisson.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 summisson.csv")
createCsvFile(prediction)

Loadmodel.py

  1. 預先準備,引入模組
import tensorflow as tf
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

import csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
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
  1. 儲存模型和導入模型
data = pd.read_csv('train_label.csv')
model = load_model('./CNN_Model.h5')
  1. 輸入測試集數據
testdata = pd.read_csv('test.csv')
Test = []

for i in tqdm(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)
  1. 預測結果
pred = model.predict(Test)
for i in range(len(pred)):  
  top = np.argmax(pred[i])
  print("Prediction {1}:{0}".format(top,(i+1)))
  1. 產生kaggle所需要的submisson.csv檔
def createCsvFile(prediction):
    file = open('submisson.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 summisson.csv")
createCsvFile(prediction)

GUI.py

  1. 預先準備,引入模組
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
  1. 瀏覽檔案的位置,添加圖片和檔案位置
def do_askpath():
    global Path
    Path = filedialog.askopenfilename()
    print("Path : {}".format(Path))
    img = Image.open(Path)
    img = img.resize((250, 250), Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img)
    panel = Label(window, image=img)
    panel.image = img
    panel.pack()
    label= tk.Label(window,text = Path).pack()
  1. 簡化loadmodel
def classifier():
    model = load_model('./CNN_ModelwithAaron.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("410721303"))
            Text = "Prediction:"+str("410721303")
        else:
            print("Prediction :{0}".format(top))
            Text = "Prediction:"+str(top)
    label= tk.Label(window,text = Text).pack()
  1. 設定檔案參數
window=tk.Tk()
window.title('Face Classify GUI Program')
window.geometry('500x500')
window.resizable(0,0)
window.configure(background='white')
  1. 添加按鈕
ttk.Button(window, text="Image Path", command=do_askpath).pack()
ttk.Button(window, text="Predict", command=classifier).pack()
  1. 程式執行
window.mainloop()

輸出結果

Face.pt和loadmodel.py結果如下:

Result
GUI.py結果如下:
GUIResult1

GUIResult2

心得分享

我認為這次的作業挺有挑戰性的,無論是一開始對於題目的理解上,還是在實作過程當中,許多新東西都要重新認識。這次我用的模型CNN也是參考網路上的教學,稍作修改出來的產物,參考了許多的資料,最終才一步步成形。在一開始要處理數據時就讓我非常頭疼,一直無法順利將正確的格式匯出,導致我的模型也建立錯誤。多虧了同儕的提醒,才發現要將label欄位的資料,轉換成numpy格式,最後才成功。後來模型順利建立完成之後,又發現辨識率極低,甚至辨識率還有為零的出現,奇特的是模型的正確率卻很高。後來經過很久的檢查,確認訓練次數,模型正確率、loss值等等,發現到我是在最後將預測出來的值,當作index又再度回去data裡面找資料,才發生錯誤,更正後辨識率大大提升。
再來開始實做視覺化程式又是一大挑戰,我這次用的方式是用tkinter建立視窗,透過谷哥大神稍微參透一下語法,就將內容一步一步填上,最後湊出簡單的成果。其中功能包含利用 ”ImagePath”這個按鈕,可以瀏覽電腦中的檔案所在,接著選擇完測試圖片之後,就可以按下”Prediction”按鍵,等待計算完成之後,就可以順利取得預測資料。基本功能都有,但是我認為有時間的話可以再添加”滾輪”功能,或是重新整理頁面的功能,讓我們載入多張照片的過程中,可以看到的範圍較大,也可以提升容錯率。
另外,在加入自己的資料並預測出學號這部分,我沒有另外擷取本人的照片,我就用Obama的照片做自己的資料去做預測,這個添加測資是透過擴增我原本39類的類別,再加上一類,命名為40類這個label,那我再將40這個預測值轉換成我的學號。我沒有將Obama的照片進行裁減,或是變成黑白的照片,我認為程式中reshape的部分就可以將它進行重新設定,達成程式要求,結果也順利的進行。
整題而言,我認為這次的程式,對於我的幫助蠻大的,雖然可能對於其中的原理,不是那麼了解,也因為時間的緊迫,完成度沒有那麼的完美,不然時間在充裕一些,我認為可以完成到更棒的品質。這次也因為GPU的設定沒有完成,所以預測結果的計算稍慢,慢到我認為有點不合格,大概為5秒的時間,如果加上GPU我認為可以達到更棒的效果。總之,這次的作業,收益良多!

kaggle
最後分析一下在kaggle上的檔案,我認為辨識率分數最高僅有75分的原因為,有些圖片是全黑,或是完全無法辨識的,所以分數無法提高至90分,甚至以上,以上圖片也可以看到前幾次的提交紀錄,非常不理想,後來才慢慢提高,透過修改參數等等動作。

相關連結:

Kaggle:
https://www.kaggle.com/c/intro-to-ml-assignment-2
介紹影片:
https://reurl.cc/XkOQAj