FaceRank检测人脸颜值、亚欧、性别的模型(案例) 作者:马育民 • 2020-04-20 16:44 • 阅读:10469 # 介绍 本文通过卷积神经网络实现人脸颜值检测,识别亚洲人或欧洲人、性别等功能 ### 难点 实现比较简单,在 **多输出** 需要做额外处理: - 颜值检测是线性回归,loss是`mse` - 亚洲人或欧洲人识别是逻辑回归,loss是`sigmoid` - 性别检测是逻辑回归,loss是`sigmoid` ### 训练结果: - 颜值误差 0.3 - 亚洲/欧洲检测准确率 0.99 - 性别检测准确率 0.98 # 数据集 使用 华南理工大学人机智能交互实验室 的数据集 非常感谢 ### 介绍 数据集共有5500张正面,包括2000个亚洲女性(AF),2000个亚洲男性(AM),750个白人女性(CF)和750个白人男性(CM) 这些正面具有不同的属性(男性/女性,亚洲人/白种人,年龄)和不同的标签(面部标志,5个等级的美容分数,美容分数分布) 详细介绍见链接: https://github.com/HCIILAB/SCUT-FBP5500-Database-Release ### 标签 所有图像都由60名志愿者的美容评分标记为[1、5],并且在每个图像的重要面部组件上还定位了86个面部标志。 **缺点:** 由于审美不同,我对很多人脸的评分不认同,训练好模型后,预测知名网红、明星时,颜值分数不高,反而 **凤姐的颜值颇高** 所以 **测试自己颜值** 时参考就好,不必纠结 ### 下载链接 https://pan.baidu.com/s/1Ff2W2VLJ1ZbWSeV5JbF0Iw(PASSWORD:if7p ) ### 目录说明: [![](https://www.malaoshi.top/upload/0/0/1EF5NTsLAeNv.png)](https://www.malaoshi.top/upload/0/0/1EF5NTsLAeNv.png) # 技术 - TensorFlow2.0 - keras - matplotlib - numpy # 代码 ### 导包 ``` import os,glob os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import numpy as np import tensorflow as tf from tensorflow import keras import matplotlib.pyplot as plt from PIL import Image import IPython.display as display import xml.etree.ElementTree as ET print(tf.__version__) print(tf.test.is_gpu_available()) ``` ### 常量 ``` img_path="/kaggle/input/facial-beauty-prediction/SCUT-FBP5500_v2/Images/" img_size=224 batch_size=8 AUTOTUNE=tf.data.experimental.AUTOTUNE ac_map={"A":0,"C":1} fm_map={"F":0,"M":1} ``` ### 定义读取文本的函数 ``` def read_txt(path): with open(path,"rt") as f: lines=f.readlines() # print(lines) names=[] labels=[] acs=[] fms=[] for item in lines : item=item.strip() name,label=item.split(" ") ac=ac_map[name[0]] fm=fm_map[name[1]] acs.append(ac) fms.append(fm) # print(name,label) names.append(os.path.join(img_path,name)) labels.append(float(label)) return names,labels,acs,fms ``` ``` train_names,train_labels,train_acs,train_fms=read_txt("/kaggle/input/facial-beauty-prediction/SCUT-FBP5500_v2/train_test_files/split_of_60%training and 40%testing/train.txt") ``` ``` train_num=len(train_names) train_num ``` ``` test_names,test_labels,test_acs,test_fms=read_txt("/kaggle/input/facial-beauty-prediction/SCUT-FBP5500_v2/train_test_files/split_of_60%training and 40%testing/test.txt") ``` ### 生成训练数据集(关键) ``` train_ds=tf.data.Dataset.from_tensor_slices((train_names,(train_labels,train_acs,train_fms))) train_ds ``` **注意:** 传入一个tuple类型,第一个元素train_names是list类型,第二个元素是tuple类型,该tuple里面的每个元素都是list ### 定义预处理函数 ``` def process_train(path,label): t=tf.io.read_file(path) arr=tf.io.decode_jpeg(t,channels=3) arr=tf.image.resize(arr,(img_size,img_size)) arr = arr/255 return arr,label ``` ``` train_ds2=train_ds.map(process_train,num_parallel_calls=AUTOTUNE).shuffle(train_num).batch(batch_size).prefetch(AUTOTUNE) test_ds=tf.data.Dataset.from_tensor_slices((test_names,(test_labels,test_acs,test_fms))) test_ds2=test_ds.map(process_train,num_parallel_calls=AUTOTUNE).batch(batch_size).prefetch(AUTOTUNE) ``` ### 构建模型(关键) ``` def build(): inp=tf.keras.Input((img_size, img_size, 3)) x=tf.keras.layers.Conv2D(64,3,padding='same',activation="relu",)(inp) x=tf.keras.layers.Conv2D(64,3,padding='same',activation="relu")(x) x=tf.keras.layers.MaxPooling2D()(x) x=tf.keras.layers.Conv2D(128,3,padding='same',activation="relu")(x) x=tf.keras.layers.Conv2D(128,3,padding='same',activation="relu")(x) x=tf.keras.layers.MaxPooling2D()(x) x=tf.keras.layers.Conv2D(256,3,padding='same',activation="relu")(x) x=tf.keras.layers.Conv2D(256,3,padding='same',activation="relu")(x) x=tf.keras.layers.MaxPooling2D()(x) x=tf.keras.layers.Conv2D(512,3,padding='same',activation="relu")(x) x=tf.keras.layers.Conv2D(512,3,padding='same',activation="relu")(x) x=tf.keras.layers.GlobalAveragePooling2D()(x) x=tf.keras.layers.Dense(1024,activation="relu")(x) # x=tf.keras.layers.Dropout(0.5)(x) # x=tf.keras.layers.Dense(1024,activation="relu")(x) # x=tf.keras.layers.Dropout(0.5)(x) score=tf.keras.layers.Dense(1,name="score")(x) ac=tf.keras.layers.Dense(1,activation="sigmoid",name="ac")(x) fm=tf.keras.layers.Dense(1,activation="sigmoid",name="fm")(x) model=tf.keras.Model(inp,[score,ac,fm]) return model ``` **注意:** 模型中输出层layer的 **name**,在 **编译** 时会用到 ``` model=build() ``` ### 编译(关键) 编译时要注意,因为是多输出模型,所以要分别设置每个输出的loss,分别设置每个输出的metrics,如下代码: ``` model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001), loss=["mse","binary_crossentropy","binary_crossentropy"], metrics={"score":"mae","ac":"acc","fm":"acc"}) ``` **注意:** metrics是dict类型,key是:score、ac、fm,是模型中layer的name 或者 ``` model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001), loss=["mse","binary_crossentropy","binary_crossentropy"], metrics=[["mae"],["acc"],"acc"]) ``` **注意:** 必须是`metrics=[["mae"],"acc","acc"]`,不能是`metrics=["mae","acc","acc"]` ### 训练 ``` history=model.fit(train_ds2,epochs=40,validation_data=test_ds2) ``` 最后一次结果: ``` Epoch 36/40 217/413 [==============>...............] - ETA: 15s - loss: 0.2152 - score_loss: 0.1608 - ac_loss: 0.0205 - fm_loss: 0.0340 - score_mae: 0.3112 - ac_acc: 0.9948 - fm_acc: 0.9896 ``` 可知: - 颜值 score_mae 误差在0.3 - 亚洲/欧洲检测准确率在0.99 - 性别检测准确率在0.98 ### 查看loss和正确率 ``` plt.plot(history.epoch,history.history["score_mae"],label="score_mae") plt.plot(history.epoch,history.history["val_score_mae"],label="val_score_mae") plt.legend() ``` ``` plt.plot(history.epoch,history.history["ac_acc"],label="ac_acc") plt.plot(history.epoch,history.history["val_ac_acc"],label="val_ac_acc") plt.legend() ``` ``` plt.plot(history.epoch,history.history["fm_acc"],label="fm_acc") plt.plot(history.epoch,history.history["val_fm_acc"],label="val_fm_acc") plt.legend() ``` ``` plt.plot(history.epoch,history.history["score_loss"],label="score_loss") plt.plot(history.epoch,history.history["val_score_loss"],label="val_score_loss") plt.legend() ``` ``` plt.plot(history.epoch,history.history["ac_loss"],label="ac_loss") plt.plot(history.epoch,history.history["val_ac_loss"],label="val_ac_loss") plt.legend() ``` ``` plt.plot(history.epoch,history.history["fm_loss"],label="fm_loss") plt.plot(history.epoch,history.history["val_fm_loss"],label="val_fm_loss") plt.legend() ``` ### 保存模型 ``` model.save("model.h5",save_format="h5") ``` # 预测 ``` import tensorflow as tf import matplotlib.pyplot as plt img_size=224 ac_map={0:"亚洲",1:"欧洲"} fm_map={0:"女",1:"男"} ``` ### 加载模型 ``` model=tf.keras.models.load_model("/Users/mym/Desktop/数据集/SCUT-FBP5500_v2/model颜值亚欧性别.h5") ``` ### 定义函数 ``` def test(path): t=tf.io.read_file(path) arr=tf.io.decode_jpeg(t,channels=3) plt.imshow(arr) arr=tf.image.resize(arr,(img_size,img_size)) arr = arr/255 arr=tf.expand_dims(arr,0) prd=model.predict(arr) score,ac,fm=tf.squeeze(prd).numpy() print("score:",score,"ac:",ac,"fm:",fm) score=int(round(score*20)) ac=1 if ac>0.5 else 0 ac=ac_map.get(ac) fm=1 if fm>0.5 else 0 fm=fm_map.get(fm) print("颜值:%s,亚欧:%s,性别:%s"%(score,ac,fm)) ``` ``` test("/Users/mym/Desktop/可删除/OIP.jpeg") ``` 原文出处:http://malaoshi.top/show_1EF5NUEm0T3B.html