基于TensorFlow深度学习人脸识别源码级项目实战

文章目录

  • 前言
  • 一、年龄识别核心代码guess.py
  • 二、年龄识别Web工程化代码
  • 总结


前言

人脸年龄识别属于人脸属性识别的范畴,人脸属性识别可对图片中的人脸进行检测定位,并识别出人脸的相关属性(如年龄、性别、表情、种族、颜值等)内容。不同属性识别的算法可以相同,也可以不同。rude-carnie是做年龄识别和性别识别的一个开源项目,基于TensorFlow,源代码网址:http://www.github.com/dpressel/rude-carnie。下面我们基于这个项目源码来讲年龄识别。

一、年龄识别核心代码guess.py

我们可以把年龄划分为几个段[’(0, 2)’,’(4, 6)’,’(8, 12)’,’(15, 20)’,’(25, 32)’,’(38, 43)’,’(48, 53)’,’(60, 100)’],然后基于分类的思想来做年龄预测问题。用下面的脚本命令:

python3 guess.py --model_type inception --model_dir /home/hadoop/chongdianleme/ nianling/22801/inception/22801 --filename /home/hadoop/chongdianleme/data/myimages/baidu1.jpg

基于训练好的年龄模型和人脸图片就能预测出年龄。但是有一个问题,直接这样预测不是很准,因为图片没有经过任何处理。我们可以通过opencv和上面讲到的FaceNet的人脸检测和对齐算法来做。但opencv比较简单,FaceNet的人脸检测和对齐效果比较好,我们可以使用前面提供的http服务接口http://172.17.100.216:8816/detectAndAlignedService来处理,然后把检测和对齐后的人脸图片传给guess.py,这样预测处理的效果精准很多。

另外一个问题是,因为训练的模型用的是开源项目训练好的,是拿外国人的人脸数据训练,这样用来预测我们中国人的年龄会有一些差异,最好的方式是拿我们中国人自己的人脸年龄数据做训练,这样预测才会更好。

针对年龄识别和性别识别都是用guess.py这个文件,年龄识别是多分类,性别是二分类。我们看下guess.py的源码,如代码8.5所示:

【代码8.5】 guess.py

代码如下(示例):

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from datetime import datetime
import math
import time
from data import inputs
import numpy as np
import tensorflow as tf
from model import select_model, get_checkpoint
from utils import *
import os
import json
import csv

RESIZE_FINAL = 227
#性别有两个
GENDER_LIST =['M','F']
#年龄是分段的,可以看成多分类任务
AGE_LIST = ['(0, 2)','(4, 6)','(8, 12)','(15, 20)','(25, 32)','(38, 43)','(48, 53)','(60, 100)']
MAX_BATCH_SZ = 128
#模型文件目录
tf.app.flags.DEFINE_string('model_dir', '',
'Model directory (where training data lives)')
#性别和年龄都是用的这个,通过参数age|gender来区分
tf.app.flags.DEFINE_string('class_type', 'age',
'Classification type (age|gender)')
#用cpu还是用GPU来训练
tf.app.flags.DEFINE_string('device_id', '/cpu:0',
'What processing unit to execute inference on')
tf.app.flags.DEFINE_string('filename', '',
'File (Image) or File list (Text/No header TSV) to process')
tf.app.flags.DEFINE_string('target', '',
'CSV file containing the filename processed along with best guess and score')
#检查点
tf.app.flags.DEFINE_string('checkpoint', 'checkpoint',
'Checkpoint basename')
tf.app.flags.DEFINE_string('model_type', 'default',
'Type of convnet')
tf.app.flags.DEFINE_string('requested_step', '', 'Within the model directory, a requested step to restore e.g., 9000')
tf.app.flags.DEFINE_boolean('single_look', False, 'single look at the image or multiple crops')
tf.app.flags.DEFINE_string('face_detection_model', '', 'Do frontal face detection with model specified')
tf.app.flags.DEFINE_string('face_detection_type', 'cascade', 'Face detection model type (yolo_tiny|cascade)')
FLAGS = tf.app.flags.FLAGS

