Toybrick

人工智能开发系列(8) 表情识别

jax.fang

中级会员

积分
371
楼主
发表于 2019-6-21 09:19:29    查看: 65813|回复: 19 | [复制链接]    打印 | 只看该作者
  
                        
                                本教程视频直播回看:


三、快速上手
1)解压附件代码到开发板上, 进入rknn_test目录
2)python3 rknn_transfer.py  进行RKNN模型转换(先将训练好的HDF5模型文件转为Tensorflow模型pb文件, 再转成RKNN模型文件)
3)python3 rknn_image_demo.py test_images/1.jpg  图像表情识别
4)python3 rknn_video_demo.py 摄像头实时表情识别

四、概述
本示例代码表情识别基本流程:
加载RKNN模型 -> 图像输入 -> 人脸检测 -> 图像预处理 -> NPU模型推理 ->  输出分类概率 -> 识别结果
人脸检测采用OPENCV-PYTHON识别,用FER2013数据集训练深度卷积神经网络构建的模型, 准确度为66%, 表情分七类:0 angry;1 disgust; 2 fear;3 happy; 4 sad; 5 surprise; 6 neutral;

五、通过RKNN转换时注意点
1、rknn.config(reorder_channel='0, 1, 2')
① 由于输入数据在前处理阶段做归一化处理, 所以RKNN模型转换时不必设置channel_mean_value。
② reorder_channel设置为按输入的图像通道顺序不做调整。
③ 构建模型时不进行量化,所以quantized_dtype可不作设置。
2、rknn.load_tensorflow(tf_pb=pb_path, inputs=['input_1'], outputs=['predictions/Softmax'],
                         input_size_list=[[INPUT_WIDTH, INPUT_HEIGHT, 1]])
① inputs指定模型中的输入节点, outputs指定模型中的输出节点。
② input_size_list中注意输入数据为灰度图, 所以channel值应为1.
3、rknn.build(do_quantization=False)
① 不对模型进行量化。
4、 rknn.inference(inputs=[gray_face], data_type='float32', data_format='nhwc')
① 输入数据在预处理后已是float32类型, 所以推理阶段要求传入的数据类型必须保持一致。
② 输入数据的data_format为默认值‘nhwc’

