Caffe2 - (七)Caffemodel 转换为 Caffe2 pb 模型

本文介绍了如何使用Caffe2的caffe_translator.py工具将Caffemodel转换为Caffe2的.pb模型,详细讲解了单输入单输出的转换过程,并提到对于多输入多输出模型,需要对原工具进行修改。
摘要由CSDN通过智能技术生成

Caffe2 - Caffemodel 转换为 Caffe2 pb 模型

1. 单输入单输出 - caffe_translator.py

Caffe2 提供了将 caffemodel 转换为 caffe2 模型的工具——caffe_translator.py.

其使用:

python -m caffe2.python.caffe_translator deploy.prototxt pretrained.caffemodel

即得到 caffe2 的模型:init_net.pbpredict_net.pb.

现在支持转换的网络层有:

  1. Input
  2. VideoData
  3. Data
  4. Convolution3D
  5. Convolution
  6. Deconvolution
  7. Crop
  8. ReLU
  9. Pooling
  10. Pooling3D
  11. LRN
  12. InnerProduct
  13. Dropout
  14. Softmax
  15. SoftmaxWithLoss
  16. Accuracy
  17. Concat
  18. TanH
  19. InstanceNorm
  20. BatchNorm
  21. Eltwise
  22. Scale
  23. Reshape
  24. Sigmoid
  25. ROIPooling
  26. PReLU
  27. Reduction

2. 多输入多输出

Caffe2 提供的模型转换工具貌似只支持单输入单输出,由于自己的网络模型有多个输入多个输出,故,基于caffe_translator.py 进行修改,得到新的 caffe_translator_multi.py:

# ----------------------------------
# caffe_translator_multi.py
# multi-inputs, multi-outputs
# ----------------------------------
#!/usr/bin/env python

import argparse
import copy
import logging
import re
import numpy as np  # noqa

import sys
sys.path.insert(0, '/path/to/caffe2/build')

from caffe2.proto import caffe2_pb2, caffe2_legacy_pb2
from caffe.proto import caffe_pb2
from caffe2.python import core, utils, workspace
from google.protobuf import text_format

logging.basicConfig()
log = logging.getLogger("caffe_translator")
log.setLevel(logging.INFO)


def _StateMeetsRule(state, rule):
    """A function that reproduces Caffe's StateMeetsRule functionality."""
    if rule.HasField('phase') and rule.phase != state.phase:
        return False
    if rule.HasField('min_level') and state.level < rule.min_level:
        return False
    if rule.HasField('max_level') and state.level > rule.max_level:
        return False
    curr_stages = set(list(state.stage))
    # all stages in rule.stages should be in, otherwise it's not a match.
    if len(rule.stage) and any([s not in curr_stages for s in rule.stage]):
        return False
    # none of the stage in rule.stages should be in, otherwise it's not a match.
    if len(rule.not_stage) and any([s in curr_stages for s in rule.not_stage]):
        return False
    # If none of the nonmatch happens, return True.
    return True


def _ShouldInclude(net_state, layer):
    """A function that reproduces Caffe's inclusion and exclusion rule."""
    ret = (len(layer.include) == 0)
    # check exclude rules: if any exclusion is met, we shouldn't include.
    ret &= not any([_StateMeetsRule(net_state, rule) for rule in layer.exclude])
    if len(layer.include):
        # check include rules: if any inclusion is met, we should include.
        ret |= any([_StateMeetsRule(net_state, rule) for rule in layer.include])
    return ret


def _GetLegacyDims(net, net_params, dummy_input, legacy_pad_ops):
    dim_map = {}
    ws = workspace.C.Workspace()
    for param in net_params.protos:
        ws.create_blob(param.name) \
            .feed(utils.Caffe2TensorToNumpyArray(param))
    external_input = net.op[0].input[0]
    ws.create_blob(external_input).feed(dummy_input)
    # Get dimensions with legacy pad
    for i in range(len(net.op)):
        op_def = net.op[i]
        ws._run_operator(op_def.SerializeToString())
        if i in legacy_pad_ops:
            output = op_def.output[0]
            blob_legacy = ws.fetch_blob(output)
            dim_map[i] = blob_legacy.shape
    return dim_map


def _GetLegacyPadArgs(op_def, arg_map):
    pads = {}
    keys = ['pad_l', 'pad_t', 'pad_r', 'pad_b']
    is_pad = 'pad' in arg_map
    if is_pad:
        for k in keys:
            pads[k] = arg_map['pad'].i
    else:
        pads = {x: arg_map[x].i for x in keys}
    return pads


