FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Merge pull request #2813 from longjon/net-spec-imp · ysh329/CaffeOnACL@eb3e114 · GitHub

Repository navigation

Commit eb3e114

Browse files
committed
Merge pull request #2813 from longjon/net-spec-imp
Python net spec cleanups and top-less layers
2 parents 311e47b + c80f6f5 commit eb3e114

2 files changed

Lines changed: 38 additions & 13 deletions

File tree

‎python/caffe/net_spec.py‎

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class -- assign to its attributes directly to name layers, and call
1818
are not guaranteed to be forward-compatible.
1919
"""
2020

21-
from collections import OrderedDict
21+
from collections import OrderedDict, Counter
2222

2323
from .proto import caffe_pb2
2424
from google import protobuf
@@ -44,10 +44,8 @@ def to_proto(*tops):
4444
"""Generate a NetParameter that contains all layers needed to compute
4545
all arguments."""
4646

47-
if not isinstance(tops, tuple):
48-
tops = (tops,)
4947
layers = OrderedDict()
50-
autonames = {}
48+
autonames = Counter()
5149
for top in tops:
5250
top.fn._to_proto(layers, {}, autonames)
5351
net = caffe_pb2.NetParameter()
@@ -89,6 +87,9 @@ def to_proto(self):
8987

9088
return to_proto(self)
9189

90+
def _to_proto(self, layers, names, autonames):
91+
return self.fn._to_proto(layers, names, autonames)
92+
9293

9394
class Function(object):
9495
"""A Function specifies a layer, its parameters, and its inputs (which
@@ -107,19 +108,26 @@ def __init__(self, type_name, inputs, params):
107108
del self.params['in_place']
108109
self.tops = tuple(Top(self, n) for n in range(self.ntop))
109110

110-
def _get_name(self, top, names, autonames):
111+
def _get_name(self, names, autonames):
112+
if self not in names and self.ntop > 0:
113+
names[self] = self._get_top_name(self.tops[0], names, autonames)
114+
elif self not in names:
115+
autonames[self.type_name] += 1
116+
names[self] = self.type_name + str(autonames[self.type_name])
117+
return names[self]
118+
119+
def _get_top_name(self, top, names, autonames):
111120
if top not in names:
112-
n = autonames.setdefault(top.fn.type_name, 1)
113121
autonames[top.fn.type_name] += 1
114-
names[top] = top.fn.type_name + str(n)
122+
names[top] = top.fn.type_name + str(autonames[top.fn.type_name])
115123
return names[top]
116124

117125
def _to_proto(self, layers, names, autonames):
118126
if self in layers:
119127
return
120128
bottom_names = []
121129
for inp in self.inputs:
122-
inp.fn._to_proto(layers, names, autonames)
130+
inp._to_proto(layers, names, autonames)
123131
bottom_names.append(layers[inp.fn].top[inp.n])
124132
layer = caffe_pb2.LayerParameter()
125133
layer.type = self.type_name
@@ -129,8 +137,8 @@ def _to_proto(self, layers, names, autonames):
129137
layer.top.extend(layer.bottom)
130138
else:
131139
for top in self.tops:
132-
layer.top.append(self._get_name(top, names, autonames))
133-
layer.name = self._get_name(self.tops[0], names, autonames)
140+
layer.top.append(self._get_top_name(top, names, autonames))
141+
layer.name = self._get_name(names, autonames)
134142

135143
for k, v in six.iteritems(self.params):
136144
# special case to handle generic *params
@@ -163,10 +171,10 @@ def __getattr__(self, name):
163171

164172
def to_proto(self):
165173
names = {v: k for k, v in six.iteritems(self.tops)}
166-
autonames = {}
174+
autonames = Counter()
167175
layers = OrderedDict()
168176
for name, top in six.iteritems(self.tops):
169-
top.fn._to_proto(layers, names, autonames)
177+
top._to_proto(layers, names, autonames)
170178
net = caffe_pb2.NetParameter()
171179
net.layer.extend(layers.values())
172180
return net
@@ -180,7 +188,9 @@ class Layers(object):
180188
def __getattr__(self, name):
181189
def layer_fn(*args, **kwargs):
182190
fn = Function(name, args, kwargs)
183-
if fn.ntop == 1:
191+
if fn.ntop == 0:
192+
return fn
193+
elif fn.ntop == 1:
184194
return fn.tops[0]
185195
else:
186196
return fn.tops

‎python/caffe/test/test_net_spec.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ def anon_lenet(batch_size):
4141
loss = L.SoftmaxWithLoss(ip2, label)
4242
return loss.to_proto()
4343

44+
def silent_net():
45+
n = caffe.NetSpec()
46+
n.data, n.data2 = L.DummyData(shape=[dict(dim=[3]), dict(dim=[4, 2])],
47+
ntop=2)
48+
n.silence_data = L.Silence(n.data, ntop=0)
49+
n.silence_data2 = L.Silence(n.data2, ntop=0)
50+
return n.to_proto()
51+
4452
class TestNetSpec(unittest.TestCase):
4553
def load_net(self, net_proto):
4654
f = tempfile.NamedTemporaryFile(mode='w+', delete=False)
@@ -65,3 +73,10 @@ def test_lenet(self):
6573
net_proto.layer[6].top)
6674
net = self.load_net(net_proto)
6775
self.assertEqual(len(net.layers), 9)
76+
77+
def test_zero_tops(self):
78+
"""Test net construction for top-less layers."""
79+
80+
net_proto = silent_net()
81+
net = self.load_net(net_proto)
82+
self.assertEqual(len(net.forward()), 0)

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL