user3162707
user3162707

Reputation: 721

caffe: model definition: write same layer with different phase using caffe.NetSpec()

I want to set up a caffe CNN with python, using caffe.NetSpec() interface. Although I saw we can put test net in solver.prototxt, I would like to write it in model.prototxt with different phase. For example, caffe model prototxt implement two data layer with different phases:

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

How should I do in python to get such implementation?

Upvotes: 6

Views: 3304

Answers (5)

Przemek D
Przemek D

Reputation: 664

Although several answers have been given, none covers a more real-world scenario where you don't even know (at the moment of writing code) the names of your layers. For example when you're assembling a network from smaller blocks, you can't write:

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

Because every next instantiation of the block would overwrite data and test_data (or batchnorm, which is more likely to be put in blocks).

Fortunately, you can assign to the NetSpec object via __getitem__, like so:

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

Upvotes: 1

Rolrence
Rolrence

Reputation: 31

I find an useful method.

You can add a key named name for your test phase layer, and modify the keys ntop and top just like this:

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)

Upvotes: 3

Thomio
Thomio

Reputation: 1433

I found another way.
I could solve this problem returning the proto string.
Basically, you can add strings with the layers that are going to be replaced (in my case, the first layer).

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())

Upvotes: 1

Gaurav Gupta
Gaurav Gupta

Reputation: 1925

If your network is like:

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

Create a train net ns, Create a test net ns_test
Now you basically have two strings str(ns.to_proto()) and str(ns_test.to_proto())
Merge those two using python regex taking into account the required layer order.

Upvotes: 1

Shai
Shai

Reputation: 114796

I assume you mean how to define phase when writing a prototxt using caffe.NetSpec?

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})

If you want to have BOTH train and test layers in the same prototxt, what I usually do is making one ns for train with ALL layers and another ns_test with only the test version of the duplicate layers only. Then, when writing the actual prototxt file:

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

This way you'll have BOTH phases in the same prototxt. A bit hacky, I know.

Upvotes: 5

Related Questions