Skip to content

Conversation

jmerkow
Copy link

@jmerkow jmerkow commented Jul 31, 2015

This PR allows you to name tops, explicitly. You can name all, none or some of the tops. It will default to autonames for unnamed tops.
If you do not specify ntops, it will infer from the number of top names given.
Two examples:

import caffe
from caffe import layers as L, params as P, to_proto
from caffe.proto import caffe_pb2
from __future__ import print_function
def caffenet_name_all():
    data,label  = L.DummyData(name="data",top=["data","label"],
                              dummy_data_param=dict(shape=[dict(dim=[1,2,3])]))
    loss = L.SigmoidCrossEntropyLoss(data, label,name="loss",top=["SCEloss"])
    return to_proto(loss)
def caffenet_name_few():
    data,label  = L.DummyData(name="data",ntop=2,top=["data"],
                              dummy_data_param=dict(shape=[dict(dim=[1,2,3])]))
    loss = L.SigmoidCrossEntropyLoss(data, label,name="loss",top=["SCEloss"])
    return to_proto(loss)

def make_net():
    with open('train-all.prototxt', 'w') as f:
        print(caffenet_name_all(), file=f)
    with open('train-few.prototxt', 'w') as f:
        print(caffenet_name_few(), file=f)

produces:
train-all.prototxt

layer {
  name: "data"
  type: "DummyData"
  top: "data"
  top: "label"
  dummy_data_param {
    shape {
      dim: 1
      dim: 2
      dim: 3
    }
  }
}
layer {
  name: "loss"
  type: "SigmoidCrossEntropyLoss"
  bottom: "data"
  bottom: "label"
  top: "SCEloss"
}

train-few.prototxt

layer {
  name: "data"
  type: "DummyData"
  top: "data"
  top: "DummyData1"
  dummy_data_param {
    shape {
      dim: 1
      dim: 2
      dim: 3
    }
  }
}
layer {
  name: "loss"
  type: "SigmoidCrossEntropyLoss"
  bottom: "data"
  bottom: "DummyData1"
  top: "SCEloss"
}

Thanks!
--Jameson

P.S. Thanks to @BlGene for help figuring out why dummy data wasn't working. You gave be the one thing I didn't try!

@longjon
Copy link
Contributor

longjon commented Jul 31, 2015

Actually there is already a way to do this; that's the point of the NetSpec class. See https://github.com/BVLC/caffe/blob/master/python/caffe/test/test_net_spec.py, and note the difference between lenet and anon_lenet.

The point of doing it that way is to avoid the redundant specification of string names and (Python) variable names; the cost is that names must have a prefix to invoke __setattr__ magic.

Explicit naming of layers is not currently supported, although layers will be named after their first tops, and that's almost always what is desired.

Is there a reason to be unsatisfied with the __setattr__ way of naming?

@jmerkow
Copy link
Author

jmerkow commented Jul 31, 2015

I did not see that in the tests.
Yes, this allows you to name without netspec for one. I ran that test, and they don't seem to interfere.

Secondly, you can use this PR to dynamically name layers without dealing with setattr (...) since this could be cumbersome.
Say for example, you want 'groups' (or units) that are very similar in structure and chain them together.
You can create a function that reads in a bottom and group name/id and then leaves the internal naming to the function.

i.e. Something like this:

def GenGroup(bottom,grpname):
    conv1 = L.Convolution(bottom, kernel_size=3, num_output=64,
        weight_filler=dict(type='xavier'),top=[grpname+"_conv"])
    relu1 = L.ReLU(conv1, in_place=True)
    return L.Pooling(relu1, kernel_size=2, stride=2, pool=P.Pooling.MAX,top=[grpname+"_pool"])
n = caffe.NetSpec()
n.data, n.label = L.DummyData(shape=[dict(dim=[1, 1, 32, 32]),
                                     dict(dim=[1, 1, 32, 32])],
                          transform_param=dict(scale=1./255), ntop=2)
unit = []
unit.append(n.data)
for i in range(0,3):
    unit.append(GenGroup(unit[-1],"unit"+str(i)))
n.loss = L.SoftmaxWithLoss(unit[-1], n.label)
print(n.to_proto())

produces:

layer {
  name: "data"
  type: "DummyData"
  top: "data"
  top: "label"
  transform_param {
    scale: 0.00392156862745
  }
  dummy_data_param {
    shape {
      dim: 1
      dim: 1
      dim: 32
      dim: 32
    }
    shape {
      dim: 1
      dim: 1
      dim: 32
      dim: 32
    }
  }
}
layer {
  name: "unit0_conv"
  type: "Convolution"
  bottom: "data"
  top: "unit0_conv"
  convolution_param {
    num_output: 64
    kernel_size: 3
    weight_filler {
      type: "xavier"
    }
  }
}
layer {
  name: "ReLU1"
  type: "ReLU"
  bottom: "unit0_conv"
  top: "unit0_conv"
}
layer {
  name: "unit0_pool"
  type: "Pooling"
  bottom: "unit0_conv"
  top: "unit0_pool"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "unit1_conv"
  type: "Convolution"
  bottom: "unit0_pool"
  top: "unit1_conv"
  convolution_param {
    num_output: 64
    kernel_size: 3
    weight_filler {
      type: "xavier"
    }
  }
}
layer {
  name: "ReLU2"
  type: "ReLU"
  bottom: "unit1_conv"
  top: "unit1_conv"
}
layer {
  name: "unit1_pool"
  type: "Pooling"
  bottom: "unit1_conv"
  top: "unit1_pool"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "unit2_conv"
  type: "Convolution"
  bottom: "unit1_pool"
  top: "unit2_conv"
  convolution_param {
    num_output: 64
    kernel_size: 3
    weight_filler {
      type: "xavier"
    }
  }
}
layer {
  name: "ReLU3"
  type: "ReLU"
  bottom: "unit2_conv"
  top: "unit2_conv"
}
layer {
  name: "unit2_pool"
  type: "Pooling"
  bottom: "unit2_conv"
  top: "unit2_pool"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "unit2_pool"
  bottom: "label"
  top: "loss"

You don't need to know the current net, all you need is a top to link to.
--Jameson

@jmerkow
Copy link
Author

jmerkow commented Jul 31, 2015

Oh, FYI, explicit naming of layers works fine because of 'self.params' magic.
This works perfectly fine:

relu1 = L.ReLU(conv1, in_place=True,name=grpname+"_relu")

if you wish to name the relu layer in the above function.

@longjon longjon added the Python label Aug 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants