Tensorflow模型转caffe模型再转ncnn模型

Tensorflow模型转caffe模型再转ncnn模型

Tensorflow模型转caffe模型网上有很多教程,我参照这个https://blog.csdn.net/weixin_42699651/article/details/88932597,成功把例子vgg_16.ckpt转换为vgg16.caffemodel。

一、Tensorflow模型转caffe模型

接下来我就要因地制宜了,尝试把MTCNN的tensorflow最终转换为caffe的模型。
以MTCNN的第一层网络P-Net为例:

已知条件

tensorflow训练出的P-Net模型:
在这里插入图片描述
1、.meta文件保存了网络结构的定义
2、.data-00000-of-00001文件和.index文件合在一起组成了ckpt文件,保存了网络结构中所有的权重和偏执的数值。.data文件保存的是变量值,.index文件保存的是.data文件中的数据和.meta文件中结构图之间的映射关系
3、.checkpoint是一个文本文件,记录了训练过程中所有中间节点上保存的模型名称,首行记录的是最后一次保存的模型名称。
参考:https://blog.csdn.net/c20081052/article/details/82961988

P-Net的caffe网络文件:
在这里插入图片描述

开始转换

新建一个文件夹,文件夹里分别存放以上五个文件,另加一个转换脚本tf2caffe.py,脚本代码如下:

import sys
import tensorflow as tf
import caffe
import numpy as np
import cv2
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))

from tensorflow.python import pywrap_tensorflow
checkpoint_path = "./pnet-3000000.index"
reader = pywrap_tensorflow.NewCheckpointReader(checkpoint_path)
var_to_shape_map = reader.get_variable_to_shape_map()


cf_prototxt = "./det1.prototxt"
cf_model = "./pnet.caffemodel"


def tensor4d_transform(tensor):
    return tensor.transpose((3, 2, 0, 1))
def tensor2d_transform(tensor):
    return tensor.transpose((1, 0))

def tf2caffe(checkpoint_path,cf_prototxt,cf_model):
    net = caffe.Net(cf_prototxt, caffe.TRAIN)
    for key_i in var_to_shape_map:

        try:

            if 'data' in key_i:
                pass
            elif 'weights' in key_i:
                a = key_i.split('/')
                if (len(a) == 3):
                    key_caffe = a[1]
                else:
                    key_caffe = a[2]
                if (reader.get_tensor(key_i).ndim == 4):
                    if (key_caffe == 'fc6'):
                        weights = tensor4d_transform(reader.get_tensor(key_i).reshape([7, 7, 512, 4096])).reshape(
                            [[7, 7, 512, 4096][3], -1])
                    elif key_caffe == 'fc7':
                        a = np.squeeze(reader.get_tensor(key_i)[0][0])
                        weights = tensor2d_transform(a)  # 2dim
                    elif key_caffe == 'fc8':
                        a = np.squeeze(reader.get_tensor(key_i)[0][0])
                        weights = tensor2d_transform(a)  # 2dim
                    else:
                        weights = tensor4d_transform(reader.get_tensor(key_i))
                net.params[key_caffe][0].data.flat = weights.flat
            elif 'biases' in key_i:
                a = key_i.split('/')
                if (len(a) == 3):
                    key_caffe = a[1]
                else:
                    key_caffe = a[2]
                net.params[key_caffe][1].data.flat = reader.get_tensor(key_i).flat
            elif 'mean_rgb' in key_i:
                pass
            elif 'global' in key_i:
                pass
            else:
                sys.exit("Warning!  Unknown tf:{}".format(key_i))
        except KeyError:
            print("\nWarning!  key error tf:{}".format(key_i))
    net.save(cf_model)
    print("\n- Finished.\n")

if __name__ == '__main__':
    tf2caffe(checkpoint_path, cf_prototxt, cf_model)

重点:

checkpoint_path = "./vgg_16.ckpt"

然而我并没有.ckpt文件,所以我改为:

checkpoint_path = "./pnet-3000000"

因为不同的网络层名,维度都不一样,所以tf2caffe.py需要根据自己要转换的网络进行修改,注意key_caffe和key_i是否要修改,建议把tf2caffe.py的脚本搞懂再进行修改,可以参考我特地为tf2caffe.py写的解析博文。

转换完成后,文件夹里多了一个p-net.caffemodel文件,如下图:
Tensorflow模型转caffe模型再转ncnn模型_第1张图片

二、转caffe模型转ncnn模型

新建一个文件夹,存放上一步转换完成的caffemodel和已知的.prototxt文件
依次执行命令:

1~/caffe/build/tools/upgrade_net_proto_text det1.prototxt new_det1.prototxt

2~/caffe/build/tools/upgrade_net_proto_binary det1.caffemodel new_det1.caffemodel

3~/liq/ncnn/build/tools/caffe/caffe2ncnn new_det1.prototxt new_det1.caffemodel det1.param det1.bin

成功转换将得到

det1.param 和 det1.bin

再详细的步骤可以参考我的另一篇博文caffe转ncnn
正文就到这里结束了,下面是后续

三、验证Tensorflow转caffe再转ncnn的最终模型是否可以被ncnn成功加载

把基于ncnn框架的mtcnn的工程,测试图片的模型加载更换成自己的,好消息是:模型可以被成功加载,并没有报错;坏消息是加载的模型效果很差,并没有检测出人脸。
模型更换前后对比:

Tensorflow模型转caffe模型再转ncnn模型_第2张图片
找原因,发现
det1.param文件和原作者给的是一模一样的,更换后,可以成功加载人脸。所以问题出在det1.bin身上。博主想查看一下具体的bin文件到底哪里不一样,导致没有读出人脸
将det1.bin文件转化为.txt文件,代码:

import struct
import os
if __name__ == '__main__':
    filepath='C:\\Users\\lhh\\Desktop\\det\\det1_2.bin'
    f = open("C:\\Users\\lhh\\Desktop\\det\\det1_2.txt", "w")
    binfile = open(filepath, 'rb') #打开二进制文件
    size = os.path.getsize(filepath) #获得文件大小
    for i in range(size):
        data = binfile.read(10) #每次输出一个字节
        f.write(str(data))
        f.write('\n')
        #print(data)
    binfile.close()

发现果然二者不一样,但也看不出来是什么原因:
在这里插入图片描述
那转化为10进制再看看呢?代码如下:

import struct
import os
if __name__ == '__main__':
    filepath='C:\\Users\\lhh\\Desktop\\det\\det1_1.bin'
    f = open("C:\\Users\\lhh\\Desktop\\det\\det1_1.txt", "w")
    binfile = open(filepath, 'rb') #打开二进制文件
    size = os.path.getsize(filepath) #获得文件大小
    for i in range(size):
        data = binfile.read(1) #每次输出一个字节
        num = struct.unpack('B', data)
        f.write(str(num[0]))
        f.write('\n')
        #print(data)
    binfile.close()

现在就很明确了,行数相同,但是每一行的数都不一样:
Tensorflow模型转caffe模型再转ncnn模型_第3张图片

分析

将ncnn原始工程给的caffemodel经过caffe转ncnn之后,得到的结果和原工程提供的.bin和.param是一模一样的,所以转换的第二步没有问题。

关键是第一步:TensorFlow转caffe:
情况1:转换步骤tf2caffe.py不对
情况2: 转换源文件pnet-3000000.index,pnet-300000.meta,pnet-3000000.data-00000-of-00001本身效果就不好

到底是情况1还是情况2,博主最终也不知道。

你可能感兴趣的:(MTCNN)