六、代码解析
rknn_transfer.py
  1. from rknn.api import RKNN

  2. from keras.models import load_model
  3. import tensorflow as tf
  4. import os
  5. import os.path as osp
  6. from keras import backend as K

  7. model_name = 'fer2013_mini_XCEPTION.102-0.66'
  8. #model_name = 'ck_mini_XCEPTION.95-0.89'
  9. #model_name = 'ck_mini_XCEPTION.98-0.90'

  10. def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
  11.     """
  12.     Freezes the state of a session into a prunned computation graph.

  13.     Creates a new computation graph where variable nodes are replaced by
  14.     constants taking their current value in the session. The new graph will be
  15.     prunned so subgraphs that are not neccesary to compute the requested
  16.     outputs are removed.
  17.     @param session The TensorFlow session to be frozen.
  18.     @param keep_var_names A list of variable names that should not be frozen,
  19.                           or None to freeze all the variables in the graph.
  20.     @param output_names Names of the relevant graph outputs.
  21.     @param clear_devices Remove the device directives from the graph for better portability.
  22.     @return The frozen graph definition.
  23.     """
  24.     from tensorflow.python.framework.graph_util import convert_variables_to_constants
  25.     graph = session.graph
  26.     with graph.as_default():
  27.         freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
  28.         output_names = output_names or []
  29.         output_names += [v.op.name for v in tf.global_variables()]
  30.         input_graph_def = graph.as_graph_def()
  31.         if clear_devices:
  32.             for node in input_graph_def.node:
  33.                 node.device = ""
  34.         frozen_graph = convert_variables_to_constants(session, input_graph_def,
  35.                                                       output_names, freeze_var_names)
  36.         return frozen_graph

  37. def pb_transfer():
  38.     #input_fld = sys.path[0]
  39.     input_fld = './trained_models/emotion_models/'
  40.     weight_file = model_name + '.hdf5'

  41.     output_fld = './'
  42.     output_graph_name = model_name + '.pb'

  43.     if not os.path.isdir(output_fld):
  44.         os.mkdir(output_fld)
  45.     weight_file_path = osp.join(input_fld, weight_file)

  46.     K.set_learning_phase(0)
  47.     net_model = load_model(weight_file_path)

  48.     print('input is :', net_model.input.name)
  49.     print ('output is:', net_model.output.name)

  50.     sess = K.get_session()

  51.     frozen_graph = freeze_session(K.get_session(), output_names=[net_model.output.op.name])

  52.     from tensorflow.python.framework import graph_io

  53.     graph_io.write_graph(frozen_graph, output_fld, output_graph_name, as_text=False)

  54.     print('saved the constant graph (ready for inference) at: ', osp.join(output_fld, output_graph_name))


  55. INPUT_WIDTH = 64
  56. INPUT_HEIGHT = 64

  57. def transfer(pb_path, rknn_name):
  58.     # 创建RKNN执行对象
  59.     #rknn = RKNN(verbose=True, verbose_file='./mini_XCEPTION_build.log')
  60.     rknn = RKNN()
  61. # 配置模型输入,用于NPU对数据输入的预处理
  62. # channel_mean_value='0 0 0 255',那么模型推理时,将会对RGB数据做如下转换
  63. # (R - 0)/255, (G - 0)/255, (B - 0)/255。推理时,RKNN模型会自动做均值和归一化处理
  64. # reorder_channel=’0 1 2’用于指定是否调整图像通道顺序,设置成0 1 2即按输入的图像通道顺序不做调整
  65. # reorder_channel=’2 1 0’表示交换0和2通道,如果输入是RGB,将会被调整为BGR。如果是BGR将会被调整为RGB
  66. #图像通道顺序不做调整
  67.     #rknn.config(channel_mean_value='0 0 0 255', reorder_channel='0 1 2')
  68.     rknn.config(quantized_dtype='dynamic_fixed_point-8')

  69. # 加载TensorFlow模型
  70. # tf_pb='digital_gesture.pb'指定待转换的TensorFlow模型
  71. # inputs指定模型中的输入节点
  72. # outputs指定模型中输出节点
  73. # input_size_list指定模型输入的大小
  74.     print('--> Loading model')
  75.     ret = rknn.load_tensorflow(tf_pb=pb_path,
  76.                          inputs=['input_1'],
  77.                          outputs=['predictions/Softmax'],
  78.                          input_size_list=[[INPUT_WIDTH, INPUT_HEIGHT, 1]])
  79.     if ret != 0:
  80.         print('Load Model failed!')
  81.         exit(ret)
  82.     print('done')

  83. # 创建解析pb模型
  84. # do_quantization=False指定不进行量化
  85. # 量化会减小模型的体积和提升运算速度,但是会有精度的丢失
  86.     print('--> Building model')
  87.     ret = rknn.build(do_quantization=False)
  88.     if ret != 0:
  89.         print('Build Model failed!')
  90.         exit(ret)
  91.     print('done')

  92.     # 导出保存rknn模型文件
  93.     print('--> Export RKNN model')
  94.     ret = rknn.export_rknn(rknn_name)
  95.     if ret != 0:
  96.         print('Export Model failed!')
  97.         exit(ret)
  98.     print('done')

  99.     # Release RKNN Context
  100.     rknn.release()

  101. if __name__ == '__main__':
  102.     pb_transfer()
  103.     transfer(model_name + '.pb', model_name + '.rknn')
