太強了,居然能夠根據指紋圖像預測性別!

在進入神經網絡世界以前,讓咱們先談一談指紋?衆所周知,沒有兩我的具備相同的指紋,可是咱們能夠創建一個CNN模型來從指紋圖像中預測性別嗎?讓咱們看看……python

在本文中,咱們將建立一個能夠根據指紋預測性別的卷積神經網絡(CNN)模型算法

 

實現步驟數組

 

• 瞭解數據集微信

• 從新構造數據集(以便使用keras 的Flow_from_directory函數)網絡

• 定義一個簡單的函數提取所需的特定標籤app

• 定義一個簡單的函數讀取圖像、調整圖像大小。dom

• 預處理訓練和測試數據ide

• 從頭開始構建簡單的CNN模型函數

• 訓練和測試模型性能

 

注:

若是你是CNN的新手?查看這篇文章以對它有一個很好的理解:

https://www.freecodecamp.org/news/an-intuitive-guide-to-convolutional-neural-networks-260c2de0a050/

 

•這篇文章假定您具備卷積神經網絡(CNN)的知識。

•該代碼是在kaggle內核中執行的。它提供免費的GPU和RAM,不足之處是空間有限,但您能夠輕鬆刪除不須要的變量。

 

數據集描述

 

來自Kaggle的數據集,包含約55,000張人類指紋圖像

https://www.kaggle.com/ruizgara/socofing

 

關於數據集的介紹:

• 它有兩個主目錄-Real目錄和Altered目錄

• Real目錄包含真實人類指紋(無任何變化)

• Altered目錄包含通過綜合更改的指紋圖像,包括用於遮蓋中央旋轉和Z形切割的三種不一樣級別的更改。

• Altered目錄進一步分爲:Altered_EasyAltered_hardAltered_Medium目錄

• Real圖像的標籤以下所示:「 100__M_Left_thumb_finger.BMP」

 

• Altered圖像的標籤遵循如下格式:「 100__M_Left_thumb_finger_CR.BMP」

 

 

格式化數據集

 

 

若是咱們的數據集如上圖所示那樣構造,咱們可使用keras中的flow_from_directory()函數來加載數據集,這是從目錄加載數據的一種很是簡單的方法,它以目錄名稱做爲類別。

話雖如此,數據中目錄的名稱並非咱們想要的類,所以咱們將沒法使用flow_from_directory函數。

 

 

另外,咱們將不得不更長的路來加載咱們的數據——將圖像轉換爲像素值,同時僅提取咱們須要的標籤「 F」和「 M」。而後咱們才能使用數據進行訓練、驗證和測試。

 

 

請記住,Altered圖像的格式應相似於:

「 100__M_Left_thumb_finger_CR.BMP」

而Real圖像的格式應相似於:

「 100__M_Left_thumb_finger.BMP」

咱們將基於「 M」和「 F」的性別進行分類。

 

第一步:從圖像標籤中提取性別。定義一個簡單的函數來完成此任務



#import necessary librariesimport numpy as npimport pandas as pdimport seaborn as snsimport tensorflow as tfimport osimport cv2import matplotlib.pyplot as plt#Function to extract labels for both real and altered imagesdef extract_label(img_path,train = True): filename, _ = os.path.splitext(os.path.basename(img_path)) subject_id, etc = filename.split('__') #For Altered folder if train: gender, lr, finger, _, _ = etc.split('_') #For Real folder else: gender, lr, finger, _ = etc.split('_')  gender = 0 if gender == 'M' else 1 lr = 0 if lr == 'Left' else 1 if finger == 'thumb': finger = 0 elif finger == 'index': finger = 1 elif finger == 'middle': finger = 2 elif finger == 'ring': finger = 3 elif finger == 'little': finger = 4 return np.array([gender], dtype=np.uint16)

 

有了上面函數就能夠幫助咱們提取標籤。此函數遍歷分配給它的圖像路徑(img_path)內的圖像標籤,拆分圖像標籤以得到F和M,而後將0分配給M,將1分配給F,返回一個0和1的數組(0表明M,1表明F)。將上述函數應用到Real目錄中的圖像,設置train = False,同時對於Altered目錄中的圖像設置train= True。

 

第二步:加載數據。建立另外一個簡單的函數來幫助您

img_size = 96#Function to iterate through all the imagesdef loading_data(path,train): print("loading data from: ",path) data = [] for img in os.listdir(path): try: img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE) img_resize = cv2.resize(img_array, (img_size, img_size)) label = extract_label(os.path.join(path, img),train) data.append([label[0], img_resize ]) except Exception as e: pass data    return data

 