def _AdjustDims(op_def, arg_map, pads, dim1, dim2):
    n1, c1, h1, w1 = dim1
    n2, c2, h2, w2 = dim2
    assert(n1 == n2)
    assert(c1 == c2)
    is_pad = 'pad' in arg_map
    if h1 != h2 or w1 != w2:
        if h1 == h2 + 1:
            pads['pad_b'] += 1
        elif h1 != h2:
            raise Exception("Unexpected dimensions for height:", h1, h2)
        if w1 == w2 + 1:
            pads['pad_r'] += 1
        elif w1 != w2:
            raise Exception("Unexpected dimensions for width:", w1, w2)
        if is_pad:
            op_def.arg.remove(arg_map['pad'])
            args = []
            for name in pads.keys():
                arg = caffe2_pb2.Argument()
                arg.name = name
                arg.i = pads[name]
                args.append(arg)
            op_def.arg.extend(args)
        else:
            for name in pads.keys():
                arg_map[name].i = pads[name]


def _RemoveLegacyPad(net, net_params, input_dims):
    legacy_pad_ops = []
    for i in range(len(net.op)):
        op_def = net.op[i]
        if re.match(r'^(Conv|ConvTranspose|MaxPool|AveragePool)(\dD)?$',
                    op_def.type):
            for arg in op_def.arg:
                if arg.name == 'legacy_pad':
                    legacy_pad_ops.append(i)
                    break
    if legacy_pad_ops:
        n, c, h, w = input_dims
        dummy_input = np.random.randn(n, c, h, w).astype(np.float32)
        dim_map = _GetLegacyDims(net, net_params, dummy_input, legacy_pad_ops)

        # Running with the legacy pad argument removed
        # compare the dimensions and adjust pad argument when necessary
        ws = workspace.C.Workspace()

        external_input = net.op[0].input[0]
        ws.create_blob(external_input).feed_blob(dummy_input)
        for param in net_params.protos:
            ws.create_blob(param.name) \
              .feed_blob(utils.Caffe2TensorToNumpyArray(param))

        for i in range(len(net.op)):
            op_def = net.op[i]
            if i in legacy_pad_ops:
                arg_map = {}
                for arg in op_def.arg:
                    arg_map[arg.name] = arg
                pads = _GetLegacyPadArgs(op_def, arg_map)
                # remove legacy pad arg
                for j in range(len(op_def.arg)):
                    arg = op_def.arg[j]
                    if arg.name == 'legacy_pad':
                        del op_def.arg[j]
                        break
                output = op_def.output[0]
                # use a new name to avoid the interference with inplace
                nonlegacy_output = output + '_nonlegacy'
                op_def.output[0] = nonlegacy_output
                ws._run_operator(op_def.SerializeToString())
                blob_nonlegacy = ws.fetch_blob(nonlegacy_output)
                # reset output name
                op_def.output[0] = output

                dim1 = dim_map[i]
                dim2 = blob_nonlegacy.shape
                _AdjustDims(op_def, arg_map, pads, dim1, dim2)

            ws._run_operator(op_def.SerializeToString())
    return net


def _GetBlobDimMap(net, net_params, dummy_input):
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
将TensorFlow模型转换Caffe2模型可以按照以下步骤进行: 1. 将TensorFlow模型导出为SavedModel格式:使用TensorFlow的`tf.saved_model.save`函数将TensorFlow模型保存为SavedModel格式。 ```python import tensorflow as tf # 加载TensorFlow模型 model = tf.keras.applications.ResNet50(weights='imagenet') # 保存为SavedModel格式 saved_model_path = './saved_model' tf.saved_model.save(model, saved_model_path) ``` 2. 使用Caffe2的tf2caffe工具进行转换Caffe2提供了一个tf2caffe工具,可以将SavedModel转换Caffe2模型。你需要克隆Caffe2的GitHub仓库,并根据官方文档的说明进行安装和配置。 ```bash git clone https://github.com/pytorch/pytorch.git cd pytorch git submodule update --init cd caffe2 mkdir build cd build cmake .. make ``` 3. 运行tf2caffe转换脚本:在Caffe2的build目录下,使用tf2caffe转换脚本将SavedModel转换Caffe2模型。 ```bash ./build/tools/tf2caffe \ --data-output-path caffe_model/data \ --code-output-path caffe_model/model \ --net-output-path caffe_model/model.prototxt \ --init-net-output-path caffe_model/init_net.pb \ --predict-net-output-path caffe_model/predict_net.pb \ --input-dim 1,224,224,3 \ --input-type float \ --input-name input \ --output-name output \ --input-blob-name input_blob \ --output-blob-name output_blob \ --caffe-weights caffe_model/caffe_weights.caffemodel \ --tensorflow-model-path saved_model ``` 通过以上步骤,你就可以将TensorFlow模型转换Caffe2模型转换后的Caffe2模型将包含模型结构和参数,并可以在Caffe2中进行推理操作。请注意,转换过程中可能需要处理一些兼容性问题,因为TensorFlow和Caffe2具有不同的特性和支持的操作集。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值