复制代码
rknn_image_demo.py
  1. import numpy as np
  2. import cv2
  3. from rknn.api import RKNN
  4. from time import time
  5. #from utils.builddata import preprocess_input
  6. import sys, getopt
  7. import sys

  8. from utils.inference import detect_faces
  9. from utils.inference import draw_text
  10. from utils.inference import draw_bounding_box
  11. from utils.inference import apply_offsets
  12. from utils.inference import load_detection_model
  13. from utils.inference import load_image
  14. from utils.preprocessor import preprocess_input

  15. # parameters for loading data and images
  16. detection_model_path = './trained_models/detection_models/haarcascade_frontalface_default.xml'

  17. def get_labels(dataset_name):
  18.     if dataset_name == 'fer2013':
  19.         return {0: 'angry', 1: 'disgust', 2: 'fear', 3: 'happy',
  20.                 4: 'sad', 5: 'surprise', 6: 'neutral'}

  21. emotion_labels = get_labels('fer2013')
  22. font = cv2.FONT_HERSHEY_SIMPLEX

  23. INPUT_SIZE = 64

  24. def load_model(modle_path):
  25.         # Create RKNN object
  26.         rknn = RKNN()

  27.         print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
  28.         print('-->loading model')
  29.         rknn.load_rknn(modle_path)
  30.         print('loading model done')

  31.         # init runtime environment
  32.         print('--> Init runtime environment')
  33.         ret = rknn.init_runtime()
  34.         if ret != 0:
  35.                 print('Init runtime environment failed')
  36.                 exit(ret)
  37.         print('done')
  38.         print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
  39.         return rknn

  40. def model_predict(rknn, gray_face):
  41.         #指定输入数据格式, 进行模型推理, 并返回推理结果, 结果为7个表情标签的概率值
  42.     emotion_prediction = rknn.inference(inputs=[gray_face], data_type='float32', data_format='nhwc')
  43.         #根据表情分类预测概率,识别表情
  44.     emotion_probability = np.max(emotion_prediction)
  45.     emotion_label_arg = np.argmax(emotion_prediction)
  46.     emotion_text = emotion_labels[emotion_label_arg]
  47.     return emotion_text


  48. if __name__ == '__main__':
  49.     image_path = sys.argv[1]

  50.     # hyper-parameters for bounding boxes shape
  51.     emotion_offsets = (0, 0)

  52.     # loading models
  53.     rknn = load_model('./fer2013_mini_XCEPTION.102-0.66.rknn')
  54.         # 加载人脸检测模型
  55.     face_detection = load_detection_model(detection_model_path)

  56.     # 设置模型输入图片像素大小, 这里为64x64
  57.     emotion_target_size = (INPUT_SIZE, INPUT_SIZE)

  58.     # 加载图片, 并转为灰度图
  59.     rgb_image = load_image(image_path, grayscale=False)
  60.     gray_image = load_image(image_path, grayscale=True)
  61.     gray_image = np.squeeze(gray_image)
  62.     gray_image = gray_image.astype('uint8')

  63.     start = time()
  64.         # 检测图片中人脸个数, 并返回人脸数据集
  65.     faces = detect_faces(face_detection, gray_image)
  66.     print('detect face cost time: %f'%(time()-start))

  67.     for face_coordinates in faces:
  68.         start = time()
  69.                 #从所有人脸数据集中截取单个人脸数据
  70.         x1, x2, y1, y2 = apply_offsets(face_coordinates, emotion_offsets)
  71.         gray_face = gray_image[y1:y2, x1:x2]

  72.         try:
  73.                         #将截取的人脸数据设置为64x64像素
  74.             gray_face = cv2.resize(gray_face, (emotion_target_size))
  75.         except:
  76.             continue

  77.                 #人脸数据归一化处理, 并转化为RKNN模型要求的输入数据格式
  78.         gray_face = preprocess_input(gray_face, True)
  79.         gray_face = np.expand_dims(gray_face, 0)
  80.         gray_face = np.expand_dims(gray_face, -1)

  81.         emotion_text = model_predict(rknn, gray_face)
  82.         print('predict emotion cost time: %f'%(time()-start))
  83.         print('predict emotion result: ' + emotion_text)

  84.         color = (255, 0, 0)
  85.         draw_bounding_box(face_coordinates, rgb_image, color)
  86.         draw_text(face_coordinates, rgb_image, emotion_text, color, 0, 0, 1, 2)

  87.     bgr_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR)
  88.     cv2.imwrite('./predicted_test_image_rknn.png', bgr_image)
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

TryYourBest

注册会员

积分
77
沙发
发表于 2019-7-1 14:32:48 | 只看该作者
我通过rknn_transfer.py文件在开发板上转换simple_CNN.81-0.96.pb文件为rknn过程中提示模型加载失败,这是为什么,该如何解决,请指教,谢谢!
错误内容如下:

  1. --> Loading model
  2. E Catch exception when loading tensorflow model: simple_CNN.81-0.96.pb!
  3. T Traceback (most recent call last):
  4. T   File "rknn/api/rknn_base.py", line 136, in rknn.api.rknn_base.RKNNBase.load_tensorflow
  5. T   File "rknn/base/RKNNlib/converter/convert_tf.py", line 102, in rknn.base.RKNNlib.converter.convert_tf.convert_tf.__init__
  6. T   File "rknn/base/RKNNlib/converter/tensorflowloader.py", line 53, in rknn.base.RKNNlib.converter.tensorflowloader.TF_Graph_Preprocess.__init__
  7. T AttributeError: 'NoneType' object has no attribute 'op'
  8. Load Model failed!
