def generator_down_sample_hack(input_net, final_num_outputs=16): """ Minic generator_down_sample() but doesn't actually do the downsampling """ # if final_num_outputs % 4 != 0: # raise ValueError('Final number outputs need to be divisible by 4.') # Check the rank of input_net. input_net.shape.assert_has_rank(4) # # Check dimension 1 and dimension 2 are defined and divisible by 4. # if input_net.shape[1]: # if input_net.shape[1] % 4 != 0: # raise ValueError( # 'Dimension 1 of the input should be divisible by 4, but is {} ' # 'instead.'.format(input_net.shape[1])) # else: # raise ValueError('Dimension 1 of the input should be explicitly defined.') # # # Check dimension 1 and dimension 2 are defined and divisible by 4. # if input_net.shape[2]: # if input_net.shape[2] % 4 != 0: # raise ValueError( # 'Dimension 2 of the input should be divisible by 4, but is {} ' # 'instead.'.format(input_net.shape[2])) # else: # raise ValueError('Dimension 2 of the input should be explicitly defined.') with tf.compat.v1.variable_scope('generator_down_sample'): down_sample = ops.pad(input_net, 3) down_sample = _conv2d(inputs=down_sample, filters=final_num_outputs * 4, kernel_size=7, stride=1, name='conv_0') down_sample = tfgan.features.instance_norm(down_sample) down_sample = tf.nn.relu(down_sample) down_sample = ops.pad(down_sample, 2) down_sample = _conv2d(inputs=down_sample, filters=final_num_outputs * 2, kernel_size=5, stride=1, name='conv_1') down_sample = tfgan.features.instance_norm(down_sample) down_sample = tf.nn.relu(down_sample) down_sample = ops.pad(down_sample, 2) down_sample = _conv2d(inputs=down_sample, filters=final_num_outputs, kernel_size=5, stride=1, name='conv_2') # down_sample = tfgan.features.instance_norm(down_sample) # down_sample = tf.nn.relu(down_sample) return down_sample
def _residual_block(input_net, num_outputs, kernel_size, stride=1, padding_size=0, activation_fn=tf.nn.relu, normalizer_fn=None, name='residual_block'): """Residual Block. Input Tensor X - > Conv1 -> IN -> ReLU -> Conv2 -> IN + X PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L7 Args: input_net: Tensor as input. num_outputs: (int) number of output channels for Convolution. kernel_size: (int) size of the square kernel for Convolution. stride: (int) stride for Convolution. Default to 1. padding_size: (int) padding size for Convolution. Default to 0. activation_fn: Activation function. normalizer_fn: Normalization function. name: Name scope Returns: Residual Tensor with the same shape as the input tensor. """ with tf.variable_scope(name): res_block = ops.pad(input_net, padding_size) res_block = _conv2d( inputs=res_block, filters=num_outputs, kernel_size=kernel_size, stride=stride, name='conv_0') if normalizer_fn: res_block = normalizer_fn(res_block) res_block = activation_fn(res_block, name='activation_0') res_block = ops.pad(res_block, padding_size) res_block = _conv2d( inputs=res_block, filters=num_outputs, kernel_size=kernel_size, stride=stride, name='conv_1') if normalizer_fn: res_block = normalizer_fn(res_block) output_net = res_block + input_net return output_net
def test_padding_with_tensor_of_invalid_shape(self): n = 2 invalid_rank = 1 h = 128 w = 64 c = 3 pad = 3 test_input_tensor = tf.random.uniform((n, invalid_rank, h, w, c)) with self.assertRaises(ValueError): ops.pad(test_input_tensor, padding_size=pad)
def discriminator_output_source(input_net): """Output Layer for Source in the Discriminator. Determine if the image is real/fake based on the feature extracted. We follow the original paper design where the output is not a simple (batch_size) shape Tensor but rather a (batch_size, 2, 2, 2048) shape Tensor. We will get the correct shape later when we piece things together. PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L79 Args: input_net: Tensor of shape (batch_size, h / 64, w / 64, 2048) as features. Returns: Tensor of shape (batch_size, h / 64, w / 64, 1) as the score. """ with tf.compat.v1.variable_scope('discriminator_output_source'): output_src = ops.pad(input_net, 1) output_src = _conv2d(inputs=output_src, filters=1, kernel_size=3, stride=1, name='conv') return output_src
def generator_up_sample_hack(input_net, num_outputs): """ Same as generator_up_sample() but doesn't do the up-sampling """ with tf.compat.v1.variable_scope('generator_up_sample'): up_sample = _conv2d_transpose(input_net, filters=128, kernel_size=4, stride=1, name='deconv_0') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) up_sample = up_sample[:, 1:-1, 1:-1, :] up_sample = _conv2d_transpose(up_sample, filters=64, kernel_size=4, stride=1, name='deconv_1') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) up_sample = up_sample[:, 1:-1, 1:-1, :] output_net = ops.pad(up_sample, 2) output_net = _conv2d(inputs=output_net, filters=num_outputs, kernel_size=7, stride=1, name='conv_0') output_net = tf.nn.tanh(output_net) return output_net
def test_padding_with_3D_tensor(self): h = 128 w = 64 c = 3 pad = 3 test_input_tensor = tf.random.uniform((h, w, c)) test_output_tensor = ops.pad(test_input_tensor, padding_size=pad) with self.cached_session() as sess: output = sess.run(test_output_tensor) self.assertTupleEqual((h + pad * 2, w + pad * 2, c), output.shape)
def discriminator_input_hidden(input_net, hidden_layer=6, init_num_outputs=64, scope='discriminator_input_hidden', trainable=True): """Input Layer + Hidden Layer in the Discriminator. Feature extraction pathway in the Discriminator. PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L68 Args: input_net: Tensor of shape (batch_size, h, w, 3) as batch of images. hidden_layer: (int) Number of hidden layers. Default to 6 per the original implementation. init_num_outputs: (int) Number of hidden unit in the first hidden layer. The number of hidden unit double after each layer. Default to 64 per the original implementation. Returns: Tensor of shape (batch_size, h / 64, w / 64, 2048) as features. """ num_outputs = init_num_outputs with tf.compat.v1.variable_scope(scope): hidden = input_net for i in range(hidden_layer): if hidden.get_shape()[1] < 3 or hidden.get_shape()[2] < 3: break hidden = ops.pad(hidden, 1) hidden = _conv2d(inputs=hidden, filters=num_outputs, kernel_size=4, stride=2, name='conv_{}'.format(i), trainable=trainable) hidden = tf.nn.leaky_relu(hidden, alpha=0.01) num_outputs = 2 * num_outputs return hidden
def generator_up_sample(input_net, num_outputs): """Up-sampling module in Generator. Up sampling path for image generation in the Generator. PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L44 Args: input_net: Tensor of shape (batch_size, h / 4, w / 4, 256). num_outputs: (int) Number of channel for the output tensor. Returns: Tensor of shape (batch_size, h, w, num_outputs). """ with tf.compat.v1.variable_scope('generator_up_sample'): up_sample = _conv2d_transpose(input_net, filters=128, kernel_size=4, stride=2, name='deconv_0') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) up_sample = up_sample[:, 1:-1, 1:-1, :] up_sample = _conv2d_transpose(up_sample, filters=64, kernel_size=4, stride=2, name='deconv_1') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) up_sample = up_sample[:, 1:-1, 1:-1, :] output_net = ops.pad(up_sample, 3) output_net = _conv2d(inputs=output_net, filters=num_outputs, kernel_size=7, stride=1, name='conv_0') output_net = tf.nn.tanh(output_net) return output_net
def generator_down_sample(input_net, final_num_outputs=256): """Down-sampling module in Generator. Down sampling pathway of the Generator Architecture: PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L32 Notes: We require dimension 1 and dimension 2 of the input_net to be fully defined for the correct down sampling. Args: input_net: Tensor of shape (batch_size, h, w, c + num_class). final_num_outputs: (int) Number of hidden unit for the final layer. Returns: Tensor of shape (batch_size, h / 4, w / 4, 256). Raises: ValueError: If final_num_outputs are not divisible by 4, or input_net does not have a rank of 4, or dimension 1 and dimension 2 of input_net are not defined at graph construction time, or dimension 1 and dimension 2 of input_net are not divisible by 4. """ if final_num_outputs % 4 != 0: raise ValueError('Final number outputs need to be divisible by 4.') # Check the rank of input_net. input_net.shape.assert_has_rank(4) # Check dimension 1 and dimension 2 are defined and divisible by 4. if input_net.shape[1]: if input_net.shape[1] % 4 != 0: raise ValueError( 'Dimension 1 of the input should be divisible by 4, but is {} ' 'instead.'.format(input_net.shape[1])) else: raise ValueError( 'Dimension 1 of the input should be explicitly defined.') # Check dimension 1 and dimension 2 are defined and divisible by 4. if input_net.shape[2]: if input_net.shape[2] % 4 != 0: raise ValueError( 'Dimension 2 of the input should be divisible by 4, but is {} ' 'instead.'.format(input_net.shape[2])) else: raise ValueError( 'Dimension 2 of the input should be explicitly defined.') with tf.compat.v1.variable_scope('generator_down_sample'): down_sample = ops.pad(input_net, 3) down_sample = _conv2d(inputs=down_sample, filters=final_num_outputs / 4, kernel_size=7, stride=1, name='conv_0') down_sample = tfgan.features.instance_norm(down_sample) down_sample = tf.nn.relu(down_sample) down_sample = ops.pad(down_sample, 1) down_sample = _conv2d(inputs=down_sample, filters=final_num_outputs / 2, kernel_size=4, stride=2, name='conv_1') down_sample = tfgan.features.instance_norm(down_sample) down_sample = tf.nn.relu(down_sample) down_sample = ops.pad(down_sample, 1) output_net = _conv2d(inputs=down_sample, filters=final_num_outputs, kernel_size=4, stride=2, name='conv_2') down_sample = tfgan.features.instance_norm(down_sample) down_sample = tf.nn.relu(down_sample) return output_net
def generator_up_sample_smooth( input_net, num_outputs, conv_kernal_size=5, resize_method=tf.image.ResizeMethod.NEAREST_NEIGHBOR): """Up-sampling module in Generator. Up sampling path for image generation in the Generator. PyTorch Version: https://github.com/yunjey/StarGAN/blob/fbdb6a6ce2a4a92e1dc034faec765e0dbe4b8164/model.py#L44 Args: input_net: Tensor of shape (batch_size, h / 4, w / 4, 256). num_outputs: (int) Number of channel for the output tensor. conv_kernal_size: must be an odd number resize_method: one of the following AREA = 'area' BICUBIC = 'bicubic' BILINEAR = 'bilinear' GAUSSIAN = 'gaussian' LANCZOS3 = 'lanczos3' LANCZOS5 = 'lanczos5' MITCHELLCUBIC = 'mitchellcubic' NEAREST_NEIGHBOR = 'nearest' Returns: Tensor of shape (batch_size, h, w, num_outputs). """ with tf.compat.v1.variable_scope('generator_up_sample'): in_shape = input_net.get_shape().as_list() up_sample = tf.image.resize(input_net, [in_shape[1] * 2, in_shape[2] * 2], method=resize_method) up_sample = ops.pad(up_sample, (conv_kernal_size - 1) // 2) up_sample = _conv2d(up_sample, filters=128, kernel_size=conv_kernal_size, stride=1, name='upsize_conv_0') # up_sample = _conv2d_transpose( # input_net, filters=128, kernel_size=4, stride=2, name='deconv_0') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) # up_sample = up_sample[:, 1:-1, 1:-1, :] up_sample = tf.image.resize(up_sample, [in_shape[1] * 4, in_shape[2] * 4], method=resize_method) up_sample = ops.pad(up_sample, (conv_kernal_size - 1) // 2) up_sample = _conv2d(up_sample, filters=64, kernel_size=conv_kernal_size, stride=1, name='upsize_conv_1') # up_sample = _conv2d_transpose( # up_sample, filters=64, kernel_size=4, stride=2, name='deconv_1') up_sample = tfgan.features.instance_norm(up_sample) up_sample = tf.nn.relu(up_sample) # up_sample = up_sample[:, 1:-1, 1:-1, :] output_net = ops.pad(up_sample, 3) output_net = _conv2d(inputs=output_net, filters=num_outputs, kernel_size=7, stride=1, name='conv_0') output_net = tf.nn.tanh(output_net) # tf.image.resize return output_net