• 首先設定預期的圖像尺寸 img_size = 96。

• 迭代:對路徑(path)中的全部圖像進行操做——讀取圖像並將它們轉換爲灰度圖像(即黑白),而後將這些圖像的像素值數組返回到img_array

• img_resize包含已基於img_size調整大小的數組值。所以全部圖像將具備相同的大小(96x96)。

• 調用extract_labels函數來獲取標籤,label中包含標籤值。

• 全部標籤和調整大小的圖像數組添加到data列表 。

• 使用try, except塊,傳遞異常

 

最後一步:分配各類目錄,在每一個目錄上使用loading_data 函數





Real_path = "../input/socofing/SOCOFing/Real"Easy_path = "../input/socofing/SOCOFing/Altered/Altered-Easy"Medium_path = "../input/socofing/SOCOFing/Altered/Altered-Medium"Hard_path = "../input/socofing/SOCOFing/Altered/Altered-Hard"Easy_data = loading_data(Easy_path, train = True)Medium_data = loading_data(Medium_path, train = True)Hard_data = loading_data(Hard_path, train = True)test = loading_data(Real_path, train = False)data = np.concatenate([Easy_data, Medium_data, Hard_data], axis=0)del Easy_data, Medium_data, Hard_data

 

 

訓練集data: Easy_data包含了loading_data函數做用在Altered_Easy文件夾的結果,Medium_data、Hard_data分別對應了loading_data函數做用於Altered_MediumAltered_hard文件夾的結果,注意函數設置置train = True,將這些結果鏈接(串聯)在一塊兒,以便全部Altered圖像都在單個變量data

測試集testtest包含loading_data函數做用於Real文件夾的結果,須要設定train = False。

 

注意:因爲kaggle內核上的內存有限,不須要的變量將不斷被刪除。Easy_data,Medium_data和Hard_data被刪除以建立空間。

 

數據預處理

 

 

必須先打亂咱們的數據,而後再繼續,這是爲何呢?由於在訓練咱們的模型時,若是神經網絡不斷看到1類型,它將很快假設全部數據1類型。當它看到0時將很難學習,而且使用測試數據進行測試時會表現糟糕。所以須要將數據隨機化(打亂)。

 

(1)隨機化訓練數據data和測試數據test數組。並查看data的格式

import randomrandom.shuffle(data)random.shuffle(test)

 

 

上圖顯示了data 包含的內容。對於第一個數組,標籤值爲0,而後是圖像的像素值數組像素值的範圍是0到255

 

(2)分離圖像數組和標籤

img, labels = [], []for label, feature in data: labels.append(label) img.append(feature)train_data = np.array(img).reshape(-1, img_size, img_size, 1)train_data = train_data / 255.0from keras.utils.np_utils import to_categoricaltrain_labels = to_categorical(labels, num_classes = 2)del data

 

• 使用for循環,將圖像數組和標籤分紅單獨的列表

• img包含圖像數組,labels包含標籤值

• img和 labels是列表

• img中的值在從新調整以前再次轉換爲數組

• 圖像的像素值的範圍是0到255,經過除以255.0,像素值將按比例縮小到0到1,變爲train_data。

• 標籤也從列表轉換爲分類值,咱們有兩個類F和M類,分配給train_labels

 

讓咱們看看處理後的訓練圖像train_data和訓練圖像標籤train_labels最後的樣子

 

 

(3)最後一步,使用訓練、驗證和測試數據集來訓練模型。已經有了訓練和測試數據,咱們仍然須要驗證數據(test),所以咱們可使用來自sklearn庫的train_test_splitfrom或使用keras的validation_split設置驗證數據。

 

總而言之,咱們將在Altered指紋圖像(train_data,train_labels)上訓練和驗證模型而後在Real指紋圖像(test)上測試模型。

 

創建CNN模型

 

 

(1)構建模型網絡結構

 

• 使用tensorflow來構建咱們的模型

• 從頭開始構建一個簡單的CNN模型,在每層都有兩個卷積層以後將經過relu激活函數添加一個max pooling層

• 以後添加一個flatten層、一個隱藏密集層,而後是一個輸出層。

• input_shape = [96,96,1](1是咱們的灰度圖像的結果)

• 類別數量2

 


#Import necessary librariesfrom tensorflow.keras import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flattenfrom tensorflow.keras import layersfrom tensorflow.keras import optimizersmodel = Sequential([ Conv2D(32, 3, padding='same', activation='relu',kernel_initializer='he_uniform', input_shape = [96, 96, 1]), MaxPooling2D(2), Conv2D(32, 3, padding='same', kernel_initializer='he_uniform', activation='relu'), MaxPooling2D(2), Flatten(), Dense(128, kernel_initializer='he_uniform',activation = 'relu'), Dense(2, activation = 'softmax'), ])

 

