in tensorflow_compression/python/layers/signal_conv.py [0:0]
def _up_convolve_transpose_explicit(self, inputs, kernel, prepadding):
# Computes upsampling followed by convolution, via transpose convolution ops
# in EXPLICIT mode. This is an efficient implementation of upsampled
# convolutions, where we only compute values that are necessary.
# `conv_transpose` expects the output and input channels in reversed order.
# We implement this by swapping those dimensions of the kernel.
kernel = tf.transpose(
kernel, list(range(self._rank)) + [self._rank + 1, self._rank])
# Compute explicit padding corresponding to the equivalent convolution call,
# and the shape of the output, taking into account any pre-padding.
input_shape = tf.shape(inputs)
padding = (self._rank + 2) * [(0, 0)]
output_shape = [input_shape[0]] + (self._rank + 1) * [None]
if self.data_format == "channels_last":
spatial_axes = range(1, self._rank + 1)
output_shape[-1] = self.filters
else:
spatial_axes = range(2, self._rank + 2)
output_shape[1] = self.filters
if self.extra_pad_end:
get_length = lambda l, s, k, p: l * s + ((k - 1) - p)
else:
get_length = lambda l, s, k, p: l * s + ((k - 1) - (s - 1) - p)
for i, a in enumerate(spatial_axes):
if self.padding == "valid":
padding[a] = 2 * (self.kernel_support[i] - 1,)
else: # same
padding[a] = (
prepadding[i][0] * self.strides_up[i] + self.kernel_support[i] // 2,
prepadding[i][1] * self.strides_up[i] + (
self.kernel_support[i] - 1) // 2,
)
output_shape[a] = get_length(
input_shape[a], self.strides_up[i], self.kernel_support[i],
sum(padding[a]))
data_format = self._op_data_format
# Compute convolution.
if self._rank == 1 and not self.channel_separable:
# `conv1d_transpose` can't do explicit padding, so if that is requested
# we insert an extra dimension and use the 2D op.
extradim = {"channels_first": 2, "channels_last": 1}[self.data_format]
data_format = data_format.replace("W", "HW")
strides = self._padded_tuple(self.strides_up, 1)
strides = strides[:extradim] + (strides[extradim],) + strides[extradim:]
padding = padding[:extradim] + [(0, 0)] + padding[extradim:]
output_shape = output_shape[:extradim] + [1] + output_shape[extradim:]
kernel = tf.expand_dims(kernel, 0)
inputs = tf.expand_dims(inputs, extradim)
outputs = tf.nn.conv2d_transpose(
inputs, kernel, output_shape,
strides=strides, padding=padding, data_format=data_format)
outputs = tf.squeeze(outputs, [extradim])
elif self._rank == 2 and not self.channel_separable:
outputs = tf.nn.conv2d_transpose(
inputs, kernel, output_shape,
strides=self.strides_up, padding=padding, data_format=data_format)
else:
self._raise_notimplemented()
# Perform downsampling if it is requested.
if any(s > 1 for s in self.strides_down):
slices = tuple(slice(None, None, s) for s in self.strides_down)
slices = self._padded_tuple(slices, slice(None))
outputs = outputs[slices]
return outputs