Implement crop layer as in Caffe for semantic segmentation

789 views
Skip to first unread message

Feng Gu

unread,
Apr 14, 2016, 9:29:31 AM4/14/16
to lasagne-users

I've been trying to implement fully convolutional networks (fcn8s), however I had some difficulty in thecrop layer after deconvolution. I tried to use SliceLayer to perform centerupper or lowerslicing of each axis (width and height), and the results were not satisfactory.

After checking the source of Caffe as here, the crop layer takes two bottom layers (input andconvolution or deconvolution) and outputs a single layer that matches the output shape of input. In addition, it performs differently for convolution and deconvolution based on their parameters, e.g.,kernel sizestride and pad.

Can anyone give some suggestions on how to implement this in Lasagne/Theano? Many thanks in advance.

This was originally posted in https://github.com/Lasagne/Lasagne/issues/660.

Feng Gu

unread,
Apr 14, 2016, 9:35:36 AM4/14/16
to lasagne-users
It seems for `deconvolution`, the `crop` layer perform upscaling by a factor determined by `stride` and shift the coordinates by a `offset=(kernel_size-1)/2-pad`. My question now is if I can pass a `slice` that are not successive (i.e. [0, 4, 8, 12, ...]) to the `SliceLayer` or I should try to use `ElemwiseMergeLayer` instead. 

goo...@jan-schlueter.de

unread,
Apr 14, 2016, 11:36:34 AM4/14/16
to lasagne-users
It seems for `deconvolution`, the `crop` layer perform upscaling by a factor determined by `stride` and shift the coordinates by a `offset=(kernel_size-1)/2-pad`.

Wait, the crop layer does not just crop the tensors to match, it also scales them? If so, neither the SliceLayer nor the ElemwiseMergeLayer can do what you want. Can you give a brief explanation of the exact use case? E.g., a stack of two or three layers and the intended operation of the crop layer for that stack?

Cheers, Jan

goo...@jan-schlueter.de

unread,
Apr 14, 2016, 11:38:34 AM4/14/16
to lasagne-users
My question now is if I can pass a `slice` that are not successive (i.e. [0, 4, 8, 12, ...]) to the `SliceLayer`

If you want to take every 4th element, this would be a SliceLayer(layer, slice(None, None, 4), axis=...). This is equivalent to x[::4] on a Python list (or numpy or Theano tensor).

Feng Gu

unread,
Apr 18, 2016, 6:09:02 AM4/18/16
to lasagne-users, goo...@jan-schlueter.de
Hi Jan,

That's definitely good know, but is it possible to take a step further and pass a random set of indices (e.g. [1, 2, 7, 20, 50, ...]) to "slice"?

Many thanks.

goo...@jan-schlueter.de

unread,
Apr 18, 2016, 1:03:45 PM4/18/16
to lasagne-users
Hey,


That's definitely good know, but is it possible to take a step further and pass a random set of indices (e.g. [1, 2, 7, 20, 50, ...]) to "slice"?

In theory yes, Theano supports that, but the SliceLayer currently doesn't. Seems this use case hasn't come up yet. Would you be willing to file a pull request?
Otherwise, for a quick solution, you could use ExpressionLayer(layer, lambda X: X[:, [1, 2, 7, 20, 50]]) to grab elements 1, 2, 7, 20, 50 from the second axis.

But why would you need to extract a nonregular set of indices?

Best, Jan

emolson

unread,
Apr 18, 2016, 1:39:24 PM4/18/16
to lasagne-users, goo...@jan-schlueter.de
I did that in order to implement fractional pooling. Unfortunately it was pretty slow.

goo...@jan-schlueter.de

unread,
Apr 18, 2016, 3:42:26 PM4/18/16
to lasagne-users
 But why would you need to extract a nonregular set of indices?
 
I did that in order to implement fractional pooling.

So there are uses cases for it, but I meant: What does Feng Gu need this for in implementing the fully-convolutional net fcn8s?

Feng Gu

unread,
Apr 20, 2016, 6:40:26 AM4/20/16
to lasagne-users, goo...@jan-schlueter.de
Thanks very much for all the replies. After checking the Caffe outputs thoroughly, I found their implementation of cropping is centre crop with some offset. The value of offset is calculated based the type of layers (convolution and deconvolution) and their parameters, e.g. kernel size, stride and pad. I have resolved my issue by using existing SliceLayer with some offset. 

Florian

unread,
May 1, 2016, 1:54:28 PM5/1/16
to lasagne-users
Hello,

I am trying to implement a fcn with lasagne however I got some difficulty with the CropLayer too. Can you share your code or maybe push it to Lasagne ?

Best,
Florian

Feng Gu

unread,
May 4, 2016, 9:57:03 AM5/4/16
to lasagne-users, thef...@gmail.com
The following is a crop layer implementation using the SliceLayer:
    net = {}
    net['crop1'] = SliceLayer(input_layer,
                              indices=slice(index_1[0], index_1[1]),
                              axis=-1)
    net['output'] = SliceLayer(net['crop1'],
                               indices=slice(index_2[0], index_2[1]),
                               axis=-2)
You need to compute the indices first, and then pass them to the SliceLayer.  Hope this helps.

Feng Gu

unread,
May 4, 2016, 10:07:23 AM5/4/16
to lasagne-users, thef...@gmail.com
This is inspired by "build_inception_module" in https://github.com/Lasagne/Recipes/blob/master/modelzoo/googlenet.py.
Reply all
Reply to author
Forward
0 new messages