tensorflow模型转化为caffe模型并调用预测

tensorflow模型转化为caffe模型并调用预测

本文一共分为三个部分首先根据tensorflow的网络结构代码写caffe的deploy.prototxt,再用python代码写XXXX.caffemodel文件,最后调用caffe模型进行预测.

根据tensorflow的网络结构代码写caffe的deploy.prototxt

写完之后可以将代码输入到这里(工具)检测写法是否正确:
验证工具
书写规则如下,我给的每一种类型的其参数是必须写的参数,如果想知道每一层更详细的参数,可以参考:caffe网络结构详解下载
Name是每一层的名字,top是经过这一层数据传向的层,bottom这一层的上一层数据
(1)输入层Input:

layer {
  name: "input"
  type: "Input"
  top: "data"
  input_param {
    shape {
      dim: 1
      dim: 32
      dim: 1
      dim: 1
    }
  }
}

一定要指定shape层,第一个dim为batchsize也就是一次性可以处理多少个数据,第二个dim为channel,如果处理的是图像也就是图片的通道数.如果处理的是向量,这个就是向量的长度,第三个dim为图像的高度,第四个dim为图像的宽度.如果是向量则第三第四都为1.
(2)全连接层InnerProduct

layer{
    name:"linear"
    type:"InnerProduct"
    bottom:"data"
    top:"linear"
    inner_product_param {
      num_output: 1024
   }
}

num_output是下一层向量数目
(3)BatchNorm层

layer {
   bottom: "linear"
   top: "bn1"
   name: "bn1"
   type: "BatchNorm"
   batch_norm_param {
      use_global_stats: true
   }
}

这个参数在测试阶段为true,在训练阶段为false
(4)Scale层

layer {
   bottom: "bn1"
   top: "bn1"
   name: "scale1"
   type: "Scale"
   scale_param {
      bias_term: true
   }
}

在转换模型的时候,tensorflow的一个 normalization layer相当于caffe的一个连续 batchNorm + Scale:
Convert batch normalization layer in tensorflow to caffe: 1 batchnorm layer in tf is equivalent to a successive of two layer : batchNorm + Scale:
(5)RELU

layer {
   bottom: "bn1"
   top: "ReLU1"
   name: "ReLU1"
   type: "ReLU"
}

(6)Eltwise

layer {
   bottom: "sum_up"
   bottom: "ReLU5"
   top: "sum_up2"
   name: "sum_up2"
   type:"Eltwise"
}

在残差网络中需要用这个层相加.

用python代码写模型参数文件

(1)读tensorflow的模型

import tensorflow as tf
sys.path.insert(0,"/path_to_caffe/python")
print(sys.path)
import caffe
import numpy as np
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))
from tensorflow.python import pywrap_tensorflow
checkpoint_path = "./checkpoint-4874200"
reader = pywrap_tensorflow.NewCheckpointReader(checkpoint_path)
var_to_shape_map = reader.get_variable_to_shape_map()

(在tensorflow较高版本中,模型文件三个 分别为xxx.meta xxxx.index xxx.0000-data-0001)
(2)创建caffe网络

cf_prototxt = "./2dto3d_deploy.prototxt"
net = caffe.Net(cf_prototxt, caffe.TEST)

(3)将参数读取写入
全解连接层的w和b

linear_w=np.squeeze(reader.get_tensor('linear_model/w1'))
tmp=np.linalg.norm(linear_w)
linear_w1=linear_w*1*(tmp>1)/tmp + linear_w*(tmp<=1)
net.params['linear'][0].data[:]=np.transpose(linear_w1, (1,0))
#在这里后两步是因为w做了w1 = tf.clip_by_norm(w1,1)
#这个操作具体可以参考:https://blog.csdn.net/wn87947/article/details/82345537
linear_b=np.squeeze(reader.get_tensor('linear_model/b1'))
net.params['linear'][1].data[:]=linear_b

BN层由于tensoflow和caffe有差异
在转化的时候记住caffe的bn+scale层等于tensorflow的bn层次
具体的转化有以下规则:

net.params[bn_name][0].data[:] = tf_movingmean
#epsilon 0.001 is the default value used by tf.contrib.layers.batch_norm!!
net.params[bn_name][1].data[:] = tf_movingvariance + 0.001
net.params[bn_name][2].data[:] = 1 # important, set it to be 1
net.params[scale_name][0].data[:] = tf_gamma
net.params[scale_name][1].data[:] = tf_beta

