summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorEvan Shelhamer <shelhamer@imaginarynumber.net>2016-03-03 16:39:18 -0800
committerEvan Shelhamer <shelhamer@imaginarynumber.net>2016-03-04 19:09:51 -0800
commit880e1474270523e3e5585a14a370fda39bb743c1 (patch)
tree55a327f5a202931f8adc8fc0be78df6aa5ae3460 /python
parent25b9ef95f35a4de766500c9c70a18d839a5f7c70 (diff)
downloadcaffeonacl-880e1474270523e3e5585a14a370fda39bb743c1.tar.gz
caffeonacl-880e1474270523e3e5585a14a370fda39bb743c1.tar.bz2
caffeonacl-880e1474270523e3e5585a14a370fda39bb743c1.zip
[pycaffe] test coord_map
- test known mappings: conv-pool-deconv stack, ReLU and 1x1 conv - test effects of padding - test rectangular/anisotropic coordinate mapping, test N-D - catch error cases: negative crop, scale mismatch, tops that are not spatially connected
Diffstat (limited to 'python')
-rw-r--r--python/caffe/test/test_coord_map.py192
1 files changed, 192 insertions, 0 deletions
diff --git a/python/caffe/test/test_coord_map.py b/python/caffe/test/test_coord_map.py
new file mode 100644
index 00000000..613260e2
--- /dev/null
+++ b/python/caffe/test/test_coord_map.py
@@ -0,0 +1,192 @@
+import unittest
+
+import numpy as np
+import random
+
+import caffe
+from caffe import layers as L
+from caffe import params as P
+from caffe.coord_map import coord_map_from_to, crop
+
+
+def coord_net_spec(ks=3, stride=1, pad=0, pool=2, dstride=2, dpad=0):
+ """
+ Define net spec for simple conv-pool-deconv pattern common to all
+ coordinate mapping tests.
+ """
+ n = caffe.NetSpec()
+ n.data = L.Input(shape=dict(dim=[2, 1, 100, 100]))
+ n.aux = L.Input(shape=dict(dim=[2, 1, 20, 20]))
+ n.conv = L.Convolution(
+ n.data, num_output=10, kernel_size=ks, stride=stride, pad=pad)
+ n.pool = L.Pooling(
+ n.conv, pool=P.Pooling.MAX, kernel_size=pool, stride=pool, pad=0)
+ # for upsampling kernel size is 2x stride
+ try:
+ deconv_ks = [s*2 for s in dstride]
+ except:
+ deconv_ks = dstride*2
+ n.deconv = L.Deconvolution(
+ n.pool, num_output=10, kernel_size=deconv_ks, stride=dstride, pad=dpad)
+ return n
+
+
+class TestCoordMap(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_conv_pool_deconv(self):
+ """
+ Map through conv, pool, and deconv.
+ """
+ n = coord_net_spec()
+ # identity for 2x pool, 2x deconv
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(ax, 1)
+ self.assertEquals(a, 1)
+ self.assertEquals(b, 0)
+ # shift-by-one for 4x pool, 4x deconv
+ n = coord_net_spec(pool=4, dstride=4)
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(ax, 1)
+ self.assertEquals(a, 1)
+ self.assertEquals(b, -1)
+
+ def test_pass(self):
+ """
+ A pass-through layer (ReLU) and conv (1x1, stride 1, pad 0)
+ both do identity mapping.
+ """
+ n = coord_net_spec()
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ n.relu = L.ReLU(n.deconv)
+ n.conv1x1 = L.Convolution(
+ n.relu, num_output=10, kernel_size=1, stride=1, pad=0)
+ for top in [n.relu, n.conv1x1]:
+ ax_pass, a_pass, b_pass = coord_map_from_to(top, n.data)
+ self.assertEquals(ax, ax_pass)
+ self.assertEquals(a, a_pass)
+ self.assertEquals(b, b_pass)
+
+ def test_padding(self):
+ """
+ Padding conv adds offset while padding deconv subtracts offset.
+ """
+ n = coord_net_spec()
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ pad = random.randint(0, 10)
+ # conv padding
+ n = coord_net_spec(pad=pad)
+ _, a_pad, b_pad = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(a, a_pad)
+ self.assertEquals(b - pad, b_pad)
+ # deconv padding
+ n = coord_net_spec(dpad=pad)
+ _, a_pad, b_pad = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(a, a_pad)
+ self.assertEquals(b + pad, b_pad)
+ # pad both to cancel out
+ n = coord_net_spec(pad=pad, dpad=pad)
+ _, a_pad, b_pad = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(a, a_pad)
+ self.assertEquals(b, b_pad)
+
+ def test_multi_conv(self):
+ """
+ Multiple bottoms/tops of a layer are identically mapped.
+ """
+ n = coord_net_spec()
+ # multi bottom/top
+ n.conv_data, n.conv_aux = L.Convolution(
+ n.data, n.aux, ntop=2, num_output=10, kernel_size=5, stride=2,
+ pad=0)
+ ax1, a1, b1 = coord_map_from_to(n.conv_data, n.data)
+ ax2, a2, b2 = coord_map_from_to(n.conv_aux, n.aux)
+ self.assertEquals(ax1, ax2)
+ self.assertEquals(a1, a2)
+ self.assertEquals(b1, b2)
+
+ def test_rect(self):
+ """
+ Anisotropic mapping is equivalent to its isotropic parts.
+ """
+ n3x3 = coord_net_spec(ks=3, stride=1, pad=0)
+ n5x5 = coord_net_spec(ks=5, stride=2, pad=10)
+ n3x5 = coord_net_spec(ks=[3, 5], stride=[1, 2], pad=[0, 10])
+ ax_3x3, a_3x3, b_3x3 = coord_map_from_to(n3x3.deconv, n3x3.data)
+ ax_5x5, a_5x5, b_5x5 = coord_map_from_to(n5x5.deconv, n5x5.data)
+ ax_3x5, a_3x5, b_3x5 = coord_map_from_to(n3x5.deconv, n3x5.data)
+ self.assertTrue(ax_3x3 == ax_5x5 == ax_3x5)
+ self.assertEquals(a_3x3, a_3x5[0])
+ self.assertEquals(b_3x3, b_3x5[0])
+ self.assertEquals(a_5x5, a_3x5[1])
+ self.assertEquals(b_5x5, b_3x5[1])
+
+ def test_nd_conv(self):
+ """
+ ND conv maps the same way in more dimensions.
+ """
+ n = caffe.NetSpec()
+ # define data with 3 spatial dimensions, otherwise the same net
+ n.data = L.Input(shape=dict(dim=[2, 3, 100, 100, 100]))
+ n.conv = L.Convolution(
+ n.data, num_output=10, kernel_size=[3, 3, 3], stride=[1, 1, 1],
+ pad=[0, 1, 2])
+ n.pool = L.Pooling(
+ n.conv, pool=P.Pooling.MAX, kernel_size=2, stride=2, pad=0)
+ n.deconv = L.Deconvolution(
+ n.pool, num_output=10, kernel_size=4, stride=2, pad=0)
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ self.assertEquals(ax, 1)
+ self.assertTrue(len(a) == len(b))
+ self.assertTrue(np.all(a == 1))
+ self.assertEquals(b[0] - 1, b[1])
+ self.assertEquals(b[1] - 1, b[2])
+
+ def test_crop_of_crop(self):
+ """
+ Map coordinates through Crop layer:
+ crop an already-cropped output to the input and check change in offset.
+ """
+ n = coord_net_spec()
+ offset = random.randint(0, 10)
+ ax, a, b = coord_map_from_to(n.deconv, n.data)
+ n.crop = L.Crop(n.deconv, n.data, axis=2, offset=offset)
+ ax_crop, a_crop, b_crop = coord_map_from_to(n.crop, n.data)
+ self.assertEquals(ax, ax_crop)
+ self.assertEquals(a, a_crop)
+ self.assertEquals(b + offset, b_crop)
+
+ def test_crop_helper(self):
+ """
+ Define Crop layer by crop().
+ """
+ n = coord_net_spec()
+ crop(n.deconv, n.data)
+
+ def test_catch_unconnected(self):
+ """
+ Catch mapping spatially unconnected tops.
+ """
+ n = coord_net_spec()
+ n.ip = L.InnerProduct(n.deconv, num_output=10)
+ with self.assertRaises(RuntimeError):
+ coord_map_from_to(n.ip, n.data)
+
+ def test_catch_scale_mismatch(self):
+ """
+ Catch incompatible scales, such as when the top to be cropped
+ is mapped to a differently strided reference top.
+ """
+ n = coord_net_spec(pool=3, dstride=2) # pool 3x but deconv 2x
+ with self.assertRaises(AssertionError):
+ crop(n.deconv, n.data)
+
+ def test_catch_negative_crop(self):
+ """
+ Catch impossible offsets, such as when the top to be cropped
+ is mapped to a larger reference top.
+ """
+ n = coord_net_spec(dpad=10) # make output smaller than input
+ with self.assertRaises(AssertionError):
+ crop(n.deconv, n.data)