| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,7 +18,7 @@ class -- assign to its attributes directly to name layers, and call | |||
| 18 | 18 | are not guaranteed to be forward-compatible. | |
| 19 | 19 | """ | |
| 20 | 20 | ||
| 21 | - from collections import OrderedDict | ||
| 21 | + from collections import OrderedDict, Counter | ||
| 22 | 22 | ||
| 23 | 23 | from .proto import caffe_pb2 | |
| 24 | 24 | from google import protobuf | |
@@ -44,10 +44,8 @@ def to_proto(*tops): | |||
| 44 | 44 | """Generate a NetParameter that contains all layers needed to compute | |
| 45 | 45 | all arguments.""" | |
| 46 | 46 | ||
| 47 | - if not isinstance(tops, tuple): | ||
| 48 | - tops = (tops,) | ||
| 49 | 47 | layers = OrderedDict() | |
| 50 | - autonames = {} | ||
| 48 | + autonames = Counter() | ||
| 51 | 49 | for top in tops: | |
| 52 | 50 | top.fn._to_proto(layers, {}, autonames) | |
| 53 | 51 | net = caffe_pb2.NetParameter() | |
@@ -89,6 +87,9 @@ def to_proto(self): | |||
| 89 | 87 | ||
| 90 | 88 | return to_proto(self) | |
| 91 | 89 | ||
| 90 | + def _to_proto(self, layers, names, autonames): | ||
| 91 | + return self.fn._to_proto(layers, names, autonames) | ||
| 92 | + | ||
| 92 | 93 | ||
| 93 | 94 | class Function(object): | |
| 94 | 95 | """A Function specifies a layer, its parameters, and its inputs (which | |
@@ -107,19 +108,26 @@ def __init__(self, type_name, inputs, params): | |||
| 107 | 108 | del self.params['in_place'] | |
| 108 | 109 | self.tops = tuple(Top(self, n) for n in range(self.ntop)) | |
| 109 | 110 | ||
| 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): | ||
| 111 | 120 | if top not in names: | |
| 112 | - n = autonames.setdefault(top.fn.type_name, 1) | ||
| 113 | 121 | 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]) | ||
| 115 | 123 | return names[top] | |
| 116 | 124 | ||
| 117 | 125 | def _to_proto(self, layers, names, autonames): | |
| 118 | 126 | if self in layers: | |
| 119 | 127 | return | |
| 120 | 128 | bottom_names = [] | |
| 121 | 129 | for inp in self.inputs: | |
| 122 | - inp.fn._to_proto(layers, names, autonames) | ||
| 130 | + inp._to_proto(layers, names, autonames) | ||
| 123 | 131 | bottom_names.append(layers[inp.fn].top[inp.n]) | |
| 124 | 132 | layer = caffe_pb2.LayerParameter() | |
| 125 | 133 | layer.type = self.type_name | |
@@ -129,8 +137,8 @@ def _to_proto(self, layers, names, autonames): | |||
| 129 | 137 | layer.top.extend(layer.bottom) | |
| 130 | 138 | else: | |
| 131 | 139 | 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) | ||
| 134 | 142 | ||
| 135 | 143 | for k, v in six.iteritems(self.params): | |
| 136 | 144 | # special case to handle generic *params | |
@@ -163,10 +171,10 @@ def __getattr__(self, name): | |||
| 163 | 171 | ||
| 164 | 172 | def to_proto(self): | |
| 165 | 173 | names = {v: k for k, v in six.iteritems(self.tops)} | |
| 166 | - autonames = {} | ||
| 174 | + autonames = Counter() | ||
| 167 | 175 | layers = OrderedDict() | |
| 168 | 176 | for name, top in six.iteritems(self.tops): | |
| 169 | - top.fn._to_proto(layers, names, autonames) | ||
| 177 | + top._to_proto(layers, names, autonames) | ||
| 170 | 178 | net = caffe_pb2.NetParameter() | |
| 171 | 179 | net.layer.extend(layers.values()) | |
| 172 | 180 | return net | |
@@ -180,7 +188,9 @@ class Layers(object): | |||
| 180 | 188 | def __getattr__(self, name): | |
| 181 | 189 | def layer_fn(*args, **kwargs): | |
| 182 | 190 | fn = Function(name, args, kwargs) | |
| 183 | - if fn.ntop == 1: | ||
| 191 | + if fn.ntop == 0: | ||
| 192 | + return fn | ||
| 193 | + elif fn.ntop == 1: | ||
| 184 | 194 | return fn.tops[0] | |
| 185 | 195 | else: | |
| 186 | 196 | return fn.tops | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,6 +41,14 @@ def anon_lenet(batch_size): | |||
| 41 | 41 | loss = L.SoftmaxWithLoss(ip2, label) | |
| 42 | 42 | return loss.to_proto() | |
| 43 | 43 | ||
| 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 | + | ||
| 44 | 52 | class TestNetSpec(unittest.TestCase): | |
| 45 | 53 | def load_net(self, net_proto): | |
| 46 | 54 | f = tempfile.NamedTemporaryFile(mode='w+', delete=False) | |
@@ -65,3 +73,10 @@ def test_lenet(self): | |||
| 65 | 73 | net_proto.layer[6].top) | |
| 66 | 74 | net = self.load_net(net_proto) | |
| 67 | 75 | 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) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments