parameters: (src_prototxt, dst_prototxt, dst_width, dst_height)
docstring: @function: Process original test prototxt for converting bin
      :param src_prototxt:
      :param dst_prototxt:
      :param resolution: Specify image resolution. "720P" [720*1080], "1080P" [1080*1920]
      :return:
function: def process_prototxt(src_prototxt, dst_prototxt, dst_width, dst_height):
      """
      @function: Process original test prototxt for converting bin
      :param src_prototxt:
      :param dst_prototxt:
      :param resolution: Specify image resolution. "720P" [720*1080], "1080P" [1080*1920]
      :return:
      """
      ### 变换 prototxt 模型分辨率 以及 预设区域尺寸 anchors box 参数排布形式 ###
      preprocess(src_prototxt, dst_width, dst_height)  
      src_net = caffe_pb2.NetParameter()
      #  吸收BN层  Scale 被改名为 "findBatchNorm"
      layer_type_set = set([u"BatchNorm", u"BN", u"Scale", u"LBN"])
      
      # conv+BN / conv+LBN / conv+BatchNorm+Scale / conv+Scale
      
      # 只读方式打开
      with open(src_prototxt, 'r') as fin:
          # 解析prototxt文件 保存每一层信息到 src_net
          pb.text_format.Merge(fin.read(), src_net)
          
      ### 吸收 Concat_ls/concat_res层 ###
      concat_loss_name_list=["Concat_ls","concat_res"] # 最后特有的 收集 loss_Px 层的concat层
      
      Concat_ls_layer_exist=False
      # 遍历 网络的每一层
      remove_layer=[]
      # 前向时需要删除的层 Dropout层等
      forward_remove_layer = []
      # 记录非in-place的信息用于修改
      dict_cbn={}       # 记录  BN类层输出 :  卷积层的输出 bottom名字 字典
      dict_activate={}  # 激活层 in-place 修改 前后 名字字典
      
      
      # enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列，同时列出数据和数据下标，一般用在 for 循环当中。
      for i, layer in enumerate(src_net.layer):
          '''############ 1. BN 结构处理  ###################'''
          # BN层
          if layer.type in layer_type_set:
              #print(layer.type)
              # BN层的前一层
              pre_layer = src_net.layer[i - 1]
              if pre_layer.type == "Convolution":
                  remove_layer.append(layer)
                  # 合并BN层到前一层convolution_param参数里面 Set bias of convolution before current layer True
                  pre_layer.convolution_param.bias_term = True
                  
                  # 可能该层在网络最后 有问题
                  if ((i + 1) < (len(src_net.layer) - 1)) and (src_net.layer[i + 1].type not in layer_type_set):
                      #### 确保是 卷积+BN  / 卷积+LBN  / 卷积+Scale / 卷积+BatchNorm 的结构
                      dict_cbn[layer.top[0]]=pre_layer.top[0]
              
              #### 确保是 卷积+BatchNorm+Scale
              if i >= 2 and layer.type == "Scale" and pre_layer.type == "BatchNorm" and src_net.layer[i - 2].type == "Convolution":
                  remove_layer.append(layer)
                  # scale输出的blob名  和 卷积层的输出blob名关联
                  dict_cbn[layer.top[0]]=src_net.layer[i - 2].top[0]
                  
          '''############ 2. concat+nms 结构处理  ###########'''
          #Concat_ls_layer_exist=False
          # 记录 Concat_ls 层
          if layer.name in concat_loss_name_list:    # Delete concat_res layer
              # 拷贝 名为 Concat_ls 层 的 输入 层列表
              bottom_list = copy.deepcopy(layer.bottom)
              # 拷贝 名为 Concat_ls 层
              tmp_layer = copy.deepcopy(layer)
              Concat_ls_layer_exist=True
          if Concat_ls_layer_exist:
              # 将concat_loss层的输入直接合并到 输入为loss或combine_loss的nms层中
              if layer.name == "nms":
                  print layer.bottom 
                  if 'loss' == layer.bottom[0]:
                      layer.bottom.remove('loss')
                  elif 'combine_loss' == layer.bottom[0]:
                      layer.bottom.remove('combine_loss')
                  else:
                      print "error!! only support loss and combine_loss" 
                  # 将 concat_loss 层的输入直接合并到 输入为 loss 或 combine_loss的 nms 层中
                  layer.bottom.extend(bottom_list)
                  
          '''############ 3. Dropout层处理 ##################'''
          if layer.type in ['Dropout']:
              forward_remove_layer.append(layer)
      
      '''# 除去bn 层'''
      for layer in remove_layer:
          print "remove "+layer.name
          src_net.layer.remove(layer)
      '''# 去除 Concat_ls 层'''
      if Concat_ls_layer_exist:
          try:
              #if(tmp_layer):
              src_net.layer.remove(tmp_layer)
          except NameError:
              print("Concat_ls layer not exist")
      '''# 除去 Dropout 层'''
      for layer in forward_remove_layer:
          print "remove "+layer.name
          src_net.layer.remove(layer)
      # 处理 Dropout 层 非 in-place
      for layer in forward_remove_layer:
          # 非 in-place 情况：输入botom != 输出
          if layer.bottom[0] != layer.top[0]:
              print "Dropout layer not in-place "
              for src_layer in src_net.layer:
                  for id in range(len(src_layer.bottom)):
                      # 在网络中找到以 Dropout层的输出bottom 为输入的层，也就是该层的后继层
                      if src_layer.bottom[id] == layer.top[0]:
                          #改名字
                          src_layer.bottom[id] = layer.bottom[0]
      
      
      #### 如果 卷积+BatchNorm+Scale的输入输出blob名字不一样，
      #### 那么其后面的层如激活层 Relu的输入blob就需要改名为前面卷积层的输出blob的名字
      #activatre_layer_type=["ReLU","Sigmoid","TanH","Power","PReLU","AbsVal","BNLL","ELU","LeakyReLU"]  #### 处理方式有bug
      #convolution_layer=["Convolution","Deconvolution"]
      #last_layer=None
      #for i, layer in enumerate(src_net.layer):
      #    if layer.type in activatre_layer_type and last_layer.type in convolution_layer:
      #        if len(layer.bottom) != 1 or len(last_layer.top) != 1:
      #            print layer.type + " / " + last_layer.type + " top/bottom numn not 1"
      #        else:
      #            layer.bottom.remove(layer.bottom[0])
      #            layer.bottom.append(last_layer.top[0])
      #    
      #    last_layer=layer
      
      # 修改激活层的 输入名 同时修改激活层为 in-place情况
      activate_layer = ["ReLU","Sigmoid","TanH","Power","PReLU","AbsVal","BNLL","ELU","LeakyReLU"]
      for i, layer in enumerate(src_net.layer):
          if layer.type in activate_layer:
              #print "layername :"+layer.name
              #for id in range(len(layer.bottom)):
              #print layer.bottom[id]
              # dict_cbn: 激活层输出:前层卷积层输出
              # 查找 有已 被删除的 激活层的输出为 输入的 激活层
              if layer.bottom[0] in dict_cbn:
                  layer.bottom[0] = dict_cbn[layer.bottom[0]]  # 替换为 对应卷积层的输出
                  # 记录 激活层 输出:输入 字典 为处理 激活层的后继层做处理
                  dict_activate[layer.top[0]] = layer.bottom[0]
                  layer.top[0] = layer.bottom[0]  # 改成 inplace
      '''
      follow_bn_layer = ["Pooling","Convolution"]
      for i, layer in enumerate(src_net.layer):
          if layer.type in follow_bn_layer:
              #print "layername :"+layer.name
              #for id in range(len(layer.bottom)):
              #print layer.bottom[id]
              if layer.bottom[0] in dict_cbn:
                  layer.bottom[0] = dict_cbn[layer.bottom[0]]
              
              elif layer.bottom[0] in dict_activate:
                  layer.bottom[0] = dict_activate[layer.bottom[0]]
      
      # 处理岔路口合并的情况 + 激活 非 inplace的case
      #merge_layer=["Eltwise","Concat","Crop"]
      merge_layer=["Eltwise","Concat","Crop"]
      for i, layer in enumerate(src_net.layer):
          if layer.type in merge_layer:
              #print "layername :"+layer.name
              for id in range(len(layer.bottom)):
                  #print layer.bottom[id]
                  if layer.bottom[id] in dict_cbn:
                      layer.bottom[id] = dict_cbn[layer.bottom[id]]
                      
                  elif layer.bottom[id] in dict_activate:
                      layer.bottom[id] = dict_activate[layer.bottom[id]]
      '''
      for i, layer in enumerate(src_net.layer):
          for id in range(len(layer.bottom)):
              # BN层 in-place 后，其后继层的调整
              if layer.bottom[id] in dict_cbn:
                  layer.bottom[id] = dict_cbn[layer.bottom[id]]
              # 激活层 in-place 后，其后继层的调整
              elif layer.bottom[id] in dict_activate:
                  layer.bottom[id] = dict_activate[layer.bottom[id]]
      
      
                  
      # 这种处理有bug
      #for dict_cbn_key in dict_cbn:
      #    for layer in src_net.layer:
      #        if layer.type not in activatre_layer_type:
      #            for id in range(len(layer.bottom)):
      #                if layer.bottom[id] == dict_cbn_key:
      #                    layer.bottom[id] = dict_cbn[dict_cbn_key]
      
      
      # 写入修改后的文件
      with open(dst_prototxt, 'w') as fout:
          fout.write(pb.text_format.MessageToString(src_net))
