def _parse_proto(prototxt_fname):
    """Parse Caffe prototxt into symbol string
    """
    proto = caffe_parser.read_prototxt(prototxt_fname)

    # process data layer
    input_name, input_dim, layers = _get_input(proto)
    # only support single input, so always use `data` as the input data
    mapping = {input_name: 'data'}
    need_flatten = {input_name: False}
    symbol_string = "import mxnet as mx\ndata = mx.symbol.Variable(name='data')\n"

    flatten_count = 0
    output_name = ""
    prev_name = None

    # convert reset layers one by one
    for i, layer in enumerate(layers):
        type_string = ''
        param_string = ''
        skip_layer = False
        bottom_order = []
        name = re.sub('[-/]', '_', layer.name)
        if layer.type == 'Convolution' or layer.type == 4:
            type_string = 'mx.symbol.Convolution'
            param_string = _convert_conv_param(layer.convolution_param)
            need_flatten[name] = True
        if layer.type == 'Deconvolution' or layer.type == 39:
            type_string = 'mx.symbol.Deconvolution'
            param_string = _convert_conv_param(layer.convolution_param)
            need_flatten[name] = True
        if layer.type == 'Pooling' or layer.type == 17:
            type_string = 'mx.symbol.Pooling'
            param_string = _convert_pooling_param(layer.pooling_param)
            need_flatten[name] = True
        if layer.type == 'ReLU' or layer.type == 18:
            type_string = 'mx.symbol.Activation'
            param_string = "act_type='relu'"
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'TanH' or layer.type == 23:
            type_string = 'mx.symbol.Activation'
            param_string = "act_type='tanh'"
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'Sigmoid' or layer.type == 19:
            type_string = 'mx.symbol.Activation'
            param_string = "act_type='sigmoid'"
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'LRN' or layer.type == 15:
            type_string = 'mx.symbol.LRN'
            param = layer.lrn_param
            param_string = "alpha=%f, beta=%f, knorm=%f, nsize=%d" % (
                param.alpha, param.beta, param.k, param.local_size)
            need_flatten[name] = True
        if layer.type == 'InnerProduct' or layer.type == 14:
            type_string = 'mx.symbol.FullyConnected'
            param = layer.inner_product_param
            param_string = "num_hidden=%d, no_bias=%s" % (
                param.num_output, not param.bias_term)
            need_flatten[name] = False
        if layer.type == 'Dropout' or layer.type == 6:
            type_string = 'mx.symbol.Dropout'
            param = layer.dropout_param
            param_string = "p=%f" % param.dropout_ratio
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'Softmax' or layer.type == 20:
            if layer.softmax_param.axis == 2:
                symbol_string += "%s = mx.symbol.transpose(%s, axes=(0,2,1))\n" %\
                    (mapping[layer.bottom[0]], mapping[layer.bottom[0]])
                type_string = 'mx.symbol.SoftmaxActivation'
                param_string = "mode='channel'"
                need_flatten[name] = False
            else:
                type_string = 'mx.symbol.SoftmaxOutput'
        if layer.type == 'Flatten' or layer.type == 8:
            if 'softmax' in layer.bottom[0]:
                prev_name = re.sub('[-/]', '_', layers[i-1].name)
                skip_layer = True
            else:
                type_string = 'mx.symbol.Flatten'
            need_flatten[name] = False
        if layer.type == 'Split' or layer.type == 22:
            type_string = 'split'  # will process later
        if layer.type == 'Concat' or layer.type == 3:
            type_string = 'mx.symbol.Concat'
            need_flatten[name] = True
        if layer.type == 'Crop':
            type_string = 'mx.symbol.Crop'
            need_flatten[name] = True
            param_string = 'center_crop=True'
        if layer.type == 'BatchNorm':
            type_string = 'mx.symbol.BatchNorm'
            param = layer.batch_norm_param
            # CuDNN requires eps to be greater than 1e-05
            # We compensate for this change in convert_model
            epsilon = param.eps
            if (epsilon <= 1e-05):
                epsilon = 1e-04
            # if next layer is scale, don't fix gamma
            fix_gamma = layers[i+1].type != 'Scale'
            param_string = 'use_global_stats=%s, fix_gamma=%s, eps=%f' % (
                param.use_global_stats, fix_gamma, epsilon)
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'Scale':
            assert layers[i-1].type == 'BatchNorm'
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
            skip_layer = True
            prev_name = re.sub('[-/]', '_', layers[i-1].name)
        if layer.type == 'PReLU':
            type_string = 'mx.symbol.LeakyReLU'
            param = layer.prelu_param
            param_string = "act_type='prelu', slope=%f" % param.filler.value
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'Eltwise':
            type_string = 'mx.symbol.broadcast_add'
            param_string = ""
            need_flatten[name] = False
        if layer.type == 'Reshape':
            type_string = 'mx.symbol.Reshape'
            param = layer.reshape_param
            param_string = 'shape=(' + ','.join([str(x) for x in list(param.shape.dim)]) + ')'
            need_flatten[name] = True
        if layer.type == 'AbsVal':
            type_string = 'mx.symbol.abs'
            need_flatten[name] = need_flatten[mapping[layer.bottom[0]]]
        if layer.type == 'Normalize':
            bottom = re.sub('[-/]', '_', layer.bottom[0])
            conv_layer = _find_layer(layers, bottom)
            assert conv_layer is not None
            param = layer.norm_param
            assert not param.across_spatial and not param.channel_shared
            assert param.scale_filler.type == 'constant'
            if conv_layer.type == 'Convolution':
                scale_name = "%s_scale" % name
                symbol_string += "%s=mx.sym.Variable(name='%s', shape=(1, %d, 1, 1), init=mx.init.Constant(%f))\n" % \
                    (scale_name, scale_name, conv_layer.convolution_param.num_output,
                    param.scale_filler.value)
                symbol_string += "%s=mx.symbol.L2Normalization(name='%s', data=%s, mode='channel')\n" %\
                    (name, name, mapping[layer.bottom[0]])
                symbol_string += "%s=mx.symbol.broadcast_mul(lhs=%s, rhs=%s)\n" %\
                    (name, scale_name, name)
                type_string = 'split'
                need_flatten[name] = True
            else:
                raise ValueError('Unknown/Invalid normalize layer!')
        if layer.type == 'Permute':
            type_string = 'mx.symbol.transpose'
            param_string = "axes=(%s)" % (','.join([str(x) for x in layer.permute_param.order]))
            need_flatten[name] = True
            from_name = ''
        if layer.type == 'PriorBox':
            param = layer.prior_box_param
            if layer.bottom[0] == 'data':
                bottom_order = [1]
            else:
                bottom_order = [0]
            try:
                import math
                min_size = param.min_size[0] / input_dim[2]
                max_size = math.sqrt(param.min_size[0] * param.max_size[0]) / input_dim[2]
                sizes = '(%f, %f)' %(min_size, max_size)
            except AttributeError:
                min_size = param.min_size[0] / input_dim[2]
                sizes = '(%f)' %(min_size)
            ars = list(param.aspect_ratio)
            ratios = [1.]
            for ar in ars:
                ratios.append(ar)
                if param.flip:
                    ratios.append(1. / ar)
            ratios_string = '(' + ','.join(str(x) for x in ratios) + ')'
            clip = param.clip
            if (param.step_h > 0 or param.step_w > 0):
                step_h = param.step_h
                step_w = param.step_w
            elif param.step > 0:
                step_h = param.step
                step_w = param.step
            else:
                step_h = -1
                step_w = -1
            finput_dimh = float(input_dim[2])
            finput_dimw = float(input_dim[3])
            step = '(%f, %f)' % (step_h / finput_dimh, step_w / finput_dimw)
            assert param.offset == 0.5, "currently only support offset = 0.5"
            symbol_string += '%s = mx.contrib.symbol.MultiBoxPrior(%s, sizes=%s, ratios=%s, clip=%s, steps=%s, name="%s")\n' % \
                (name, mapping[layer.bottom[0]], sizes, ratios_string, clip, step, name)
            symbol_string += '%s = mx.symbol.Flatten(data=%s)\n' % (name, name)
            type_string = 'split'
            need_flatten[name] = False
        if layer.type == 'DetectionOutput':
            bottom_order = [1, 0, 2]
            param = layer.detection_output_param
            assert param.share_location == True
            assert param.background_label_id == 0
            nms_param = param.nms_param
            type_string = 'mx.contrib.symbol.MultiBoxDetection'
            param_string = "nms_threshold=%f, nms_topk=%d, clip=False" % \
                (nms_param.nms_threshold, nms_param.top_k)
        if skip_layer:
            assert len(layer.bottom) == 1
            symbol_string += "%s = %s\n" % (name, prev_name)
        elif type_string == '':
            raise ValueError('Unknown layer %s!' % layer.type)
        elif type_string != 'split':
            bottom = layer.bottom
            if param_string != "":
                param_string = ", " + param_string
            if len(bottom) == 1:
                # print(need_flatten)
                if need_flatten[mapping[bottom[0]]] and type_string == 'mx.symbol.FullyConnected':
                    flatten_name = "flatten_%d" % flatten_count
                    symbol_string += "%s=mx.symbol.Flatten(name='%s', data=%s)\n" % (
                        flatten_name, flatten_name, mapping[bottom[0]])
                    flatten_count += 1
                    need_flatten[flatten_name] = False
                    bottom[0] = flatten_name
                    mapping[bottom[0]] = bottom[0]
                symbol_string += "%s = %s(name='%s', data=%s %s)\n" % (
                    name, type_string, name, mapping[bottom[0]], param_string)
            else:
                if not bottom_order:
                    bottom_order = range(len(bottom))
                symbol_string += "%s = %s(name='%s', *[%s] %s)\n" % \
                                 (name, type_string, name, ','.join([mapping[bottom[x]] for x in bottom_order]), param_string)
                if layer.type == 'Concat' and layer.concat_param.axis == 2:
                    symbol_string += "%s = mx.symbol.Reshape(data=%s, shape=(0, -1, 4), name='%s')\n" %\
                        (name, name, name)
        for j in range(len(layer.top)):
            mapping[layer.top[j]] = name
        output_name = name
    return symbol_string, output_name, input_dim
