统一 Caffe 网络结构#

from pathlib import Path
from google.protobuf import text_format
import caffe_pb2 as pb2

temp_dir = Path(".temp")
temp_dir.mkdir(exist_ok=True)

处理 in-place 层#

from caffe_utils import _rebuild_layers

该函数用于处理 Caffe 网络中的 in-place 层,解决因输入输出绑定(in-place)导致的名称冲突问题。 具体来说,当某层的输入(bottom)和输出(top)名称相同时(即 in-place 层),需要将其 top 改为层名称(pl.name),并通过映射表 changed_top_dict 动态更新其他层的 bottom,确保后续层引用正确。

text = """
name: "MyNetwork"
layer {
  name: "input_layer"
  type: "Input"
  top: "input"
  input_param { shape { dim: 1 dim: 3 dim: 224 dim: 224 } }
}

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "input"
  top: "conv1_out"
}

layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1_out"
  top: "conv1_out"  # 这是 in-place 操作,输入输出名称相同
}

layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1_out"  # 依赖原始名称 "conv1_out"
  top: "pool1_out"
}
""".strip()

Hide code cell content

predict_net = text_format.Merge(text, pb2.NetParameter())
_rebuild_layers(predict_net.layer)
predict_net
name: "MyNetwork"
layer {
  name: "input_layer"
  type: "Input"
  top: "input"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "input"
  top: "conv1_out"
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1_out"
  top: "relu1"
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "relu1"
  top: "pool1_out"
}

Hide code cell content

from caffe_utils import unity_struct

predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = unity_struct(predict_net)
predict_net
name: "MyNetwork"
layer {
  name: "input_layer"
  type: "Input"
  top: "input_layer"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "input_layer"
  top: "conv1"
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "relu1"
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "relu1"
  top: "pool1"
}

为什么需要这样的处理?

  • 避免名称冲突:原 in-place 层的输入输出绑定会导致后续层无法正确引用输出名称(如 pool1 无法找到 "conv1_out")。

  • 兼容性需求:部分框架(如 PyTorch、TensorFlow)不支持 Caffe 的原生 in-place 机制,需显式修改名称以保证结构清晰。

统一输入节点表示#

Hide code cell content

from caffe_utils import unity_inputs

text = """
name: "单输入"
# 定义所有输入名称
input: "data"

# 输入的维度配置
input_dim: 1
input_dim: 3
input_dim: 32
input_dim: 32

layer {
    name: "relu"
	bottom: "data"
	top: "relu"
	type: "ReLU"
}
""".strip()
predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = unity_inputs(predict_net)
predict_net
name: "单输入"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 32
      dim: 32
    }
  }
}
layer {
  name: "relu"
  type: "ReLU"
  bottom: "data"
  top: "relu"
}

Hide code cell content

text = """
name: "多输入"
# 定义所有输入名称
input: ["data1", "data2"]

# 第一个输入的维度配置
input_shape {
  dim: 1    # 批次大小
  dim: 3    # 通道数
  dim: 224  # 高度
  dim: 224  # 宽度
}

# 第二个输入的维度配置
input_shape {
  dim: 1    # 批次大小
  dim: 1    # 通道数
  dim: 112  # 高度
  dim: 112  # 宽度
}

layer {
	bottom: "data1"
	top: "relu"
	name: "relu"
	type: "ReLU"
}

layer {
	bottom: "data2"
    bottom: "relu"
	top: "output"
	name: "add"
	type: "Add"
}
""".strip()
predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = unity_inputs(predict_net)
predict_net
name: "多输入"
layer {
  name: "data1"
  type: "Input"
  top: "data1"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "data2"
  type: "Input"
  top: "data2"
  input_param {
    shape {
      dim: 1
      dim: 1
      dim: 112
      dim: 112
    }
  }
}
layer {
  name: "relu"
  type: "ReLU"
  bottom: "data1"
  top: "relu"
}
layer {
  name: "add"
  type: "Add"
  bottom: "data2"
  bottom: "relu"
  top: "output"
}

Hide code cell content

from caffe_utils import unity_struct

predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = unity_struct(predict_net)
predict_net
name: "多输入"
layer {
  name: "data1"
  type: "Input"
  top: "data1"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "data2"
  type: "Input"
  top: "data2"
  input_param {
    shape {
      dim: 1
      dim: 1
      dim: 112
      dim: 112
    }
  }
}
layer {
  name: "relu"
  type: "ReLU"
  bottom: "data1"
  top: "relu"
}
layer {
  name: "add"
  type: "Add"
  bottom: "data2"
  bottom: "relu"
  top: "add"
}

替换数字名称#

from caffe_utils import convert_num_to_name
text = """
name: "替换数字名称"
layer {
  name: "data"
  type: "Input"
  top: "181"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "Relu_1"
  type: "ReLU"
  bottom: "181"
  top: "182"
}

layer {
  name: "PRelu_2"
  type: "PReLU"
  bottom: "182"
  top: "183"
}
""".strip()
predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = convert_num_to_name(predict_net)
predict_net
name: "替换数字名称"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "Relu_1"
  type: "ReLU"
  bottom: "data"
  top: "Relu_1"
}
layer {
  name: "PRelu_2"
  type: "PReLU"
  bottom: "Relu_1"
  top: "PRelu_2"
}

统一 caffe 结构#

from caffe_utils import unity_struct

predict_net = text_format.Merge(text, pb2.NetParameter())
predict_net = unity_struct(predict_net)
predict_net
name: "替换数字名称"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param {
    shape {
      dim: 1
      dim: 3
      dim: 224
      dim: 224
    }
  }
}
layer {
  name: "Relu_1"
  type: "ReLU"
  bottom: "data"
  top: "Relu_1"
}
layer {
  name: "PRelu_2"
  type: "PReLU"
  bottom: "Relu_1"
  top: "PRelu_2"
}