function_tokens: def process_prototxt ( src_prototxt , dst_prototxt , dst_width , dst_height ) : ### 变换 prototxt 模型分辨率 以及 预设区域尺寸 anchors box 参数排布形式 ### preprocess ( src_prototxt , dst_width , dst_height ) src_net = caffe_pb2 . NetParameter ( ) #  吸收BN层  Scale 被改名为 "findBatchNorm" layer_type_set = set ( [ u"BatchNorm" , u"BN" , u"Scale" , u"LBN" ] ) # conv+BN / conv+LBN / conv+BatchNorm+Scale / conv+Scale # 只读方式打开 with open ( src_prototxt , 'r' ) as fin : # 解析prototxt文件 保存每一层信息到 src_net pb . text_format . Merge ( fin . read ( ) , src_net ) ### 吸收 Concat_ls/concat_res层 ### concat_loss_name_list = [ "Concat_ls" , "concat_res" ] # 最后特有的 收集 loss_Px 层的concat层 Concat_ls_layer_exist = False # 遍历 网络的每一层 remove_layer = [ ] # 前向时需要删除的层 Dropout层等 forward_remove_layer = [ ] # 记录非in-place的信息用于修改 dict_cbn = { } # 记录  BN类层输出 :  卷积层的输出 bottom名字 字典 dict_activate = { } # 激活层 in-place 修改 前后 名字字典 # enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列，同时列出数据和数据下标，一般用在 for 循环当中。 for i , layer in enumerate ( src_net . layer ) : '''############ 1. BN 结构处理  ###################''' # BN层 if layer . type in layer_type_set : #print(layer.type) # BN层的前一层 pre_layer = src_net . layer [ i - 1 ] if pre_layer . type == "Convolution" : remove_layer . append ( layer ) # 合并BN层到前一层convolution_param参数里面 Set bias of convolution before current layer True pre_layer . convolution_param . bias_term = True # 可能该层在网络最后 有问题 if ( ( i + 1 ) < ( len ( src_net . layer ) - 1 ) ) and ( src_net . layer [ i + 1 ] . type not in layer_type_set ) : #### 确保是 卷积+BN  / 卷积+LBN  / 卷积+Scale / 卷积+BatchNorm 的结构 dict_cbn [ layer . top [ 0 ] ] = pre_layer . top [ 0 ] #### 确保是 卷积+BatchNorm+Scale if i >= 2 and layer . type == "Scale" and pre_layer . type == "BatchNorm" and src_net . layer [ i - 2 ] . type == "Convolution" : remove_layer . append ( layer ) # scale输出的blob名  和 卷积层的输出blob名关联 dict_cbn [ layer . top [ 0 ] ] = src_net . layer [ i - 2 ] . top [ 0 ] '''############ 2. concat+nms 结构处理  ###########''' #Concat_ls_layer_exist=False # 记录 Concat_ls 层 if layer . name in concat_loss_name_list : # Delete concat_res layer # 拷贝 名为 Concat_ls 层 的 输入 层列表 bottom_list = copy . deepcopy ( layer . bottom ) # 拷贝 名为 Concat_ls 层 tmp_layer = copy . deepcopy ( layer ) Concat_ls_layer_exist = True if Concat_ls_layer_exist : # 将concat_loss层的输入直接合并到 输入为loss或combine_loss的nms层中 if layer . name == "nms" : print layer . bottom if 'loss' == layer . bottom [ 0 ] : layer . bottom . remove ( 'loss' ) elif 'combine_loss' == layer . bottom [ 0 ] : layer . bottom . remove ( 'combine_loss' ) else : print "error!! only support loss and combine_loss" # 将 concat_loss 层的输入直接合并到 输入为 loss 或 combine_loss的 nms 层中 layer . bottom . extend ( bottom_list ) '''############ 3. Dropout层处理 ##################''' if layer . type in [ 'Dropout' ] : forward_remove_layer . append ( layer ) '''# 除去bn 层''' for layer in remove_layer : print "remove " + layer . name src_net . layer . remove ( layer ) '''# 去除 Concat_ls 层''' if Concat_ls_layer_exist : try : #if(tmp_layer): src_net . layer . remove ( tmp_layer ) except NameError : print ( "Concat_ls layer not exist" ) '''# 除去 Dropout 层''' for layer in forward_remove_layer : print "remove " + layer . name src_net . layer . remove ( layer ) # 处理 Dropout 层 非 in-place for layer in forward_remove_layer : # 非 in-place 情况：输入botom != 输出 if layer . bottom [ 0 ] != layer . top [ 0 ] : print "Dropout layer not in-place " for src_layer in src_net . layer : for id in range ( len ( src_layer . bottom ) ) : # 在网络中找到以 Dropout层的输出bottom 为输入的层，也就是该层的后继层 if src_layer . bottom [ id ] == layer . top [ 0 ] : #改名字 src_layer . bottom [ id ] = layer . bottom [ 0 ] #### 如果 卷积+BatchNorm+Scale的输入输出blob名字不一样， #### 那么其后面的层如激活层 Relu的输入blob就需要改名为前面卷积层的输出blob的名字 #activatre_layer_type=["ReLU","Sigmoid","TanH","Power","PReLU","AbsVal","BNLL","ELU","LeakyReLU"]  #### 处理方式有bug #convolution_layer=["Convolution","Deconvolution"] #last_layer=None #for i, layer in enumerate(src_net.layer): #    if layer.type in activatre_layer_type and last_layer.type in convolution_layer: #        if len(layer.bottom) != 1 or len(last_layer.top) != 1: #            print layer.type + " / " + last_layer.type + " top/bottom numn not 1" #        else: #            layer.bottom.remove(layer.bottom[0]) #            layer.bottom.append(last_layer.top[0]) #     #    last_layer=layer # 修改激活层的 输入名 同时修改激活层为 in-place情况 activate_layer = [ "ReLU" , "Sigmoid" , "TanH" , "Power" , "PReLU" , "AbsVal" , "BNLL" , "ELU" , "LeakyReLU" ] for i , layer in enumerate ( src_net . layer ) : if layer . type in activate_layer : #print "layername :"+layer.name #for id in range(len(layer.bottom)): #print layer.bottom[id] # dict_cbn: 激活层输出:前层卷积层输出 # 查找 有已 被删除的 激活层的输出为 输入的 激活层 if layer . bottom [ 0 ] in dict_cbn : layer . bottom [ 0 ] = dict_cbn [ layer . bottom [ 0 ] ] # 替换为 对应卷积层的输出 # 记录 激活层 输出:输入 字典 为处理 激活层的后继层做处理 dict_activate [ layer . top [ 0 ] ] = layer . bottom [ 0 ] layer . top [ 0 ] = layer . bottom [ 0 ] # 改成 inplace '''
      follow_bn_layer = ["Pooling","Convolution"]
      for i, layer in enumerate(src_net.layer):
          if layer.type in follow_bn_layer:
              #print "layername :"+layer.name
              #for id in range(len(layer.bottom)):
              #print layer.bottom[id]
              if layer.bottom[0] in dict_cbn:
                  layer.bottom[0] = dict_cbn[layer.bottom[0]]
              
              elif layer.bottom[0] in dict_activate:
                  layer.bottom[0] = dict_activate[layer.bottom[0]]
      
      # 处理岔路口合并的情况 + 激活 非 inplace的case
      #merge_layer=["Eltwise","Concat","Crop"]
      merge_layer=["Eltwise","Concat","Crop"]
      for i, layer in enumerate(src_net.layer):
          if layer.type in merge_layer:
              #print "layername :"+layer.name
              for id in range(len(layer.bottom)):
                  #print layer.bottom[id]
                  if layer.bottom[id] in dict_cbn:
                      layer.bottom[id] = dict_cbn[layer.bottom[id]]
                      
                  elif layer.bottom[id] in dict_activate:
                      layer.bottom[id] = dict_activate[layer.bottom[id]]
      ''' for i , layer in enumerate ( src_net . layer ) : for id in range ( len ( layer . bottom ) ) : # BN层 in-place 后，其后继层的调整 if layer . bottom [ id ] in dict_cbn : layer . bottom [ id ] = dict_cbn [ layer . bottom [ id ] ] # 激活层 in-place 后，其后继层的调整 elif layer . bottom [ id ] in dict_activate : layer . bottom [ id ] = dict_activate [ layer . bottom [ id ] ] # 这种处理有bug #for dict_cbn_key in dict_cbn: #    for layer in src_net.layer: #        if layer.type not in activatre_layer_type: #            for id in range(len(layer.bottom)): #                if layer.bottom[id] == dict_cbn_key: #                    layer.bottom[id] = dict_cbn[dict_cbn_key] # 写入修改后的文件 with open ( dst_prototxt , 'w' ) as fout : fout . write ( pb . text_format . MessageToString ( src_net ) )