背景:python端运用tensorFlow训练权重,很快速。c代码端为了获得更好的运行性能,只保留网络前馈运算的部分。

目的:将python端通过tensorFlow训练的权重输出出来,c端读取。

前期的工作:

MTCNN(三)基于python代码的网络结构更改

MTCNN(六)c代码网络结构的更改

目录

一、中间调试程序

1.1 c代码端输出中间结果

1.2 python端输出中间结果

二、原结构与原结构

2.1  读入tensorFlow模型与参数

2.2 创建相应文档

2.3 写入

Pconv1_w卷积核

Pconv1_b偏移

PPReLU1斜率

Pconv41_w全连接层

三、新结构


权重输出程序的实现:庄铭泳

一、中间调试程序

初期较多bug,无法很快实现权重转移。需要来回实验,将tensorFlow与c端代码的中间结果进行对比。所以需要输出TF与c端代码的中间结果,以便进行调试。

1.1 c代码端输出中间结果

MTCNN原程序自带输出中间结果的pBoxshow函数。

void pBoxShow(const struct pBox *pbox){
	if (pbox->pdata == NULL){
		cout << "pbox is NULL, please check it !" << endl;
		return;
	}
	cout << "the data is :" << endl;
	mydataFmt *p = pbox->pdata;
	//pbox->channel
	for (int channel = 0; channel < pbox->channel; channel++){
		cout << "the " << channel <<"th channel data is :"<< endl;
		//pbox->height
		for (int i = 0; i < pbox->height; i++){
			for (int k = 0; k < pbox->width; k++){
				cout << *p++ << " ";
			}
			cout << endl;
		}
	}
	p = NULL;
}

在c程序之中输出中间结果的值。

feature2Matrix(this->maxPooling1, this->maxPooling_matrix, this->conv2_wb);
convolution(this->conv2_wb, this->maxPooling1, this->conv2, this->maxPooling_matrix);
prelu(this->conv2, this->conv2_wb->pbias, this->prelu_gmma2->pdata);

printf("\n########################conv2 ##########################\n");    
pBoxShow(this->conv2);

 

1.2 python端输出中间结果

#PNet debug
   if(1==1):
       scale = scales[12]
       
       hs = int(np.ceil(h * scale))
       ws = int(np.ceil(w * scale))
       print("scale", scale, "hs", hs, "ws", ws)
       im_data = imresample(imgDebug, (hs, ws))
#        im_data = (im_data - 127.5) * (1. / 128.0)
       print("im_data.shape", im_data.shape)
       
       if(im_data.shape == (17, 21, 3)):
           print("orignal img ###########\n")
           for c in range(3):
               print("channel:",c)
               tempImg = []
               for y in range(17):
                   for x in range(21):
                       tempImg.append(im_data[y,x,c])
                   print(tempImg)
                   tempImg = []
               print("\n")
           print("\n\n\n")

 

二、原结构与原结构

MTCNN初始的程序为人脸识别程序,原结构与原结构需要验证对齐上。

2.1  读入tensorFlow模型与参数

import tensorflow as tf
#import cv2
#import numpy as np
import os
import struct
from src.mtcnn import PNet, RNet, ONet
from tools import get_model_filenames
os.environ["CUDA_VISIBLE_DEVICES"] = "3"

model_dir = "/1t_second/myzhuang2/MTCNN/wangbm_tf/save_model/sepatate/"
file_paths = get_model_filenames(model_dir)

