my keras impl
iperov opened this issue · 18 comments
class BlurPool(KL.Layer):
"""
https://arxiv.org/abs/1904.11486 https://github.com/adobe/antialiased-cnns
"""
def __init__(self, filt_size=5, stride=2, **kwargs):
self.strides = (stride,stride)
self.filt_size = filt_size
self.padding = ( (int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2)) ), (int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2)) ) )
if(self.filt_size==1):
self.a = np.array([1.,])
elif(self.filt_size==2):
self.a = np.array([1., 1.])
elif(self.filt_size==3):
self.a = np.array([1., 2., 1.])
elif(self.filt_size==4):
self.a = np.array([1., 3., 3., 1.])
elif(self.filt_size==5):
self.a = np.array([1., 4., 6., 4., 1.])
elif(self.filt_size==6):
self.a = np.array([1., 5., 10., 10., 5., 1.])
elif(self.filt_size==7):
self.a = np.array([1., 6., 15., 20., 15., 6., 1.])
super(BlurPool, self).__init__(**kwargs)
def compute_output_shape(self, input_shape):
height = input_shape[1] // self.strides[0]
width = input_shape[2] // self.strides[1]
channels = input_shape[3]
return (input_shape[0], height, width, channels)
def call(self, x):
k = self.a
k = k[:,None]*k[None,:]
k = k / np.sum(k)
k = np.tile (k[:,:,None,None], (1,1,K.int_shape(x)[-1],1) )
k = K.constant (k, dtype=K.floatx() )
x = K.spatial_2d_padding(x, padding=self.padding)
x = K.depthwise_conv2d(x, k, strides=self.strides, padding='valid')
return x
Is this good enough and is there example code for building a model to replace Conv layer with strides=2?
@off99555 Yes, Conv (stride2)+Relu
should be replaced with Conv(stride1)+Relu+BlurPool(stride2)
. See the readme or antialiased resnet for reference.
@iperov Great! I guess this repo will stay pytorch based for now but nice to have kears too.
@iperov
Thank you for your great work on implementing this great layer using keras. I think it is only good for 2D model. It will be great if you would like to modify it for 3D CNN. Many thanks.
I had to modify compute_output_shape
in the following way to make it work with Conv2D layers preserving the behavior (e.g. in keras.applications.xception.Xception
):
height = math.ceil(input_shape[1] / self.strides[0])
width = math.ceil(input_shape[2] / self.strides[1])
any reason you used depthwise_conv2d
instead of con2d
?
as original
Wow this is great!
- Do you have working version for tensorflow2 tf.keras?
- Is it possible to insert this layers to keras.application models?
This is my TF implementation, though not for tf 2.0
def blur_pool(inp, pad_type='reflect', filter=3, stride=2, pad_off=0):
def pad(inp, pad_sizes, pad_type):
return tf.pad(inp, paddings=pad_sizes, mode=pad_type)
pad_sizes = [int(1.*(filter-1)/2), int(np.ceil(1.*(filter-1)/2)), int(1.*(filter-1)/2), int(np.ceil(1.*(filter-1)/2))]
pad_sizes = [[0,0], [pad_sizes[0]+pad_off, pad_sizes[1]+pad_off], [pad_sizes[2]+pad_off, pad_sizes[3]+pad_off], [0,0]]
if(filter==1):
a = np.array([1.,])
elif(filter==2):
a = np.array([1., 1.])
elif(filter==3):
a = np.array([1., 2., 1.])
elif(filter==4):
a = np.array([1., 3., 3., 1.])
elif(filter==5):
a = np.array([1., 4., 6., 4., 1.])
elif(filter==6):
a = np.array([1., 5., 10., 10., 5., 1.])
elif(filter==7):
a = np.array([1., 6., 15., 20., 15., 6., 1.])
filt = a[:,None]*a[None,:]
filt = filt/np.sum(filt)
filt = np.tile(filt[:, :, None, None], (1,1,int(np.shape(inp)[-1]), 1))
filt = tf.constant(filt)
if(filter==1):
if(pad_off==0):
return inp[:,:,::stride,::stride]
else:
return pad(inp, pad_sizes, pad_type)[:,:,::stride,::stride]
else:
return tf.nn.depthwise_conv2d(pad(inp, pad_sizes, pad_type), tf.cast(filt, tf.float32),
strides=(1, stride, stride, 1), padding='VALID')
Thank you @iperov and @christegho .
I tried to create a little gist for tensorflow2 (tf.keras), however it is till not finished. If someone could help me with it that would be great!
The gist is here:
https://gist.github.com/Cospel/96b88baa589e244b6bf53d47ccfb7a4c
Curious if anyone has had any luck implementing the 1D version. There's no depthwise_conv1d, and the standard playbook to expand_dims and use depthwise_conv2d returns error "Current implementation only supports equal length strides in the row and column dimensions."
Thankyou @iperov and @christegho ! These implementations do help a lot in integration.
Great! but When I predict the U-Net model. I must fix the filt_size and stride to keep the same as the training.
Thanks @iperov for sharing!
I'm on TF 2.1 and I had to add a get_config
so TF/Keras didn't freak out. Here's the method I popped in:
# https://stackoverflow.com/questions/58678836/notimplementederror-layers-with-arguments-in-init-must-override-get-conf/58680354#58680354
def get_config(self):
config = super().get_config().copy()
config.update({
'filt_size': self.filt_size,
'strides': self.strides[0]
})
return config
Hello! I'm on TF1.14 and I had an error as fllow:
AttributeError: 'mappinggroxy' object has no attribute 'update'
So, I want to konw why, what the keras version you used?
I believe I was just using tf.keras
from TF 2.1, not the separate keras
package.
Maybe someone knows how to change the 'compute_output_shape' function when 'input_shape' contains None for free dimensions?
it's better not to use keras or tensorflow. Migrate to pytorch and feel happy.