【问题标题】:caffe: model definition: write same layer with different phase using caffe.NetSpec()caffe:模型定义:使用 caffe.NetSpec() 编写具有不同阶段的同一层
【发布时间】:2016-08-19 02:29:05
【问题描述】:

我想用python设置一个caffe CNN,使用caffe.NetSpec()接口。虽然我看到我们可以把测试网放在solver.prototxt,但我想把它写在model.prototxt不同阶段。比如caffe model prototxt实现两个不同阶段的数据层:

layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
....
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
....
}

我应该如何在 python 中获得这样的实现?

【问题讨论】:

标签: neural-network deep-learning caffe


【解决方案1】:

我假设您的意思是在使用 caffe.NetSpec 编写 prototxt 时如何定义阶段?

from caffe import layers as L, params as P, to_proto
import caffe

ns = caffe.NetSpec()
ns.data = L.Data(name="data", 
                 data_param={'source':'/path/to/lmdb','batch_size':32},
                 include={'phase':caffe.TEST})

如果你想在同一个 prototxt 中同时拥有训练层和测试层,我通常会制作一个 ns 用于具有所有层的训练,另一个 ns_test 仅具有重复层的测试版本。然后,在编写实际的 prototxt 文件时:

with open('model.prototxt', 'w') as W:
  W.write('%s\n' % ns_test.to_proto())
  W.write('%s\n' % ns.to_proto())

这样,您将在同一个 prototxt 中拥有两个阶段。有点老套,我知道。

【讨论】:

  • 是的,我使用 caffe.NetSpec(),但问题是我想定义两个具有相同名称但不同阶段的层,例如 ns.data = L.Data(name="data ", data_param={'source':'/path/to/lmdb','batch_size':32}, include={'phase':caffe.TEST}) ns.data = L.Data(name="data" , data_param={'source':'/path/to/lmdb','batch_size':32}, include={'phase':caffe.TRAIN})
  • 但这只会使 ns.data 用于 TEST 阶段
  • 谢谢,它解决了我的问题。但是,这样做,solver.test_net中没有数据。这是否意味着如果我想在某个训练过程之后测试预测,我必须手动设置要测试的阶段?我想做的是使用solver.solve(),让求解器自动训练和测试网络。
  • @user3162707 我没有完全理解你的评论。如果您相应地设置测试数据源,并在求解器 prototxt 中设置测试间隔,则求解器应自动使用测试数据以指定间隔测试网络。无论如何,如果这解决了您的问题(就像我的问题一样,虽然有点 hacky),它应该被标记为正确答案。
【解决方案2】:

如果您的网络是这样的:

layer {phase: TRAIN}
layer {phase: TEST}
layer {}
layer {phase: TRAIN}
layer {}
layer {phase: TEST}
layer {}
layer {}
layer {phase: TEST}

创建一个火车网ns, 创建测试网ns_test
现在你基本上有两个字符串str(ns.to_proto())str(ns_test.to_proto())
考虑到所需的层顺序,使用 python 正则表达式合并这两个。

【讨论】:

    【解决方案3】:

    我找到了另一种方法。
    我可以解决这个问题,返回原始字符串。
    基本上,您可以添加带有要替换的层的字符串(在我的例子中,第一层)。

    def lenet(path_to_lmdb_train, path_to_lmdb_test,
              batch_size_train, batch_size_test ):
        n = caffe.NetSpec()
        n.data, n.label = L.Data(batch_size=batch_size_train, backend=P.Data.LMDB, source=path_to_lmdb_train,
                                 include=dict(phase=caffe.TRAIN), transform_param=dict(scale=1./255), ntop=2)
        first_layer = str(n.to_proto())
    
        n.data, n.label = L.Data(batch_size=batch_size_test, backend=P.Data.LMDB, source=path_to_lmdb_test,
                                 include=dict(phase=caffe.TEST), transform_param=dict(scale=1./255), ntop=2)
        n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
        n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
        n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
        n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
        n.ip1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier'))
        n.relu1 = L.ReLU(n.ip1, in_place=True)
        n.ip2 = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier'))
        n.loss = L.SoftmaxWithLoss( n.ip2, n.label )
        n.accuracy = L.Accuracy( n.ip2, n.label, include=dict(phase=caffe.TEST) )
    
        return first_layer + str(n.to_proto())
    

    【讨论】:

      【解决方案4】:

      我找到了一个有用的方法。

      您可以为您的测试阶段层添加一个名为name 的键,并修改键ntoptop 就像这样:

      net.data = L.Data(name='data', 
                      include=dict(phase=caffe_pb2.Phase.Value('TRAIN')),
                      ntop=1)
      net.test_data = L.Data(name='data', 
                          include=dict(phase=caffe_pb2.Phase.Value('TEST')),
                          top='data',
                          ntop=0)
      

      【讨论】:

        【解决方案5】:

        尽管已经给出了几个答案,但没有一个答案涵盖了更真实的场景,您甚至不知道(在编写代码时)层的名称。例如,当您从较小的块组装网络时,您不能编写:

        n.data = L.Data(#...
        n.test_data = L.Data(#...
        

        因为块的每个下一个实例化都会覆盖datatest_data(或batchnorm,它更有可能被放入块中)。

        幸运的是,您可以通过__getitem__ 分配给 NetSpec 对象,如下所示:

        layer_name = 'norm{}'.format(i) #for example
        n[layer_name + '_train'] = L.Data(#...
        n[layer_name + '_test']  = L.Data(#...
        

        【讨论】:

        • 我有一个使用setattr()的讨厌的解决方法...我更喜欢这个!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-20
        • 2023-03-18
        • 2022-12-17
        • 1970-01-01
        • 2019-01-08
        • 2015-08-22
        相关资源
        最近更新 更多