caffe:使用固定的预定义内核(过滤器)进行卷积

caffe: convolution with a fix predifined kernel (filter)

我对具有固定预定义矩阵的卷积感兴趣,而不是拥有可学习的过滤器;例如 sobel 过滤器:

所以,我将 learning = 0(所以它是固定的)设置为:

layer {
    name: "conv1"
    type: "Convolution"
    bottom: "data"
    top: "conv1"
    param { lr_mult: 0 decay_mult: 0 }
    convolution_param {
      num_output: 10
      kernel_size: 3    # filter is 3x3
      stride: 2          
      weight_filler {
        type: ??}
    }
  }

现在,我不知道如何将矩阵信息提供给conv层。有任何想法吗?我认为它应该转到 weight_filler,但是如何呢?

还有一个问题:num_output 必须与 bottom 的(此处数据通道 = 10)通道大小相同吗?我可以设置 num_output 另一个号码吗?如果是,会发生什么,这意味着什么?

如何将权重初始化为特定值?

您可以使用 net_surgery 在 python 中加载您的 untrained/un-initialized 网络,然后将您想要的特定权重分配给过滤器,保存网络,并与权重一起使用你想要这个特定的图层。

如何设置num_output和其他conv_params

这是个好问题:你有一个形状为 bx10xhxw 的输入 blob,你想应用一个 3x3 过滤每个通道并得到一个新的过滤 bx10xhxw。如果你只设置num_output: 10,过滤器的形状将是10x10x3x3,即10个形状为[=的过滤器14=]x3x3 - 这 不是 想要的。您需要 3x3 过滤器。
为此,您需要查看 group conv_param。将 group: 10num_output: 10 一起设置(假设输入 c=10)将为您提供您想要的,权重形状将为 10x1x3x 3.

在pythoncaffe接口中,caffe.Net对象通过加载.prototxt文件实例化,它定义了网络架构。您可以使用具有以下属性的 caffe.Net 对象来访问网络上的各种信息。

  • blob_loss_weights:按层名称索引的网络 blob 损失权重的 OrderedDict(从下到上,即输入到输出)
  • blobs:按层名称索引的网络 blob 的 OrderedDict(从下到上,即输入到输出)
  • bottom_names:全网下名
  • inputs:输入到这个网络
  • layer_dict:按层名称索引的网络层的 OrderedDict(从下到上,即输入到输出)
  • layerscaffe._caffe.LayerVec - 其元素是网络中 caffe.Layer 个对象的列表,caffe.Layer 个类有 blobs 层参数内存字段和 type 层类型(例如卷积、数据等)
  • outputs:来自这个网络的输出
  • params:按名称索引的网络参数的OrderedDict(从下到上,即输入到输出);每个都是多个 blob 的列表(例如,权重和偏差)
  • top_names: 网络中的所有顶级人物

您可以使用 caffe.Net.params 访问层的可学习参数,并使用 caffe.Net.layer_dict 访问层信息。

caffe.Net.params 是有序字典,其中键是层名称,值是参数(例如权重和偏差)的斑点,在卷积层的情况下,首先blob 的元素是 weiht,blob 的第二个元素是 bias:

  • caffe.Net.params['layer_name'][0] : 体重
  • caffe.Net.params['layer_name'][1]:偏差

请注意,访问 blob 的内存应该用 caffe.Net.params['layer_name'][0].data 完成,更新 blob 的内存应该用 ... 完成,例如 caffe.Net.params['layer_name'][0].data[...]

以下代码说明了从 numpy 保存的文件 (.npy) 加载可学习参数:

def load_weights_and_biases(network):
    k_list = list(network.params.keys())

    suffix = ["weight", "bias"]
    num_layers = len(network.layer_dict)
    
    for idx, layer_name in enumerate(network.layer_dict):
        print(f"\n-----------------------------")
        print(f"layer index: {idx}/{num_layers}")
        print(f"layer name: '{layer_name}''")
        print(f"layer type: '{detection_nw.layers[idx].type}' ")
        
        if layer_name in k_list:
            params = network.params[layer_name]
            print(f"{len(params)} learnable parameters in '{detection_nw.layers[idx].type}' type")        
            
            for i, p in enumerate(params):
                #print(f"\tparams[{i}]: {p}")
                #print(f"\tparams[{i}] CxHxW: {p.channels}x{p.height}x{p.width}")
                print(f"\tp[{i}]: {p.data.shape} of {p.data.dtype}")
                
                                
                param_file_path = f"./npy_save/{layer_name}_{suffix[i]}.npy"
                
                param_file = Path(param_file_path)
                if param_file.exists():
                    print(f"\tload {param_file_path}")
                    arr = np.load(param_file_path, allow_pickle=True)
                    
                    if p.data.shape == arr.shape:
                        print(f"\tset {layer_name}_{suffix[i]} with arr:shape {arr.shape}, type {arr.dtype}")
                                                
                        p.data[...] = arr
                        
                    else:
                        print(f"p.data.shape: {p.data.shape} is not equal to arr.shape: {arr.shape}")
                        break
                else:
                    print(f"{param_file_path} is not exits!!")
                    break                       
        else:
            print(f"no learnable parameters in '{layer_name}' of '{network.layers[idx].type}' type'")

Blob 类型在 pythoncaffe(又名 pycaffe)接口中定义为 caffe._caffe.Blob。在 import caffe 之后使用 help(caffe._caffe.Blob) 并在此处定义的 数据描述符中描述的名称 帮助输出部分作为属性。

有关 Caffe 中 Blob 参考的更多详细信息