def one_of(fname, types):
return any([fname.endswith('.' + ty) for ty in types])

def resolve_file(fname):
if os.path.exists(fname): return fname
for suffix in ('.jpg', '.png', '.JPG', '.PNG', '.jpeg'):
cand = fname + suffix
if os.path.exists(cand):
return cand
return None

def classify_many_single_crop(sess, label_list, softmax_output, coder, images, image_files, writer):
try:
num_batches = math.ceil(len(image_files) / MAX_BATCH_SZ)
pg = ProgressBar(num_batches)
for j in range(num_batches):
start_offset = j * MAX_BATCH_SZ
end_offset = min((j + 1) * MAX_BATCH_SZ, len(image_files))

batch_image_files = image_files[start_offset:end_offset]
print(start_offset, end_offset, len(batch_image_files))
image_batch = make_multi_image_batch(batch_image_files, coder)
batch_results = sess.run(softmax_output, feed_dict={
     images:image_batch.eval()})
batch_sz = batch_results.shape[0]
for i in range(batch_sz):
output_i = batch_results[i]
best_i = np.argmax(output_i)
best_choice = (label_list[best_i], output_i[best_i])
print('Guess @ 1 %s, prob = %.2f' % best_choice)
if writer is not None:
f = batch_image_files[i]
writer.writerow((f, best_choice[0], '%.2f' % best_choice[1]))
pg.update()
pg.done()
except Exception as e:
print(e)
print('Failed to run all images')

def classify_one_multi_crop(sess, label_list, softmax_output, coder, images, image_file, writer):
try:

print('Running file %s' % image_file)
image_batch = make_multi_crop_batch(image_file, coder)

batch_results = sess.run(softmax_output, feed_dict={
     images:image_batch.eval()})
output = batch_results[0]
batch_sz = batch_results.shape[0]

for i in range(1, batch_sz):
output = output + batch_results[i]

output /= batch_sz
best = np.argmax(output)
best_choice = (label_list[best], output[best])
print('Guess @ 1 %s, prob = %.2f' % best_choice)

nlabels = len(label_list)
if nlabels > 2:
output[best] = 0
second_best = np.argmax(output)
print('Guess @ 2 %s, prob = %.2f' % (label_list[second_best], output[second_best]))

if writer is not None:
writer.writerow((image_file, best_choice[0], '%.2f' % best_choice[1]))
except Exception as e:
print(e)
print('Failed to run image %s ' % image_file)

def list_images(srcfile):
with open(srcfile, 'r') as csvfile:
delim = ',' if srcfile.endswith('.csv') else '\t'
reader = csv.reader(csvfile, delimiter=delim)
if srcfile.endswith('.csv') or srcfile.endswith('.tsv'):
print('skipping header')
_ = next(reader)

return [row[0] for row in reader]

def main(argv=None): # pylint: disable=unused-argument
files = []
print("target %s" % FLAGS.target)
if FLAGS.face_detection_model:
print('Using face detector (%s) %s' % (FLAGS.face_detection_type, FLAGS.face_detection_model))
face_detect = face_detection_model(FLAGS.face_detection_type, FLAGS.face_detection_model)
face_files, rectangles = face_detect.run(FLAGS.filename)
print(face_files)
files += face_files

config = tf.ConfigProto(allow_soft_placement=True)
with tf.Session(config=config) as sess:
label_list = AGE_LIST if FLAGS.class_type == 'age' else GENDER_LIST
nlabels = len(label_list)
print('Executing on %s' % FLAGS.device_id)
model_fn = select_model(FLAGS.model_type)
with tf.device(FLAGS.device_id):
images = tf.placeholder(tf.float32, [None, RESIZE_FINAL, RESIZE_FINAL, 3])
logits = model_fn(nlabels, images, 1, False)
init = tf.global_variables_initializer()

