背景: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端的网络结构来进行更改。
基本的层操作都一样,只要与同上的顺序输出即可