def _parse_proto ( prototxt_fname ) : proto = caffe_parser . read_prototxt ( prototxt_fname ) input_name , input_dim , layers = _get_input ( proto ) mapping = { input_name : 'data' } need_flatten = { input_name : False } symbol_string = "import mxnet as mx\ndata = mx.symbol.Variable(name='data')\n" flatten_count = 0 output_name = "" prev_name = None for i , layer in enumerate ( layers ) : type_string = '' param_string = '' skip_layer = False bottom_order = [ ] name = re . sub ( '[-/]' , '_' , layer . name ) if layer . type == 'Convolution' or layer . type == 4 : type_string = 'mx.symbol.Convolution' param_string = _convert_conv_param ( layer . convolution_param ) need_flatten [ name ] = True if layer . type == 'Deconvolution' or layer . type == 39 : type_string = 'mx.symbol.Deconvolution' param_string = _convert_conv_param ( layer . convolution_param ) need_flatten [ name ] = True if layer . type == 'Pooling' or layer . type == 17 : type_string = 'mx.symbol.Pooling' param_string = _convert_pooling_param ( layer . pooling_param ) need_flatten [ name ] = True if layer . type == 'ReLU' or layer . type == 18 : type_string = 'mx.symbol.Activation' param_string = "act_type='relu'" need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'TanH' or layer . type == 23 : type_string = 'mx.symbol.Activation' param_string = "act_type='tanh'" need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'Sigmoid' or layer . type == 19 : type_string = 'mx.symbol.Activation' param_string = "act_type='sigmoid'" need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'LRN' or layer . type == 15 : type_string = 'mx.symbol.LRN' param = layer . lrn_param param_string = "alpha=%f, beta=%f, knorm=%f, nsize=%d" % ( param . alpha , param . beta , param . k , param . local_size ) need_flatten [ name ] = True if layer . type == 'InnerProduct' or layer . type == 14 : type_string = 'mx.symbol.FullyConnected' param = layer . inner_product_param param_string = "num_hidden=%d, no_bias=%s" % ( param . num_output , not param . bias_term ) need_flatten [ name ] = False if layer . type == 'Dropout' or layer . type == 6 : type_string = 'mx.symbol.Dropout' param = layer . dropout_param param_string = "p=%f" % param . dropout_ratio need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'Softmax' or layer . type == 20 : if layer . softmax_param . axis == 2 : symbol_string += "%s = mx.symbol.transpose(%s, axes=(0,2,1))\n" % ( mapping [ layer . bottom [ 0 ] ] , mapping [ layer . bottom [ 0 ] ] ) type_string = 'mx.symbol.SoftmaxActivation' param_string = "mode='channel'" need_flatten [ name ] = False else : type_string = 'mx.symbol.SoftmaxOutput' if layer . type == 'Flatten' or layer . type == 8 : if 'softmax' in layer . bottom [ 0 ] : prev_name = re . sub ( '[-/]' , '_' , layers [ i - 1 ] . name ) skip_layer = True else : type_string = 'mx.symbol.Flatten' need_flatten [ name ] = False if layer . type == 'Split' or layer . type == 22 : type_string = 'split' if layer . type == 'Concat' or layer . type == 3 : type_string = 'mx.symbol.Concat' need_flatten [ name ] = True if layer . type == 'Crop' : type_string = 'mx.symbol.Crop' need_flatten [ name ] = True param_string = 'center_crop=True' if layer . type == 'BatchNorm' : type_string = 'mx.symbol.BatchNorm' param = layer . batch_norm_param epsilon = param . eps if ( epsilon <= 1e-05 ) : epsilon = 1e-04 fix_gamma = layers [ i + 1 ] . type != 'Scale' param_string = 'use_global_stats=%s, fix_gamma=%s, eps=%f' % ( param . use_global_stats , fix_gamma , epsilon ) need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'Scale' : assert layers [ i - 1 ] . type == 'BatchNorm' need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] skip_layer = True prev_name = re . sub ( '[-/]' , '_' , layers [ i - 1 ] . name ) if layer . type == 'PReLU' : type_string = 'mx.symbol.LeakyReLU' param = layer . prelu_param param_string = "act_type='prelu', slope=%f" % param . filler . value need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'Eltwise' : type_string = 'mx.symbol.broadcast_add' param_string = "" need_flatten [ name ] = False if layer . type == 'Reshape' : type_string = 'mx.symbol.Reshape' param = layer . reshape_param param_string = 'shape=(' + ',' . join ( [ str ( x ) for x in list ( param . shape . dim ) ] ) + ')' need_flatten [ name ] = True if layer . type == 'AbsVal' : type_string = 'mx.symbol.abs' need_flatten [ name ] = need_flatten [ mapping [ layer . bottom [ 0 ] ] ] if layer . type == 'Normalize' : bottom = re . sub ( '[-/]' , '_' , layer . bottom [ 0 ] ) conv_layer = _find_layer ( layers , bottom ) assert conv_layer is not None param = layer . norm_param assert not param . across_spatial and not param . channel_shared assert param . scale_filler . type == 'constant' if conv_layer . type == 'Convolution' : scale_name = "%s_scale" % name symbol_string += "%s=mx.sym.Variable(name='%s', shape=(1, %d, 1, 1), init=mx.init.Constant(%f))\n" % ( scale_name , scale_name , conv_layer . convolution_param . num_output , param . scale_filler . value ) symbol_string += "%s=mx.symbol.L2Normalization(name='%s', data=%s, mode='channel')\n" % ( name , name , mapping [ layer . bottom [ 0 ] ] ) symbol_string += "%s=mx.symbol.broadcast_mul(lhs=%s, rhs=%s)\n" % ( name , scale_name , name ) type_string = 'split' need_flatten [ name ] = True else : raise ValueError ( 'Unknown/Invalid normalize layer!' ) if layer . type == 'Permute' : type_string = 'mx.symbol.transpose' param_string = "axes=(%s)" % ( ',' . join ( [ str ( x ) for x in layer . permute_param . order ] ) ) need_flatten [ name ] = True from_name = '' if layer . type == 'PriorBox' : param = layer . prior_box_param if layer . bottom [ 0 ] == 'data' : bottom_order = [ 1 ] else : bottom_order = [ 0 ] try : import math min_size = param . min_size [ 0 ] / input_dim [ 2 ] max_size = math . sqrt ( param . min_size [ 0 ] * param . max_size [ 0 ] ) / input_dim [ 2 ] sizes = '(%f, %f)' % ( min_size , max_size ) except AttributeError : min_size = param . min_size [ 0 ] / input_dim [ 2 ] sizes = '(%f)' % ( min_size ) ars = list ( param . aspect_ratio ) ratios = [ 1. ] for ar in ars : ratios . append ( ar ) if param . flip : ratios . append ( 1. / ar ) ratios_string = '(' + ',' . join ( str ( x ) for x in ratios ) + ')' clip = param . clip if ( param . step_h > 0 or param . step_w > 0 ) : step_h = param . step_h step_w = param . step_w elif param . step > 0 : step_h = param . step step_w = param . step else : step_h = - 1 step_w = - 1 finput_dimh = float ( input_dim [ 2 ] ) finput_dimw = float ( input_dim [ 3 ] ) step = '(%f, %f)' % ( step_h / finput_dimh , step_w / finput_dimw ) assert param . offset == 0.5 , "currently only support offset = 0.5" symbol_string += '%s = mx.contrib.symbol.MultiBoxPrior(%s, sizes=%s, ratios=%s, clip=%s, steps=%s, name="%s")\n' % ( name , mapping [ layer . bottom [ 0 ] ] , sizes , ratios_string , clip , step , name ) symbol_string += '%s = mx.symbol.Flatten(data=%s)\n' % ( name , name ) type_string = 'split' need_flatten [ name ] = False if layer . type == 'DetectionOutput' : bottom_order = [ 1 , 0 , 2 ] param = layer . detection_output_param assert param . share_location == True assert param . background_label_id == 0 nms_param = param . nms_param type_string = 'mx.contrib.symbol.MultiBoxDetection' param_string = "nms_threshold=%f, nms_topk=%d, clip=False" % ( nms_param . nms_threshold , nms_param . top_k ) if skip_layer : assert len ( layer . bottom ) == 1 symbol_string += "%s = %s\n" % ( name , prev_name ) elif type_string == '' : raise ValueError ( 'Unknown layer %s!' % layer . type ) elif type_string != 'split' : bottom = layer . bottom if param_string != "" : param_string = ", " + param_string if len ( bottom ) == 1 : if need_flatten [ mapping [ bottom [ 0 ] ] ] and type_string == 'mx.symbol.FullyConnected' : flatten_name = "flatten_%d" % flatten_count symbol_string += "%s=mx.symbol.Flatten(name='%s', data=%s)\n" % ( flatten_name , flatten_name , mapping [ bottom [ 0 ] ] ) flatten_count += 1 need_flatten [ flatten_name ] = False bottom [ 0 ] = flatten_name mapping [ bottom [ 0 ] ] = bottom [ 0 ] symbol_string += "%s = %s(name='%s', data=%s %s)\n" % ( name , type_string , name , mapping [ bottom [ 0 ] ] , param_string ) else : if not bottom_order : bottom_order = range ( len ( bottom ) ) symbol_string += "%s = %s(name='%s', *[%s] %s)\n" % ( name , type_string , name , ',' . join ( [ mapping [ bottom [ x ] ] for x in bottom_order ] ) , param_string ) if layer . type == 'Concat' and layer . concat_param . axis == 2 : symbol_string += "%s = mx.symbol.Reshape(data=%s, shape=(0, -1, 4), name='%s')\n" % ( name , name , name ) for j in range ( len ( layer . top ) ) : mapping [ layer . top [ j ] ] = name output_name = name return symbol_string , output_name , input_dim
Parse Caffe prototxt into symbol string