requested_step = FLAGS.requested_step if FLAGS.requested_step else None

checkpoint_path = '%s' % (FLAGS.model_dir)

model_checkpoint_path, global_step = get_checkpoint(checkpoint_path, requested_step, FLAGS.checkpoint)

saver = tf.train.Saver()
saver.restore(sess, model_checkpoint_path)

softmax_output = tf.nn.softmax(logits)

coder = ImageCoder()

# Support a batch mode if no face detection model
if len(files) == 0:
if (os.path.isdir(FLAGS.filename)):
for relpath in os.listdir(FLAGS.filename):
abspath = os.path.join(FLAGS.filename, relpath)

if os.path.isfile(abspath) and any([abspath.endswith('.' + ty) for ty in ('jpg', 'png', 'JPG', 'PNG', 'jpeg')]):
print(abspath)
files.append(abspath)
else:
files.append(FLAGS.filename)
# If it happens to be a list file, read the list and clobber the files
if any([FLAGS.filename.endswith('.' + ty) for ty in ('csv', 'tsv', 'txt')]):
files = list_images(FLAGS.filename)

writer = None
output = None
if FLAGS.target:
print('Creating output file %s' % FLAGS.target)
output = open(FLAGS.target, 'w')
writer = csv.writer(output)
writer.writerow(('file', 'label', 'score'))
image_files = list(filter(lambda x: x is not None, [resolve_file(f) for f in files]))
print(image_files)
if FLAGS.single_look:
classify_many_single_crop(sess, label_list, softmax_output, coder, images, image_files, writer)

else:
for image_file in image_files:
classify_one_multi_crop(sess, label_list, softmax_output, coder, images, image_file, writer)

if output is not None:
output.close()

if __name__ == '__main__':
tf.app.run()

二、年龄识别Web工程化代码

年龄识别我们对外提供一个Web接口,guessAgeWeb_chongdianleme.py如代码8.6所示:

【代码8.6】 guessAgeWeb_chongdianleme.py

代码如下(示例):

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from datetime import datetime
import math
import time
from data import inputs
import numpy as np
import tensorflow as tf
from model import select_model, get_checkpoint
from utils import *
import os
import csv
#pip3 install flask
from flask import Flask
from flask import request
import urllib
# pip3 install requests
import requests, urllib.request
from scipy import misc
import argparse
import facenet
import align.detect_face
import json