相关的具体讨论可以参考:bn层转化
下面给出bn层转化的一个试例

bn1_tf_movingmean=np.squeeze(reader.get_tensor('linear_model/batch_normalization/moving_mean'))
bn1_tf_movingvariance=np.squeeze(reader.get_tensor('linear_model/batch_normalization/moving_variance'))
bn1_tf_gamma=np.squeeze(reader.get_tensor('linear_model/batch_normalization/gamma'))
bn1_tf_beta=np.squeeze(reader.get_tensor('linear_model/batch_normalization/beta'))
net.params['bn1'][0].data[:] = bn1_tf_movingmean
# epsilon 0.001 is the default value used by tf.contrib.layers.batch_norm!!
net.params['bn1'][1].data[:] = bn1_tf_movingvariance+ 0.001
net.params['bn1'][2].data[:] = 1 # important, set it to be 1
net.params['scale1'][0].data[:] = bn1_tf_gamma
net.params['scale1'][1].data[:] = bn1_tf_beta

(3)最后写入文件

net.save('a.caffemodel')

调用caffe模型预测验证

import sys
sys.path.insert(0,"/path_to_caffe/python")
print(sys.path)
import caffe
import numpy as np
a=[-1.59036,2.64035,-1.84236,2.63166,-1.60718,4.62976,-1.53916,5.21137,-1.26383,2.65532,-1.29271,4.93954,-1.38703,5.27324,-1.58944,0.633358,-1.59042,1.12005,-1.53584,0.696239,-1.08071,0.598781,-0.603272,-0.938632,0.0140431,-2.17247,-1.89872,0.648127,-2.23398,-0.798227,-2.80334,-1.86967]
p2d=np.array(a)
y=np.reshape(p2d,(1,32,1,1))
caffe.set_mode_gpu()
model_def = './2dto3d_deploy.prototxt'
model_pretrained ='./a.caffemodel'
net = caffe.Net(model_def,model_pretrained,caffe.TEST)
net.blobs['data'].data[...]=y
out = net.forward() #前像传播预测
print (out)

以上测试数据的正确预测结果为:
{‘linear6’: array([[-1.1093297 , 0.13423912, -0.71337676, -0.3413014 , 0.60594785,
-0.503688 , -0.44055757, 0.61926687, -0.3807128 , 1.1093313 ,
-0.13424 , 0.7133761 , 0.57371044, 0.56901824, -0.12641048,
0.05005788, 0.47413373, 0.14192167, -0.3304365 , -0.7288994 ,
0.4668903 , 0.06698397, -0.6077603 , 0.33841628, 0.02581951,
-0.36136347, -0.09946679, 0.07204475, -0.29733503, 0.13283135,
0.85128194, -1.0867463 , 0.6229229 , 1.1905218 , -3.798849 ,
0.13268307, 1.8069856 , -3.7732291 , -0.5529848 , -0.9289112 ,
-0.9280683 , 0.14142033, -1.392531 , -2.9245243 , -0.55180794,
-1.8918784 , -2.9869053 , -1.0472283 ]], dtype=float32)}

附件下载

最后我给出了一个示例转换的所有文件附件下载地址
其中有如下内容:
(1) linear_model.py 为网络结构的定义文件可以参考这个文件的代码按照规则写出
(2) 2dto3d_deploy.prototxt
(3)checkpoint*文件是tensorflow模型文件
(4)caffe_script.py为写模型参数文件运行之后生产a.caffemodel
(5)predict.py根据2dto3d_deploy.prototxt和a.caffemodel进行预测看结果是否正确已经给出一组测试数据
(6)caffe网络模型深入理解各层详解.pdf


   转载规则


《tensorflow模型转化为caffe模型并调用预测》 ivory 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
C++程序中使用openpose预测关节点坐标的简易实现 C++程序中使用openpose预测关节点坐标的简易实现
C++程序中使用openpose预测关节点坐标的简易实现虽然在openpose的官网上已经给出了很多可用的demo,但是如果我们在自己的C++项目中想要使用openpose来预测三维关键点官网给出的例子不是很适用,所以我现在给出了C++程序
2019-07-08
下一篇 
Linux下科学上网和在终端中使用代理的方法 Linux下科学上网和在终端中使用代理的方法
Linux下科学上网和在终端中使用代理的方法1、SSGLOBAL SETTINGS$ git clone https://github.com/shadowsocksrr/shadowsocksr.git $ cd shadowsocksr
2019-07-08
  目录