tscohen / GrouPy

Group Equivariant Convolutional Neural Networks
http://ta.co.nl
Other
349 stars 85 forks source link

Group equivariant pooling #26

Closed andreeabir closed 2 years ago

andreeabir commented 2 years ago

Hi,

I have a question regarding the implementation of equivariant pooling. I found in your experiments the usage of function imported from . In this implementation, the rotation axis and channel axis are fold together, perform 2d spatial pooling and then unfold. I have used the same implementation in Pytorch and tested if my P4CNN using pooling is equivariant using the code below. I found that when I add after each GConv, the network is not equivariant and the test fails. However, when I am not using , the GCNN is equivariant and the test pass. I don't understand if the pooling layer implemented like this is equivariant or not, or I am testing wrong the equivariance of the network. Can you help me please?

def test_p4_net_equivariance():
    from groupy.gfunc import Z2FuncArray, P4FuncArray
    import groupy.garray.C4_array as c4a

    im = np.random.randn(1, 1, 96, 96).astype('float32')
    check_equivariance(
        im=im,
        layers=[
            P4ConvZ2(in_channels=1, out_channels=2, kernel_size=3),
            P4ConvP4(in_channels=2, out_channels=3, kernel_size=3)
        ],
        input_array=Z2FuncArray,
        output_array=P4FuncArray,
        point_group=c4a,
    )

def check_equivariance(im, layers, input_array, output_array, point_group):
    # Transform the image
    f = input_array(im)
    g = point_group.rand()
    gf = g * f
    im1 = gf.v
    # Apply layers to both images
    im = Variable(torch.Tensor(im))
    im1 = Variable(torch.Tensor(im1))

    fmap = im
    fmap1 = im1
    for layer in layers:
        fmap = layer(fmap)
        fmap = plane_group_spatial_max_pooling(fmap, ksize=2, stride=1)
        fmap1 = layer(fmap1)
        fmap1 = plane_group_spatial_max_pooling(fmap1, ksize=2, stride=1)

    # Transform the computed feature maps
    fmap1_garray = output_array(fmap1.data.numpy())
    r_fmap1_data = (g.inv() * fmap1_garray).v

    fmap_data = fmap.data.numpy()
    assert np.allclose(fmap_data, r_fmap1_data, rtol=1e-5, atol=1e-3)

if __name__ == '__main__':
    test_p4_net_equivariance()
tscohen commented 2 years ago

Hi andreeabir,

I don't have much time to check your code, but you'll want to make sure that the pooling regions (2x2) are mapped onto each other by the rotation. Ie each pooling region is mapped to exactly one pooling region. This will depend on the image size and whether it's odd or even, and what you use as rotation center (the center of a pixel or the place between 4 pixels). You should be able to test the equivariance of this operation in isolation, which may be easier.

andreeabir commented 2 years ago

Hi,

Thank you for the quick response. I have tested the equivariance of the maxpool operation in isolation and indeed I found that there were some problems in the test code depending on the image size (odd or even). Thanks for the guidance.