def test_bilinear_kernel_1D(self): """Test 1D kernels used in bilinear upsampling This method tests the correctness of the 1D kernel values used in bilinear upsampling for some upsampling ratios. """ rat = tensor.iscalar() kernel_ten = bilinear_kernel_1D(ratio=rat, normalize=False) f_ten = theano.function([rat], kernel_ten) kernel_ten_norm = bilinear_kernel_1D(ratio=rat, normalize=True) f_ten_norm = theano.function([rat], kernel_ten_norm) for ratio in [2, 3, 4, 5, 6, 7, 8, 9]: # getting the un-normalized kernel kernel = bilinear_kernel_1D(ratio=ratio, normalize=False) f = theano.function([], kernel) kernel_1D = self.numerical_kernel_1D(ratio) utt.assert_allclose(kernel_1D, f()) utt.assert_allclose(kernel_1D, f_ten(ratio)) # getting the normalized kernel kernel = bilinear_kernel_1D(ratio=ratio, normalize=True) f = theano.function([], kernel) kernel_1D = kernel_1D / float(ratio) utt.assert_allclose(kernel_1D, f()) utt.assert_allclose(kernel_1D, f_ten_norm(ratio))
def _bilinear_upsampling_1D(self, inpt, ratio, batch_size=None, num_input_channels=None): ''' This implementation is a very minimally changed excerpt from: https://github.com/Theano/theano/blob/ddfd7d239a1e656cee850cdbc548da63f349c37d/theano/tensor/nnet/abstract_conv.py#L455 ''' if theano.config.device.startswith('gpu'): from theano.tensor.nnet.abstract_conv import bilinear_kernel_1D, conv2d_grad_wrt_inputs else: raise AssertionError('Bilinear interpolation requires GPU and cuDNN.') try: up_bs = batch_size * num_input_channels except TypeError: up_bs = None row, col = inpt.shape[2:] up_input = inpt.reshape((-1, 1, row, col)) concat_mat = T.concatenate((up_input[:, :, :1, :], up_input, up_input[:, :, -1:, :]), axis=2) pad = 2 * ratio - (ratio - 1) // 2 - 1 kern = bilinear_kernel_1D(ratio=ratio, normalize=True) upsampled_row = conv2d_grad_wrt_inputs( output_grad=concat_mat, filters=kern[np.newaxis, np.newaxis, :, np.newaxis], input_shape=(up_bs, 1, row * ratio, col), filter_shape=(1, 1, None, 1), border_mode=(pad, 0), subsample=(ratio, 1), filter_flip=True ) return upsampled_row.reshape((inpt.shape[0], inpt.shape[1], row * ratio, col * 1))
def _bilinear_upsampling_1D(self, inpt, ratio, batch_size=None, num_input_channels=None): ''' This implementation is a very minimally changed excerpt from: https://github.com/Theano/theano/blob/ddfd7d239a1e656cee850cdbc548da63f349c37d/theano/tensor/nnet/abstract_conv.py#L455 ''' if theano.config.device.startswith('gpu'): from theano.tensor.nnet.abstract_conv import bilinear_kernel_1D, conv2d_grad_wrt_inputs else: raise AssertionError( 'Bilinear interpolation requires GPU and cuDNN.') try: up_bs = batch_size * num_input_channels except TypeError: up_bs = None row, col = inpt.shape[2:] up_input = inpt.reshape((-1, 1, row, col)) concat_mat = T.concatenate( (up_input[:, :, :1, :], up_input, up_input[:, :, -1:, :]), axis=2) pad = 2 * ratio - (ratio - 1) // 2 - 1 kern = bilinear_kernel_1D(ratio=ratio, normalize=True) upsampled_row = conv2d_grad_wrt_inputs(output_grad=concat_mat, filters=kern[np.newaxis, np.newaxis, :, np.newaxis], input_shape=(up_bs, 1, row * ratio, col), filter_shape=(1, 1, None, 1), border_mode=(pad, 0), subsample=(ratio, 1), filter_flip=True) return upsampled_row.reshape( (inpt.shape[0], inpt.shape[1], row * ratio, col * 1))
def bilinear_upsampling(input, ratio, batch_size=None, num_input_channels=None, use_1D_kernel=True): """Compute bilinear upsampling This function will build the symbolic graph for upsampling a tensor by the given ratio using bilinear interpolation. Parameters ---------- input: symbolic 4D tensor mini-batch of feature map stacks, of shape (batch size, input channels, input rows, input columns) that will be upsampled. ratio: `int or Constant or Scalar Tensor of int* dtype` the ratio by which the input is upsampled in the 2D space (row and col size). batch_size: None, int or Constant variable The size of the first dimension of the input variable. Optional, possibly used to choose an optimal implementation. batch_size will be used only if num_input_channels is not None. num_input_channels: None, int or Constant variable The size of the second dimension of the input variable. Optional, possibly used to choose an optimal implementation. num_input_channels will be used only if batch_size is not None. use_1D_kernel: bool if set to true, row and column will be upsampled seperately by 1D kernels, otherwise they are upsampled together using a 2D kernel. The final result is the same, only the speed can differ, given factors such as upsampling ratio. Returns ------- symbolic 4D tensor set of feature maps generated by bilinear upsampling. Tensor is of shape (batch size, num_input_channels, input row size * ratio, input column size * ratio) Notes ----- :note: The kernel used for bilinear interpolation is fixed (not learned). :note: When the upsampling ratio is even, the last row and column is repeated one extra time compared to the first row and column which makes the upsampled tensor asymmetrical on both sides. This does not happen when the upsampling ratio is odd. """ T = theano.tensor try: up_bs = batch_size * num_input_channels except TypeError: up_bs = None row, col = input.shape[2:] up_input = input.reshape((-1, 1, row, col)) # concatenating the first and last row and column # first and last row concat_mat = T.concatenate( (up_input[:, :, :1, :], up_input, up_input[:, :, -1:, :]), axis=2) # first and last col concat_mat = T.concatenate( (concat_mat[:, :, :, :1], concat_mat, concat_mat[:, :, :, -1:]), axis=3) concat_col = col + 2 pad = 2 * ratio - (ratio - 1) // 2 - 1 if use_1D_kernel: kern = bilinear_kernel_1D(ratio=ratio, normalize=True) # upsampling rows upsampled_row = conv2d_grad_wrt_inputs( output_grad=concat_mat, filters=kern[np.newaxis, np.newaxis, :, np.newaxis], input_shape=(up_bs, 1, row * ratio, concat_col), filter_shape=(1, 1, None, 1), border_mode=(pad, 0), subsample=(ratio, 1), filter_flip=True) # upsampling cols upsampled_mat = conv2d_grad_wrt_inputs( output_grad=upsampled_row, filters=kern[np.newaxis, np.newaxis, np.newaxis, :], input_shape=(up_bs, 1, row * ratio, col * ratio), filter_shape=(1, 1, 1, None), border_mode=(0, pad), subsample=(1, ratio), filter_flip=True) else: kern = bilinear_kernel_2D(ratio=ratio, normalize=True) upsampled_mat = conv2d_grad_wrt_inputs( output_grad=concat_mat, filters=kern[np.newaxis, np.newaxis, :, :], input_shape=(up_bs, 1, row * ratio, col * ratio), filter_shape=(1, 1, None, None), border_mode=(pad, pad), subsample=(ratio, ratio), filter_flip=True) return upsampled_mat.reshape( (input.shape[0], input.shape[1], row * ratio, col * ratio))