复制代码
回复

使用道具 举报

jax.fang

中级会员

积分
371
板凳
 楼主| 发表于 2019-7-4 09:51:17 | 只看该作者
TryYourBest 发表于 2019-7-1 14:32
我通过rknn_transfer.py文件在开发板上转换simple_CNN.81-0.96.pb文件为rknn过程中提示模型加载失败,这是 ...

可以将rknn=RKNN()改成rknn=RKNN(verbose=True)看下详细的日志信息, 可以看到是哪个OP不支持
回复

使用道具 举报

TryYourBest

注册会员

积分
77
地板
发表于 2019-7-4 10:15:28 | 只看该作者
本帖最后由 TryYourBest 于 2019-7-4 10:16 编辑
jax.fang 发表于 2019-7-4 09:51
可以将rknn=RKNN()改成rknn=RKNN(verbose=True)看下详细的日志信息, 可以看到是哪个OP不支持
...

将rknn = RKNN()改成rknn = RKNN(verbose = True)后,提示如下错误,多了第一行的D import~,由于知识尚浅,不明白啥意思

  1. --> Loading model
  2. D import clients finished
  3. E Catch exception when loading tensorflow model: simple_CNN.81-0.96.pb!
  4. T Traceback (most recent call last):
  5. T   File "rknn/api/rknn_base.py", line 136, in rknn.api.rknn_base.RKNNBase.load_tensorflow
  6. T   File "rknn/base/RKNNlib/converter/convert_tf.py", line 102, in rknn.base.RKNNlib.converter.convert_tf.convert_tf.__init__
  7. T   File "rknn/base/RKNNlib/converter/tensorflowloader.py", line 53, in rknn.base.RKNNlib.converter.tensorflowloader.TF_Graph_Preprocess.__init__
  8. T AttributeError: 'NoneType' object has no attribute 'op'
  9. Load Model failed!
复制代码
回复

使用道具 举报

jax.fang

中级会员

积分
371
5#
 楼主| 发表于 2019-7-4 16:18:54 | 只看该作者
TryYourBest 发表于 2019-7-4 10:15
将rknn = RKNN()改成rknn = RKNN(verbose = True)后,提示如下错误,多了第一行的D import~,由于知识 ...

TensorFlow版本是多少
回复

使用道具 举报

TryYourBest

注册会员

积分
77
6#
发表于 2019-7-4 16:45:21 | 只看该作者
jax.fang 发表于 2019-7-4 16:18
TensorFlow版本是多少

TensorFlow的版本是1.10.1的
回复

使用道具 举报

jax.fang

中级会员

积分
371
7#
 楼主| 发表于 2019-7-4 19:39:30 | 只看该作者
TryYourBest 发表于 2019-7-4 16:45
TensorFlow的版本是1.10.1的

这个模型用TensorFlow能加载吗?从报错的信息来看,TensorFlow加载这个模型就失败了。这个模型好像是用比较新的版本的TensorFlow导出的吧
回复

使用道具 举报

TryYourBest

注册会员

积分
77
8#
发表于 2019-7-5 09:56:27 | 只看该作者
jax.fang 发表于 2019-7-4 19:39
这个模型用TensorFlow能加载吗?从报错的信息来看,TensorFlow加载这个模型就失败了。这个模型好像是用比 ...

我PC用的是1.13.1的,我尝试下1.10版本的,支持开发板的tensorflow还有比1.10.1更高版本的么,网上找了找没找到
回复

使用道具 举报

allforgot

注册会员

积分
64
9#
发表于 2019-7-23 14:17:13 | 只看该作者
请问有人将这个项目移植到安卓上吗
回复

使用道具 举报

小宁哥

注册会员

积分
93
10#
发表于 2019-12-9 10:46:01 | 只看该作者
在image_demo里load_image 报错,invalid interpolation method,我改为opencv 读图后,结果图为空,是怎么回事
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表