RESIZE_FINAL = 227
#性别有两个
GENDER_LIST = ['M', 'F']
#年龄是分段的,可以看成多分类任务
AGE_LIST = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)', '(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
MAX_BATCH_SZ = 128
def one_of(fname, types):
return any([fname.endswith('.' + ty) for ty in types])
def resolve_file(fname):
if os.path.exists(fname): return fname
for suffix in ('.jpg', '.png', '.JPG', '.PNG', '.jpeg'):
cand = fname + suffix
if os.path.exists(cand):
return cand
return None
def list_images(srcfile):
with open(srcfile, 'r') as csvfile:
delim = ',' if srcfile.endswith('.csv') else '\t'
reader = csv.reader(csvfile, delimiter=delim)
if srcfile.endswith('.csv') or srcfile.endswith('.tsv'):
print('skipping header')
_ = next(reader)
return [row[0] for row in reader]
# 初始化
class_type = 'age'
device_id = "/cpu:0"
model_type = "inception"
requested_step = ""
#模型文件目录
model_dir = "/home/hadoop/chongdianleme/nianling/22801/inception/22801"
checkpoint = "checkpoint"
config = tf.ConfigProto(allow_soft_placement=True)
sess = tf.Session(config=config)
with sess.as_default():
label_list = AGE_LIST if class_type == 'age' else GENDER_LIST
nlabels = len(label_list)
model_fn = select_model(model_type)
images = tf.placeholder(tf.float32, [None, RESIZE_FINAL, RESIZE_FINAL, 3])
logits = model_fn(nlabels, images, 1, False)
init = tf.global_variables_initializer()
requested_step = requested_step if requested_step else None
checkpoint_path = '%s' % (model_dir)
model_checkpoint_path, global_step = get_checkpoint(checkpoint_path, requested_step, checkpoint)
saver = tf.train.Saver()
saver.restore(sess, model_checkpoint_path)
softmax_output = tf.nn.softmax(logits)
coder = ImageCoder()
def _is_png(filename):
return '.png' in filename

app = Flask(__name__)
@app.route('/predictAge', methods=['GET', 'POST'])
def prediction():
start = time.time()
imageUrl = request.values.get("imageUrl")
#用户信息
device = request.values.get("device")
userid = request.values.get("userid")
urlType = request.values.get("urlType")
imageType = request.values.get("imageType")
files = []
#支持本地图片和网络图片
if urlType=="local":
filename = imageUrl
else:
baseImageName = os.path.basename(imageUrl)
filename = "/home/hadoop/chongdianleme/ageimage/%s" % baseImageName
filename = filename+imageType
urllib.request.urlretrieve(imageUrl, filename)
#通过我们前面讲的FaceNet里的人脸检测和对齐的http接口对图片进行处理,这样识别的年龄更精准
url = "http://172.17.100.216:8816/detectAndAlignedService"
body_value = {
     "image_file": filename, "alignedImage_files":filename}
data_urlencode = urllib.parse.urlencode(body_value).encode(encoding='UTF8')
request2 = urllib.request.Request(url, data_urlencode)
#调用接口
resultJson = urllib.request.urlopen(request2).read().decode('UTF-8')
#解析json格式的数据
o = json.loads(resultJson)
ts = o["times"]
i = o["i"]
newFileName = filename.replace(".","_0_.")
files.append(newFileName)
image_files = list(filter(lambda x: x is not None, [resolve_file(f) for f in files]))
print(image_files)
finalAge = 0
avgBest = 0.00
bestProb = 0.00
avgSecond = 0.00
secondProb = 0.00
for image_file in image_files:
try:
print('Running file %s' % image_file)
#image_batch = make_multi_crop_batch(image_file, coder)
#start
with tf.gfile.FastGFile(filename, 'rb') as f:
image_data = f.read()

# Convert any PNG to JPEG's for consistency.
if _is_png(filename):
print('Converting PNG to JPEG for %s' % filename)
image_data = coder.png_to_jpeg(image_data)

image = coder.decode_jpeg(image_data)

crops = []
print('Running multi-cropped image')
h = image.shape[0]
w = image.shape[1]
hl = h - RESIZE_FINAL
wl = w - RESIZE_FINAL

crop = tf.image.resize_images(image, (RESIZE_FINAL, RESIZE_FINAL))
crops.append(standardize_image(crop))
crops.append(tf.image.flip_left_right(crop))

corners = [(0, 0), (0, wl), (hl, 0), (hl, wl), (int(hl / 2), int(wl / 2))]
for corner in corners:
ch, cw = corner
cropped = tf.image.crop_to_bounding_box(image, ch, cw, RESIZE_FINAL, RESIZE_FINAL)
crops.append(standardize_image(cropped))
flipped = tf.image.flip_left_right(cropped)
crops.append(standardize_image(flipped))

image_batch = tf.stack(crops)
#end
batch_results = sess.run(softmax_output, feed_dict={
     images:image_batch.eval(session=sess)})
output = batch_results[0]
batch_sz = batch_results.shape[0]

for i in range(1, batch_sz):
output = output + batch_results[i]

output /= batch_sz
best = np.argmax(output)
ageClass = label_list[best] # (25, 32)
bestAgeArr = ageClass.replace(" ", "").replace("(", "").replace(")", "").split(",")
#AGE_LIST = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)', '(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
#因为训练的模型用的是开源项目训练好的,是拿外国人的人脸数据训练,
# 这样用来预测我们中国人的年龄会有一些差异,最好的方式是拿我们中国人自己的人脸年龄数据做训练,这样预测才会更好。
# 所以针对外国人训练数据预测我们中国人需要对年龄做一些经验上的特殊处理
if int(bestAgeArr[1]) == 53:
avgBest= 56
elif int(bestAgeArr[1]) == 43:
avgBest = 45
elif int(bestAgeArr[1]) == 20:
avgBest = 22.66
elif int(bestAgeArr[1]) == 6:
avgBest = 6.66
else:
avgBest = (int(bestAgeArr[0]) + int(bestAgeArr[1])) / 1.66
bestProb = output[best]
best_choice = (label_list[best], output[best])
print('Guess @ 1 %s, prob = %.2f' % best_choice)

nlabels = len(label_list)
if nlabels > 2:
output[best] = 0
second_best = np.argmax(output)
secondAgeClass = label_list[second_best] # (25, 32)
secondAgeArr = secondAgeClass.replace(" ", "").replace("(", "").replace(")", "").split(",")
if int(secondAgeArr[1])== 53:
avgSecond = 56
elif int(secondAgeArr[1])== 43:
avgSecond = 45
elif int(secondAgeArr[1])== 20:
avgSecond = 22.66
elif int(secondAgeArr[1])== 6:
avgSecond = 6.66
else:
avgSecond = (int(secondAgeArr[0]) + int(secondAgeArr[1])) / 1.66
secondProb = output[second_best]
print('Guess @ 2 %s, prob = %.2f' % (label_list[second_best], output[second_best]))
except Exception as e:
import traceback
traceback.print_exc()
print('Failed to run image %s ' % image_file)

if avgSecond > 0:
#基于加权平均法计算最终的合适的年龄
finalAge = (avgBest * bestProb + avgSecond * secondProb) / (bestProb + secondProb)
else:
finalAge = avgBest
print("finalAge %s " % finalAge)
end = time.time()
times = str(end - start)
#返回年龄等json格式数据
result = {
     "finalAge": finalAge,"times": times}
out = json.dumps(result, ensure_ascii=False)
print("out={0}".format(out))
return out

if __name__ == '__main__':
#指定ip地址和端口号
app.run(host='172.17.100.216', port=8818)

然后我们看下怎么部署和启动基于Flask的年龄识别服务,脚本代码如下所示:

#创建shell脚本文件vim guessAgeService.sh

#输入:

python3 guessAgeWeb_chongdianleme.py

#然后:wq保存

#对guessAgeService.sh脚本授权可执行权限

sudo chmod 755 guessAgeService.sh

#然后再创建一个以后台方式运行的shell脚本:

vim nohupguessAgeService.sh

#输入:

nohup /home/hadoop/chongdianleme/guessAgeService.sh > guessAge.log 2>&1 &

#然后:wq保存

#同样对nohupguessAgeService.sh脚本授权可执行权限

sudo chmod 755 nohupguessAgeService.sh

## 2.读入数据

<font color=#999AAA >代码如下(示例):



```c
data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

#最后运行sh nohupguessAgeService.sh脚本启动基于flask的人脸识别比对服务接口。

启动完成后,就可以在浏览器地址里输入url访问我们的服务了。这个http接口声明了同时支持get和post访问,我们在浏览器里输入地址就可以直接访问了。

http://172.17.100.216:8818/predictAge?imageUrl=/home/hadoop/chongdianleme/age/luhan2.jpg&urlType=local&imageType=jpg

这个就是一个接口服务,其他系统或者php、java web网站都可以调用这个接口,输入要预测imageUrl人脸图片路径,urlType是同时支持本地图片和网络图片链接的设置,返回人脸年龄json格式数据。

总结

除了基于TensorFlow深度学习人脸识别源码级项目实战

其它深度学习框架也有不错的开源实现,比如MXNet,
此文章有对应的配套视频,其它更多精彩文章请大家下载充电了么app,可获取千万免费好课和文章,配套新书教材请看陈敬雷新书:《分布式机器学习实战》(人工智能科学与技术丛书)

【新书介绍】
《分布式机器学习实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】
新书特色:深入浅出,逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目

【新书介绍视频】
分布式机器学习实战(人工智能科学与技术丛书)新书【陈敬雷】
视频特色:重点对新书进行介绍,最新前沿技术热点剖析,技术职业规划建议!听完此课你对人工智能领域将有一个崭新的技术视野!职业发展也将有更加清晰的认识!

【精品课程】
《分布式机器学习实战》大数据人工智能AI专家级精品课程

【免费体验视频】:
人工智能百万年薪成长路线/从Python到最新热点技术

从Python编程零基础小白入门到人工智能高级实战系列课

视频特色: 本系列专家级精品课有对应的配套书籍《分布式机器学习实战》,精品课和书籍可以互补式学习,彼此相互补充,大大提高了学习效率。本系列课和书籍是以分布式机器学习为主线,并对其依赖的大数据技术做了详细介绍,之后对目前主流的分布式机器学习框架和算法进行重点讲解,本系列课和书籍侧重实战,最后讲几个工业级的系统实战项目给大家。 课程核心内容有互联网公司大数据和人工智能那些事、大数据算法系统架构、大数据基础、Python编程、Java编程、Scala编程、Docker容器、Mahout分布式机器学习平台、Spark分布式机器学习平台、分布式深度学习框架和神经网络算法、自然语言处理算法、工业级完整系统实战(推荐算法系统实战、人脸识别实战、对话机器人实战)、就业/面试技巧/职业生涯规划/职业晋升指导等内容。

【充电了么公司介绍】

充电了么App是专注上班族职业培训充电学习的在线教育平台。

专注工作职业技能提升和学习,提高工作效率,带来经济效益!今天你充电了么?

充电了么官网
http://www.chongdianleme.com/

充电了么App官网下载地址
https://a.app.qq.com/o/simple.jsp?pkgname=com.charged.app

功能特色如下:

【全行业职位】 - 专注职场上班族职业技能提升

覆盖所有行业和职位,不管你是上班族,高管,还是创业都有你要学习的视频和文章。其中大数据智能AI、区块链、深度学习是互联网一线工业级的实战经验。

除了专业技能学习,还有通用职场技能,比如企业管理、股权激励和设计、职业生涯规划、社交礼仪、沟通技巧、演讲技巧、开会技巧、发邮件技巧、工作压力如何放松、人脉关系等等,全方位提高你的专业水平和整体素质。

【牛人课堂】 - 学习牛人的工作经验

1.智能个性化引擎:

海量视频课程,覆盖所有行业、所有职位,通过不同行业职位的技能词偏好挖掘分析,智能匹配你目前职位最感兴趣的技能学习课程。

2.听课全网搜索

输入关键词搜索海量视频课程,应有尽有,总有适合你的课程。

3.听课播放详情

视频播放详情,除了播放当前视频,更有相关视频课程和文章阅读,对某个技能知识点强化,让你轻松成为某个领域的资深专家。

【精品阅读】 - 技能文章兴趣阅读

1.个性化阅读引擎:

千万级文章阅读,覆盖所有行业、所有职位,通过不同行业职位的技能词偏好挖掘分析,智能匹配你目前职位最感兴趣的技能学习文章。

2.阅读全网搜索

输入关键词搜索海量文章阅读,应有尽有,总有你感兴趣的技能学习文章。

【机器人老师】 - 个人提升趣味学习

基于搜索引擎和智能深度学习训练,为您打造更懂你的机器人老师,用自然语言和机器人老师聊天学习,寓教于乐,高效学习,快乐人生。

【精短课程】 - 高效学习知识

海量精短牛人课程,满足你的时间碎片化学习,快速提高某个技能知识点。

你可能感兴趣的:(深度学习,人工智能,tensorflow,机器学习)