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 w
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.
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())
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(#...
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.
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)