•  每一個卷積層(Conv2D)包含32個大小爲3(即3 x 3)的過濾器,僅在第一層中設置輸入形狀

•  Max pooling(MaxPooling2D)的池化大小爲2

•  只有一個具備128個神經單元的隱藏層(Dense),激活函數是relu

•  分類:將使用Dense大小爲2(類編號)的輸出層和softmax激活來結束網絡。

 

下圖是「FrançoisChollet(keras的做者)的python深度學習」一書中的圖片,詳細說明了如何選擇正確的最後一層激活和損失函數。

模型結構總結以下:

 

model.compile(optimizer = optimizers.Adam(1e-3), loss = 'categorical_crossentropy', metrics = ['accuracy'])early_stopping_cb = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

 

(2)編譯模型:

使用Adam、學習率爲0.001的優化器,categorical_crossentropy做爲損失函數,準確性爲metrics使用early_stopping_call回調以防止過擬合它會監視「val_loss」,若是10個epoch內「val_loss」沒有增長,中止訓練模型。

 

 

(3)擬合模型

history = model.fit(train_data, train_labels, batch_size = 128, epochs = 30,  validation_split = 0.2, callbacks = [early_stopping_cb], verbose = 1)

訓練模型30個epoch(若是願意,您能夠訓練更長的時間),咱們設定validation_split = 0.2告訴模型將訓練數據的20%用於驗證。

 

 

如上圖所示的圖像代表咱們的模型正在訓練中,它給出了訓練損失和準確度的值,以及每一個時期的驗證損失和準確度的值。咱們成功地訓練了模型,訓練準確度爲99%,val準確度爲98 %。還不錯!

 

(4)繪製訓練和驗證數據的準確性和損失曲線

import pandas as pdimport matplotlib.pyplot as pltpd.DataFrame(history.history).plot(figsize = (8,5))plt.grid(True)plt.gca().set_ylim(0,1)

 

從上圖能夠看出,一切進展順利。在咱們的模型訓練過程當中沒有重大的過擬合,兩條損失曲線都隨着精度的提升而逐漸減少。

 

測試模型

 

訓練完模型後,想在之前未見過的數據上對其進行測試,以查看其性能如何。如前所述,在Real指紋圖像上測試模型咱們已經有了 test數據。

 

 

 

就像咱們對訓練數據所作的同樣,咱們將標籤和圖像陣列分開,整形併除以255.0

 


test_images, test_labels = [], []for label, feature in test: test_images.append(feature) test_labels.append(label) test_images = np.array(test_images).reshape(-1, img_size, img_size, 1)test_images = test_images / 255.0del testtest_labels = to_categorical(test_labels, num_classes = 2)

 

咱們獲得了與訓練數據(train_data,train_labels)相似的結果

 

最後,咱們經過對模型進行測試來評估測試數據,並給出準確性和損失值:

 

model.evaluate(test_images, test_labels)

 

驗證集的準確度爲99.72%,損失值爲0.0126。太好了,您剛剛成功創建了指紋性別分類模型!

 

 

結論

 

總而言之,咱們從頭開始構建一個簡單的CNN,基於指紋圖像來預測性別。咱們提取了特定標籤,將圖像轉換爲數組,預處理了咱們的數據集,還預留了訓練數據供咱們的模型進行訓練。在測試數據上測試了咱們的模型,並達到了99%的準確性。

 

最後說明

 

只要您有足夠的圖像來訓練,使用CNN就能對幾乎全部圖像進行分類只是神經網絡的衆多奇蹟之一。有不少東西須要學習和探索,咱們只是不許備好迎接使人驚奇的事情

 

參考

https://www.kaggle.com/abolarinbukola/fingerprint-gender-classification-cnn

 

流羣

 

歡迎加入公衆號讀者羣一塊兒和同行交流,目前有SLAM、三維視覺、傳感器自動駕駛、計算攝影、檢測、分割、識別、醫學影像、GAN算法競賽等微信羣(之後會逐漸細分),請掃描下面微信號加羣,備註:」暱稱+學校/公司+研究方向「,例如:」張三 + 上海交大 + 視覺SLAM「。請按照格式備註,不然不予經過。添加成功後會根據研究方向邀請進入相關微信羣。請勿在羣內發送廣告,不然會請出羣,謝謝理解~


本文分享自微信公衆號 - 小白學視覺(NoobCV)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索