tensorflow模型转ncnn

第一步把tensorflow保存的.ckpt模型转为pb模型, 并记下模型的输入输出名字.
第二步去ncnn的github上把仓库clone下来, 按照上面的要求装好依赖并make.
第三步是修改ncnn的CMakeList, 具体修改的位置有:

  • ncnn/CMakeList.txt 文件, 在文件开头处加入add_definitions(-std=c++11), 末尾处加上add_subdirectory(examples), 如果ncnn没有examples文件夹,就新建一个, 并加上CMakeList.txt文件.
  • ncnn/tools/CMakeList.txt 文件, 加入add_subdirectory(tensorflow)

原版的tools/tensorflow/tensorflow2ncnn.cpp里, 不支持tensorflow的elu, FusedBathNormalization, Conv2dBackpropback操作, 其实elu是支持的,只需要仿照relu的格式, 在.cpp文件里加上就行. FusedBatchNormalization就是ncnn/layer/里实现的batchnorm.cpp, 只是`tensorflow2ncnn里没有写上, 可以增加下面的内容:

else if (node.op() == "FusedBatchNorm")
{
    fprintf(pp, "%-16s", "BatchNorm");
}
...
else if (node.op() == "FusedBatchNorm")
{
    std::cout << "node name is FusedBatchNorm" << std::endl;
    tensorflow::TensorProto tensor;
    find_tensor_proto(weights, node, tensor);
    const tensorflow::TensorShapeProto& shape = tensor.tensor_shape();

    const tensorflow::TensorProto& gamma = weights[node.input(1)];
    const tensorflow::TensorProto& Beta = weights[node.input(2)];
    const tensorflow::TensorProto& mean = weights[node.input(3)];
    const tensorflow::TensorProto& var = weights[node.input(4)];

    int channels = gamma.tensor_shape().dim(0).size(); // data size
    int dtype = gamma.dtype();

    switch (dtype){
        case 1: 
        {

            const float * gamma_tensor = reinterpret_cast(gamma.tensor_content().c_str());
            const float * mean_data = reinterpret_cast(mean.tensor_content().c_str());
            const float * var_data = reinterpret_cast(var.tensor_content().c_str());
            const float * b_data = reinterpret_cast(Beta.tensor_content().c_str());
            for (int i=0; i< channels; ++i)
            {
                fwrite(gamma_tensor+i, sizeof(float), 1, bp);
            }
            for (int i=0; i< channels; ++i)
            {
                fwrite(mean_data+i, sizeof(float), 1, bp);
            }
            for (int i=0; i< channels; ++i)
            {
                fwrite(var_data+i, sizeof(float), 1, bp);
            }
            for (int i=0; i< channels; ++i)
            {
                fwrite(b_data+i, sizeof(float), 1, bp);
            }
        }
        default:
            std::cerr << "Type is not supported." << std::endl;

    }
    fprintf(pp, " 0=%d", channels);

    tensorflow::AttrValue value_epsilon;
    if (find_attr_value(node, "epsilon", value_epsilon)){
        float epsilon = value_epsilon.f();
        fprintf(pp, " 1=%f", epsilon);
    }
}

同理, Conv2dBackpropback其实就是ncnn里的反卷积操作, 只不过ncnn实现反卷积的操作和tensorflow内部实现反卷积的操作过程不一样, 但结果是一致的, 需要仿照普通卷积的写法加上去.

ncnn同样支持空洞卷积, 但无法识别tensorflow的空洞卷积, 具体原理可以看tensorflow空洞卷积的原理, tensorflow是改变featuremap做空洞卷积, 而ncnn是改变kernel做空洞卷积, 结果都一样. 需要对.proto文件修改即可完成空洞卷积.

总之ncnn对tensorflow的支持很不友好, 有的层还需要自己手动去实现, 还是很麻烦.

你可能感兴趣的:(tensorflow)