with tf.device('/cpu'):
    with tf.Graph().as_default():
        config = tf.ConfigProto(allow_soft_placement=True)
        with tf.Session(config=config) as sess:
            if len(file_paths) == 3:
                image_pnet = tf.placeholder(
                    tf.float32, [None, None, None, 3])
                pnet = PNet({'data': image_pnet}, mode='test')
                out_tensor_pnet = pnet.get_all_output()

                image_rnet = tf.placeholder(tf.float32, [None, 24, 24, 3])
                rnet = RNet({'data': image_rnet}, mode='test')
                out_tensor_rnet = rnet.get_all_output()

                image_onet = tf.placeholder(tf.float32, [None, 48, 48, 3])
                onet = ONet({'data': image_onet}, mode='test')
                out_tensor_onet = onet.get_all_output()

                saver_pnet = tf.train.Saver(
                                [v for v in tf.global_variables()
                                 if v.name[0:5] == "pnet/"])
                saver_rnet = tf.train.Saver(
                                [v for v in tf.global_variables()
                                 if v.name[0:5] == "rnet/"])
                saver_onet = tf.train.Saver(
                                [v for v in tf.global_variables()
                                 if v.name[0:5] == "onet/"])

                saver_pnet.restore(sess, file_paths[0])

                def pnet_fun(img): return sess.run(
                    out_tensor_pnet, feed_dict={image_pnet: img})

                saver_rnet.restore(sess, file_paths[1])

                def rnet_fun(img): return sess.run(
                    out_tensor_rnet, feed_dict={image_rnet: img})

                saver_onet.restore(sess, file_paths[2])

                def onet_fun(img): return sess.run(
                    out_tensor_onet, feed_dict={image_onet: img})

2.2 创建相应文档

##PNET Params Write
           variable_names = [v.name for v in tf.global_variables()]
           pnet_var = []
           for var in variable_names:
               if 'pnet' in var:
                   pnet_var.append(var)
                   print(var)
           PnetOutFile = "Pnet.bin"
           PnetBinFile = open(PnetOutFile,'wb')
           print("tensorflow model load seccess")

           writeNum = 0

2.3 写入

Pconv1_w卷积核

Conv层输出顺序:先确定输出核(num_out_kerns),再确定输入核(num_in_map),再先列后行输出。相应顺序需要保持一致。此顺序为c代码端的顺序。注意相应TensorFlow的权重为Pconv1_w[ ky, kx ,num_in_map, num_out_map ]

可见TensorFlow之中权重的排列为[列数,行数,输入通道,输出通道]

#Pconv1_w
           Pconv1_w = sess.run(pnet_var[0])
           ky, kx, num_in_map, num_out_kerns = Pconv1_w.shape
           print(0,Pconv1_w.shape)
           for j in range(num_out_kerns):
               for i in range(num_in_map):
                   for y in range(ky):
                       for x in range(kx):
                           PnetBinFile.write(struct.pack('f', Pconv1_w[y,x,i,j]))
                           writeNum += 1

Pconv1_b偏移

Conv层偏置、PReLU层的输出顺序TF和C代码中一致,按照顺序输出即可.

#Pconv1_b
           Pconv1_b = sess.run(pnet_var[1])
           print(1,Pconv1_b.shape)
           for item in range(0,len(Pconv1_b[:])):
               PnetBinFile.write(struct.pack('f',Pconv1_b[item]))
               writeNum += 1

PPReLU1斜率

#PPReLU1
           PPReLU1 = sess.run(pnet_var[2])
           print(2,PPReLU1.shape)
           for item in range(0,len(PPReLU1[:])):
               PnetBinFile.write(struct.pack('f',PPReLU1[item]))
               writeNum += 1

Pconv41_w全连接层

全连接层输出按照先输出通道(num_out_kerns)再输入通道(num_in_map)。这是c代码之中的权重排列顺序。

TensorFlow之中的权重排列顺序为:[宽,高,输入通道,输出通道]

#Pconv41_b
           Pconv41_b = sess.run(pnet_var[10])
           print(10,Pconv41_b.shape)
           for item in range(0,len(Pconv41_b[:])):
               PnetBinFile.write(struct.pack('f',Pconv41_b[item]))
               writeNum += 1                
#Pconv42_w
           Pconv42_w = sess.run(pnet_var[11])
           print(11,Pconv42_w.shape)
           ky, kx, num_in_map, num_out_kerns = Pconv42_w.shape
           for j in range(num_out_kerns):
               for i in range(num_in_map):
                   for y in range(ky):
                       for x in range(kx):                    
                           PnetBinFile.write(struct.pack('f', Pconv42_w[y,x,i,j]))
                           writeNum += 1

三、新结构

人头数据集上python代码训练,并且测试成功,c端直接运用python端的网络结构来进行更改。

基本的层操作都一样,只要与同上的顺序输出即可