【深度学习】Caffe: tensorflow的模型到底怎么转成caffemodel??(完整的流程+代码讲解)
tensorflow的模型到底怎么转成caffemodel?
1. 简介
一般情况下,LZ是使用tensorflow的,好像之前在学校只要python跑通,benchmark再刷高一点就行了。现在在公司,要把自己的模型进行移植,之前是后端的移植,最近前端也提了需求,前端一般都是用海思芯片,只支持caffe,所以为了先测试时间得把tf的模型转成caffemodel。
程序猿总有不会的,总有要学习的不是嘛!
然后在网上搜索了很久,发现有些教程实在有些复杂,今天就以一个简单的网络结构为例,进行记录。说明这个网络中只包含卷积层和全连接层,后续碰到其他层会继续补充。
2. tensorflow模型准备
转换模型的第一步是不是得先准备个tensorflow的模型,没模型可以先随便训练个,有点参数和输出结果就行。经过训练后得到了对应的ckpt模型,因为后续要使用pycaffe搭建对应的网络,所以我们还得先查看下模型的名称
import numpy as np
import tensorflow as tf
#输出变量名和对应的参数
with tf.Session() as sess:
saver = tf.compat.v1.train.import_meta_graph('../models/model.ckpt.meta')
saver.restore(sess, tf.train.latest_checkpoint('../models/'))
for var in tf.compat.v1.trainable_variables():
print("*************************************")
print(var.name)
# print(np.array(sess.run(var)))
这段代码的目的就是为了看下保存的模型名称,当然如果把最后一行反注释,可以看到对应训练得到的weights和biases,所以对于一个公司来说,模型是非常重要的,在后端实际场景使用中还会转成pb模型并进行加密,这样即使对方得到了你的pb文件,也没法反解出对应的参数,但是如果是ckpt,可以看到查出网络结构和参数非常容易。
3. 生成对应的prototxt文件
之前因为不熟悉,都是单纯手动写prototxt,实在是太傻了,pycaffe可以轻松解决这个问题。
先写出主要的框架
import caffe
# 定义你的caffe网络结构
def deploy():
# 定义你的输入数据
data_img = caffe.layers.Input(shape=dict(dim=[1, 3, 102, 102]))
# 定义你的网络结构
# 网络结构要和你的tf模型完全一致,为了后续load参数方便,最好每层名字也对应一致
.
.
.
return caffe.to_proto(out)
# 定义一个函数,将网络结构写入到对应的prototxt中
def write_deploy():
with open('your_model.prototxt', 'w') as f:
f.write('name:"model_name"\n')
f.write(str(deploy()))
if __name__ == '__main__':
write_deploy()
4. 读取对应参数值,并生成对应的caffemodel
这个时候既需要tensorflow的接口,又需要caffe的接口了,生成prototxt的时候,我们已经获得了对应的网络结构了,下面只需要将对应的参数保存到caffe的params中就可以了
# load tf model_parameters
import tensorflow as tf
import numpy as np
import caffe
def generate_caffe_model():
cf_prototxt = "your_model.prototxt"
cf_model = "your_model.caffemodel"
# 定义自己的net
net = caffe.Net(cf_prototxt, caffe.TEST)
with tf.Session() as sess:
# 导入tf的网络结构和变量名称
saver = tf.train.import_meta_graph("../models/model.ckpt.meta",
clear_devices=True)
saver.restore(sess, tf.train.latest_checkpoint("../models/"))
all_vars = tf.trainable_variables()
# 针对不同变量,存储对应的参数
for var in all_vars:
name = var.name
v_param = np.array(sess.run(var))
print("*********************************")
# print(name, v_param.ndim, v_param.shape)
if 'weights' in name:
layer_name = name[:-10]#.strip("/weights:0")
print(layer_name)
if v_param.ndim == 4:
v_4d = np.transpose(v_param, [3, 2, 0, 1])
net.params[layer_name][0].data[...] = v_4d
print("conv weights {} succefully".format(layer_name))
else:
v_2d = np.transpose(v_param, [1, 0])
net.params[layer_name][0].data[...] = v_2d
print("fc weights {} succefully".format(layer_name))
elif 'biases' in name:
layer_name = name[:-9] #.strip("/biases:0")
net.params[layer_name][1].data[...] = v_param
print("{} biases succefully".format(layer_name))
else:
print("please check if something wrong !")
continue
# 保存caffemodel
net.save(cf_model)
print("\n -- Finished. -- \n")
转换的时候其实有好几个注意点。
a. 卷积
-
tensorflow卷积参数的存储方式是:
(kernel_h, kernel_w, input_channel, output_channel) -
caffe卷积参数的存储方式是:
(output_channel, input_channel, kernel_h, kernel_w) -
卷积的存储权重和偏差的位置:
权重存储的位置为:conv_params[conv][0]
偏差存储的位置为:conv_params[conv][1]
b. 全连接
- tensorflow全连接参数的存储方式是:
(input_dim, output_dim) - caffe全连接参数存储方式是:
(output_dim, input_dim) - 全连接的存储权重和偏差的位置:
权重存储的位置为:conv_params[fc][0]
偏差存储的位置为:conv_params[fc][1]
5. 验证模型转换是否成功
这时就需要使用tensorflow模型和caffe模型inference后的结果对比,caffe模型做deploy的代码框架:
# inference part
import caffe
import cv2
# some preprocess operation
def preprocess(img):
#定义一些预处理操作,尽量和tensorflow的预处理方式保持一致
return img
def deploy_part():
net_file = "your_model.prototxt"
caffe_model = "your_model.caffemodel"
test_dir = "test.bmp"
# 定义对应的网络
net = caffe.Net(net_file, caffe_model, caffe.TEST)
img = cv2.imread(test_dir)
img = preprocess(img)
img = img.transpose((2, 0, 1))
net.blobs['Input1'].data[...] = img
out = net.forward()
print(out)
if __name__ == '__main__':
deploy_part()
这里还有一个问题需要注意的是tensorflow的数据格式一般都是(N, H,W, C)的方式,而在caffe中是(N, C, H, W),opencv读入图片的格式为(H, W, C),所以在传入数据时需要使用transpose进行转换。
这个tensorflow inference后得到的结果:

这个是caffe deploy后得到的结果:

从上面两个图中可以看到两者结果的差异体现在小数点后第8位,并且这是最后数据的结果,基本上结果差异非常的小。
对于tensorflow转caffemodel,不知道小伙伴们有没有清楚一些呢?
更多推荐

所有评论(0)