本文僅為模型應用實戰,而非顏值研究,所得結果僅供娛樂,僅供參考。
方法也僅供參考。
一般而言,數據量越大,結果越接近正常人審美。由於本次數據量較小,故僅為實驗。
使用環境:ubuntu14.04,opencv3.2.0,dlib19.6,python2.7
一、准備工作:
1、下載dlib庫,下載特征提取模型。
該模型的作用是通過卷積神經網絡產生128維的特征向量,用以代表這張臉。網絡輸入參數為人臉landmark的68個特征點shape和整幅圖像。可猜想網絡特征與人臉的68特征點坐標有關,在網絡中進行歸一化並進一步處理,使得提出的特征具有獨立、唯一性。
考慮到人臉的顏值與五官位置,拍照時的表情有關,故本網絡可作為一種方案進行嘗試。
Dlib下載:
本模型原用於人臉識別,原型為CNN_ResNet。殘差網絡是為了減弱在訓練過程中隨着網絡層數增加而帶來的梯度彌散/爆炸的問題。該方法在LFW上進行人臉識別達到99.38%的准確率。
模型名稱:dlib_face_recognition_resnet_model_v1,迭代次數為10000,訓練時用了約300萬的圖片。輸入層的圖片尺寸是150。
下載地址:
提取特征的網絡模型地址:
http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2
landmark 68特征點位置提取模型:
http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2
2、數據准備:准備不同類型的臉部圖像,注意選用顏值不同的照片,該部分具有一定的主觀性,也是對最后評分影響最重要的一個環節,所以數據量應盡可能大,選用的圖像盡可能典型。
我們設置6個分數,分別為:95,90,85,80,70,65
95分人數僅2人,其余分數在15人左右。85人最多,約20人。數據符合正態分布。
二、生成數據庫。
將整理好的圖片分別用文件夾包含好,每一個文件夾為一類顏值分數。在確保能夠檢測到臉的情況下,將每張圖片送入網絡提取特征,同時為其加入標簽,表示顏值所屬類別,為后續測試分類做好准備。
這樣每張圖就都已經生成了其對應的128個值和一個標簽。
三、基於最鄰近匹配的分數估計(類似KNN)
數據形式如下表所示:

新的測試圖片進入網絡同樣得到128個值:

定義兩種衡量接近度的尺度(方式):
(1)歐氏距離:

(2)基於線性組合系數的接近度表示:
我們將表1的數據矩陣進行轉置,得到如下表所示的矩陣:

將以上矩陣設為A,測試圖片所形成的特征列向量為b。

A為128*n維,x為n維,b為128維。
則求得的x為b向量在A向量中每個列向量所具有的分量。即把測試圖片的特征看作原有數據集中每個圖片特征的線性組合。其系數越大的,則我們認為該系數所對應的數據庫中的圖片越接近測試圖片。
分別找到歐式距離最近的3個、線性組合中系數最大的三個,將這三個分別進行加權處理。
對歐式距離最接近的三張,我們找到對應的原數據(分數值),我們暫認為三者概率近似,以1:1:1的形式加權求和(這三張中可能有多張屬於同一顏值類別)。
對於使用線性組合方法的,取到這三張對應的而后使用權重的方法。
最后將2種方法結合,我們認為第二種方案更可信,以0.6權重加權,第一種方案,以0.4權重加權。
取歐式距離的前5張,進行類別投票以檢驗分數,若投票結果類別對應的分數值與之前求得分數相差較大,則將本次投票結果以一定的比例折算進入總分,調整原有分數,以防誤差過大。



四、拓展:加入性別識別
即准備男、女照片各約100張,應覆蓋不同年齡段,在樣本較少的情況下,(長得清秀的)男孩可能被誤認為女生。
分別打上標簽:0-女生,1-男生。
基於投票的分類,分別求測試圖與數據庫中特征值距離的歐式距離、余弦距離,取與特征距離最近的10張,找到對應的原圖所屬性別,進行投票,多於半數(即大於10張)認為其為該性別。
數據結果如下:
歐式距離最近10張圖片的性別結果:[1,1,0,0,1,1,1,1,1,1]
余弦距離最近10張圖片的性別結果:[1,1,1,0,0,1,1,1,1,1]
結果為:男性,置信度confidence=8*2/20=0.8
置信度表示本次結果的可信度,或根據先驗知識,求預測類別的概率。
基於投票的方案准確率較高。

【注】測試和訓練圖片均源於網絡。
還可以采用基於SVM的分類,關鍵代碼:
clf=svm.SVC(C=1, kernel='rbf', gamma=1, decision_function_shape='ovr')
clf.fit(dataMat,np.uint8(labelMat))
face_descriptor_trans=face_descriptor_trans.reshape(1,-1)
print(clf.decision_function(dataMat))
score=clf.predict(face_descriptor_trans)
但在問題顏值計算中,分類結果始終為第三類,原因暫未知。且第三類中圖片數量略多於其他類別。
二分類問題有不錯的表現。
此外鄰近匹配法和分類思想也可用於表情識別等分類問題中。
---------------------------------關鍵代碼-----------------------------------
歐氏距離與余弦距離計算
def euler_dist(vector1, vector2):
X = np.vstack([vector1, vector2])
dist = pdist(X)
return dist
def cos(vector1, vector2):
dot_product = 0.0;
normA = 0.0;
normB = 0.0;
for a, b in zip(vector1, vector2):
dot_product += a * b
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return None
else:
return dot_product / ((normA * normB) ** 0.5)
矩陣轉換為列表,可用index進行索引:dist1 = list(dist)
對原dist進行排序操作 找到距離最近的索引號new_dist1 = sorted(dist)
score_1[j]=labelMat[np.uint8(loca_dist1[j])]
反查出對應的標簽是哪一類。
for i in range(0,num_select):
record_times[np.uint8(score_1[i])]=record_times[np.uint8(score_1[i])]+1
進行投票表決。
得分加權:
final_score=score[np.uint8(score_1[0])]0.333+score[np.uint8(score_1[1])]0.333+score[np.uint8(score_1[2])]*0.333