diff --git a/lessonFour/cyclegan/__pycache__/cyclegan.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/cyclegan.cpython-36.pyc new file mode 100644 index 0000000..5d75739 Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/cyclegan.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/__pycache__/data_provider.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/data_provider.cpython-36.pyc new file mode 100644 index 0000000..2c2ab4f Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/data_provider.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/__pycache__/getConfig.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/getConfig.cpython-36.pyc new file mode 100644 index 0000000..564aa6d Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/getConfig.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/__pycache__/networks.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/networks.cpython-36.pyc new file mode 100644 index 0000000..a4d374f Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/networks.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/__pycache__/pix2pix.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/pix2pix.cpython-36.pyc new file mode 100644 index 0000000..99a86fd Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/pix2pix.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/__pycache__/train.cpython-36.pyc b/lessonFour/cyclegan/__pycache__/train.cpython-36.pyc new file mode 100644 index 0000000..52f6ae3 Binary files /dev/null and b/lessonFour/cyclegan/__pycache__/train.cpython-36.pyc differ diff --git a/lessonFour/cyclegan/config.ini b/lessonFour/cyclegan/config.ini new file mode 100644 index 0000000..729a411 --- /dev/null +++ b/lessonFour/cyclegan/config.ini @@ -0,0 +1,53 @@ +[ints] + +ps_tasks=0 + +task=0 + +batch_size=1 + +patch_size=64 + +#最大的训练步数 +max_number_of_steps=5 + +patch_dim=128 + + +[floats] + + +generator_lr=0.0002 + +discriminator_lr=0.0001 + +cycle_consistency_loss_weight=10.0 + + + +[strings] +#运行模式的模式 +mode = train +master= + +#训练的图片 +image_set_x_file_pattern=train_img/sky.jpg +#风格图片 +image_set_y_file_pattern=style_img/scream.jpg +#Model的保存位置 +train_log_dir=model_log_data/ +#进行风格迁移使用的Model +checkpoint_path=model_log_data/model.ckpt-30 + + +generated_x_dir=generated_x/ + +generated_y_dir=trans_out_img/ + +image_set_y_glob= + + + + + + diff --git a/lessonFour/cyclegan/cyclegan.py b/lessonFour/cyclegan/cyclegan.py new file mode 100755 index 0000000..ee5f4a8 --- /dev/null +++ b/lessonFour/cyclegan/cyclegan.py @@ -0,0 +1,273 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Defines the CycleGAN generator and discriminator networks.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +from six.moves import xrange # pylint: disable=redefined-builtin +import tensorflow as tf + +layers = tf.contrib.layers + + +def cyclegan_arg_scope(instance_norm_center=True, + instance_norm_scale=True, + instance_norm_epsilon=0.001, + weights_init_stddev=0.02, + weight_decay=0.0): + """Returns a default argument scope for all generators and discriminators. + + Args: + instance_norm_center: Whether instance normalization applies centering. + instance_norm_scale: Whether instance normalization applies scaling. + instance_norm_epsilon: Small float added to the variance in the instance + normalization to avoid dividing by zero. + weights_init_stddev: Standard deviation of the random values to initialize + the convolution kernels with. + weight_decay: Magnitude of weight decay applied to all convolution kernel + variables of the generator. + + Returns: + An arg-scope. + """ + instance_norm_params = { + 'center': instance_norm_center, + 'scale': instance_norm_scale, + 'epsilon': instance_norm_epsilon, + } + + weights_regularizer = None + if weight_decay and weight_decay > 0.0: + weights_regularizer = layers.l2_regularizer(weight_decay) + + with tf.contrib.framework.arg_scope( + [layers.conv2d], + normalizer_fn=layers.instance_norm, + normalizer_params=instance_norm_params, + weights_initializer=tf.random_normal_initializer(0, weights_init_stddev), + weights_regularizer=weights_regularizer) as sc: + return sc + + +def cyclegan_upsample(net, num_outputs, stride, method='conv2d_transpose'): + """Upsamples the given inputs. + + Args: + net: A Tensor of size [batch_size, height, width, filters]. + num_outputs: The number of output filters. + stride: A list of 2 scalars or a 1x2 Tensor indicating the scale, + relative to the inputs, of the output dimensions. For example, if kernel + size is [2, 3], then the output height and width will be twice and three + times the input size. + method: The upsampling method: 'nn_upsample_conv', 'bilinear_upsample_conv', + or 'conv2d_transpose'. + + Returns: + A Tensor which was upsampled using the specified method. + + Raises: + ValueError: if `method` is not recognized. + """ + with tf.variable_scope('upconv'): + net_shape = tf.shape(net) + height = net_shape[1] + width = net_shape[2] + + # Reflection pad by 1 in spatial dimensions (axes 1, 2 = h, w) to make a 3x3 + # 'valid' convolution produce an output with the same dimension as the + # input. + spatial_pad_1 = np.array([[0, 0], [1, 1], [1, 1], [0, 0]]) + + if method == 'nn_upsample_conv': + net = tf.image.resize_nearest_neighbor( + net, [stride[0] * height, stride[1] * width]) + net = tf.pad(net, spatial_pad_1, 'REFLECT') + net = layers.conv2d(net, num_outputs, kernel_size=[3, 3], padding='valid') + elif method == 'bilinear_upsample_conv': + net = tf.image.resize_bilinear( + net, [stride[0] * height, stride[1] * width]) + net = tf.pad(net, spatial_pad_1, 'REFLECT') + net = layers.conv2d(net, num_outputs, kernel_size=[3, 3], padding='valid') + elif method == 'conv2d_transpose': + # This corrects 1 pixel offset for images with even width and height. + # conv2d is left aligned and conv2d_transpose is right aligned for even + # sized images (while doing 'SAME' padding). + # Note: This doesn't reflect actual model in paper. + net = layers.conv2d_transpose( + net, num_outputs, kernel_size=[3, 3], stride=stride, padding='valid') + net = net[:, 1:, 1:, :] + else: + raise ValueError('Unknown method: [%s]', method) + + return net + + +def _dynamic_or_static_shape(tensor): + shape = tf.shape(tensor) + static_shape = tf.contrib.util.constant_value(shape) + return static_shape if static_shape is not None else shape + + +def cyclegan_generator_resnet(images, + arg_scope_fn=cyclegan_arg_scope, + num_resnet_blocks=6, + num_filters=64, + upsample_fn=cyclegan_upsample, + kernel_size=3, + num_outputs=3, + tanh_linear_slope=0.0, + is_training=False): + """Defines the cyclegan resnet network architecture. + + As closely as possible following + https://github.com/junyanz/CycleGAN/blob/master/models/architectures.lua#L232 + + FYI: This network requires input height and width to be divisible by 4 in + order to generate an output with shape equal to input shape. Assertions will + catch this if input dimensions are known at graph construction time, but + there's no protection if unknown at graph construction time (you'll see an + error). + + Args: + images: Input image tensor of shape [batch_size, h, w, 3]. + arg_scope_fn: Function to create the global arg_scope for the network. + num_resnet_blocks: Number of ResNet blocks in the middle of the generator. + num_filters: Number of filters of the first hidden layer. + upsample_fn: Upsampling function for the decoder part of the generator. + kernel_size: Size w or list/tuple [h, w] of the filter kernels for all inner + layers. + num_outputs: Number of output layers. Defaults to 3 for RGB. + tanh_linear_slope: Slope of the linear function to add to the tanh over the + logits. + is_training: Whether the network is created in training mode or inference + only mode. Not actually needed, just for compliance with other generator + network functions. + + Returns: + A `Tensor` representing the model output and a dictionary of model end + points. + + Raises: + ValueError: If the input height or width is known at graph construction time + and not a multiple of 4. + """ + # Neither dropout nor batch norm -> dont need is_training + del is_training + + end_points = {} + + input_size = images.shape.as_list() + height, width = input_size[1], input_size[2] + if height and height % 4 != 0: + raise ValueError('The input height must be a multiple of 4.') + if width and width % 4 != 0: + raise ValueError('The input width must be a multiple of 4.') + + if not isinstance(kernel_size, (list, tuple)): + kernel_size = [kernel_size, kernel_size] + + kernel_height = kernel_size[0] + kernel_width = kernel_size[1] + pad_top = (kernel_height - 1) // 2 + pad_bottom = kernel_height // 2 + pad_left = (kernel_width - 1) // 2 + pad_right = kernel_width // 2 + paddings = np.array( + [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], + dtype=np.int32) + spatial_pad_3 = np.array([[0, 0], [3, 3], [3, 3], [0, 0]]) + + with tf.contrib.framework.arg_scope(arg_scope_fn()): + + ########### + # Encoder # + ########### + with tf.variable_scope('input'): + # 7x7 input stage + net = tf.pad(images, spatial_pad_3, 'REFLECT') + net = layers.conv2d(net, num_filters, kernel_size=[7, 7], padding='VALID') + end_points['encoder_0'] = net + + with tf.variable_scope('encoder'): + with tf.contrib.framework.arg_scope( + [layers.conv2d], + kernel_size=kernel_size, + stride=2, + activation_fn=tf.nn.relu, + padding='VALID'): + + net = tf.pad(net, paddings, 'REFLECT') + net = layers.conv2d(net, num_filters * 2) + end_points['encoder_1'] = net + net = tf.pad(net, paddings, 'REFLECT') + net = layers.conv2d(net, num_filters * 4) + end_points['encoder_2'] = net + + ################### + # Residual Blocks # + ################### + with tf.variable_scope('residual_blocks'): + with tf.contrib.framework.arg_scope( + [layers.conv2d], + kernel_size=kernel_size, + stride=1, + activation_fn=tf.nn.relu, + padding='VALID'): + for block_id in xrange(num_resnet_blocks): + with tf.variable_scope('block_{}'.format(block_id)): + res_net = tf.pad(net, paddings, 'REFLECT') + res_net = layers.conv2d(res_net, num_filters * 4) + res_net = tf.pad(res_net, paddings, 'REFLECT') + res_net = layers.conv2d(res_net, num_filters * 4, + activation_fn=None) + net += res_net + + end_points['resnet_block_%d' % block_id] = net + + ########### + # Decoder # + ########### + with tf.variable_scope('decoder'): + + with tf.contrib.framework.arg_scope( + [layers.conv2d], + kernel_size=kernel_size, + stride=1, + activation_fn=tf.nn.relu): + + with tf.variable_scope('decoder1'): + net = upsample_fn(net, num_outputs=num_filters * 2, stride=[2, 2]) + end_points['decoder1'] = net + + with tf.variable_scope('decoder2'): + net = upsample_fn(net, num_outputs=num_filters, stride=[2, 2]) + end_points['decoder2'] = net + + with tf.variable_scope('output'): + net = tf.pad(net, spatial_pad_3, 'REFLECT') + logits = layers.conv2d( + net, + num_outputs, [7, 7], + activation_fn=None, + normalizer_fn=None, + padding='valid') + logits = tf.reshape(logits, _dynamic_or_static_shape(images)) + + end_points['logits'] = logits + end_points['predictions'] = tf.tanh(logits) + logits * tanh_linear_slope + + return end_points['predictions'], end_points diff --git a/lessonFour/cyclegan/data_provider.py b/lessonFour/cyclegan/data_provider.py new file mode 100755 index 0000000..04d122e --- /dev/null +++ b/lessonFour/cyclegan/data_provider.py @@ -0,0 +1,171 @@ + + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +import numpy as np +import tensorflow as tf + + +def normalize_image(image): + """Rescale from range [0, 255] to [-1, 1].""" + return (tf.to_float(image) - 127.5) / 127.5 + + +def undo_normalize_image(normalized_image): + """Convert to a numpy array that can be read by PIL.""" + # Convert from NHWC to HWC. + normalized_image = np.squeeze(normalized_image, axis=0) + return np.uint8(normalized_image * 127.5 + 127.5) + + +def _sample_patch(image, patch_size): + """Crop image to square shape and resize it to `patch_size`. + + Args: + image: A 3D `Tensor` of HWC format. + patch_size: A Python scalar. The output image size. + + Returns: + A 3D `Tensor` of HWC format which has the shape of + [patch_size, patch_size, 3]. + """ + image_shape = tf.shape(image) + height, width = image_shape[0], image_shape[1] + target_size = tf.minimum(height, width) + image = tf.image.resize_image_with_crop_or_pad(image, target_size, + target_size) + # tf.image.resize_area only accepts 4D tensor, so expand dims first. + image = tf.expand_dims(image, axis=0) + image = tf.image.resize_images(image, [patch_size, patch_size]) + image = tf.squeeze(image, axis=0) + # Force image num_channels = 3 + image = tf.tile(image, [1, 1, tf.maximum(1, 4 - tf.shape(image)[2])]) + image = tf.slice(image, [0, 0, 0], [patch_size, patch_size, 3]) + return image + + +def full_image_to_patch(image, patch_size): + image = normalize_image(image) + # Sample a patch of fixed size. + image_patch = _sample_patch(image, patch_size) + image_patch.shape.assert_is_compatible_with([patch_size, patch_size, 3]) + return image_patch + + +def _provide_custom_dataset(image_file_pattern, + batch_size, + shuffle=True, + num_threads=1, + patch_size=128): + """Provides batches of custom image data. + + Args: + image_file_pattern: A string of glob pattern of image files. + batch_size: The number of images in each batch. + shuffle: Whether to shuffle the read images. Defaults to True. + num_threads: Number of mapping threads. Defaults to 1. + patch_size: Size of the path to extract from the image. Defaults to 128. + + Returns: + A tf.data.Dataset with Tensors of shape + [batch_size, patch_size, patch_size, 3] representing a batch of images. + + Raises: + ValueError: If no files match `image_file_pattern`. + """ + if not tf.gfile.Glob(image_file_pattern): + raise ValueError('No file patterns found.') + filenames_ds = tf.data.Dataset.list_files(image_file_pattern) + bytes_ds = filenames_ds.map(tf.io.read_file, num_parallel_calls=num_threads) + images_ds = bytes_ds.map( + tf.image.decode_image, num_parallel_calls=num_threads) + patches_ds = images_ds.map( + lambda img: full_image_to_patch(img, patch_size), + num_parallel_calls=num_threads) + patches_ds = patches_ds.repeat() + + if shuffle: + patches_ds = patches_ds.shuffle(5 * batch_size) + + patches_ds = patches_ds.prefetch(5 * batch_size) + patches_ds = patches_ds.batch(batch_size) + + return patches_ds + + +def provide_custom_datasets(image_file_patterns, + batch_size, + shuffle=True, + num_threads=1, + patch_size=128): + """Provides multiple batches of custom image data. + + Args: + image_file_patterns: A list of glob patterns of image files. + batch_size: The number of images in each batch. + shuffle: Whether to shuffle the read images. Defaults to True. + num_threads: Number of prefetching threads. Defaults to 1. + patch_size: Size of the patch to extract from the image. Defaults to 128. + + Returns: + A list of tf.data.Datasets the same number as `image_file_patterns`. Each + of the datasets have `Tensor`'s in the list has a shape of + [batch_size, patch_size, patch_size, 3] representing a batch of images. + + Raises: + ValueError: If image_file_patterns is not a list or tuple. + """ + if not isinstance(image_file_patterns, (list, tuple)): + raise ValueError( + '`image_file_patterns` should be either list or tuple, but was {}.'. + format(type(image_file_patterns))) + custom_datasets = [] + for pattern in image_file_patterns: + custom_datasets.append( + _provide_custom_dataset( + pattern, + batch_size=batch_size, + shuffle=shuffle, + num_threads=num_threads, + patch_size=patch_size)) + + return custom_datasets + + +def provide_custom_data(image_file_patterns, + batch_size, + shuffle=True, + num_threads=1, + patch_size=128): + """Provides multiple batches of custom image data. + + Args: + image_file_patterns: A list of glob patterns of image files. + batch_size: The number of images in each batch. + shuffle: Whether to shuffle the read images. Defaults to True. + num_threads: Number of prefetching threads. Defaults to 1. + patch_size: Size of the patch to extract from the image. Defaults to 128. + + Returns: + A list of float `Tensor`s with the same size of `image_file_patterns`. Each + of the `Tensor` in the list has a shape of + [batch_size, patch_size, patch_size, 3] representing a batch of images. As a + side effect, the tf.Dataset initializer is added to the + tf.GraphKeys.TABLE_INITIALIZERS collection. + + Raises: + ValueError: If image_file_patterns is not a list or tuple. + """ + datasets = provide_custom_datasets( + image_file_patterns, batch_size, shuffle, num_threads, patch_size) + + tensors = [] + for ds in datasets: + iterator = ds.make_initializable_iterator() + tf.add_to_collection(tf.GraphKeys.TABLE_INITIALIZERS, iterator.initializer) + tensors.append(iterator.get_next()) + + return tensors diff --git a/lessonFour/cyclegan/getConfig.py b/lessonFour/cyclegan/getConfig.py new file mode 100644 index 0000000..4421059 --- /dev/null +++ b/lessonFour/cyclegan/getConfig.py @@ -0,0 +1,9 @@ +import configparser +def get_config(config_file='config.ini'): + parser=configparser.ConfigParser() + parser.read(config_file) + # get the ints, floats and strings + _conf_ints = [(key, int(value)) for key, value in parser.items('ints')] + _conf_floats = [(key, float(value)) for key, value in parser.items('floats')] + _conf_strings = [(key, str(value)) for key, value in parser.items('strings')] + return dict(_conf_ints + _conf_floats + _conf_strings) \ No newline at end of file diff --git a/lessonFour/cyclegan/networks.py b/lessonFour/cyclegan/networks.py new file mode 100755 index 0000000..26919b2 --- /dev/null +++ b/lessonFour/cyclegan/networks.py @@ -0,0 +1,62 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Networks for GAN Pix2Pix example using TFGAN.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +import tensorflow as tf + +import cyclegan +import pix2pix + + +def generator(input_images): + """Thin wrapper around CycleGAN generator to conform to the TFGAN API. + + Args: + input_images: A batch of images to translate. Images should be normalized + already. Shape is [batch, height, width, channels]. + + Returns: + Returns generated image batch. + + Raises: + ValueError: If shape of last dimension (channels) is not defined. + """ + input_images.shape.assert_has_rank(4) + input_size = input_images.shape.as_list() + channels = input_size[-1] + if channels is None: + raise ValueError( + 'Last dimension shape must be known but is None: %s' % input_size) + with tf.contrib.framework.arg_scope(cyclegan.cyclegan_arg_scope()): + output_images, _ = cyclegan.cyclegan_generator_resnet(input_images, + num_outputs=channels) + return output_images + + +def discriminator(image_batch, unused_conditioning=None): + """A thin wrapper around the Pix2Pix discriminator to conform to TFGAN API.""" + with tf.contrib.framework.arg_scope(pix2pix.pix2pix_arg_scope()): + logits_4d, _ = pix2pix.pix2pix_discriminator( + image_batch, num_filters=[64, 128, 256, 512]) + logits_4d.shape.assert_has_rank(4) + # Output of logits is 4D. Reshape to 2D, for TFGAN. + logits_2d = tf.contrib.layers.flatten(logits_4d) + + return logits_2d diff --git a/lessonFour/cyclegan/pix2pix.py b/lessonFour/cyclegan/pix2pix.py new file mode 100755 index 0000000..13c1c57 --- /dev/null +++ b/lessonFour/cyclegan/pix2pix.py @@ -0,0 +1,292 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= +"""Implementation of the Image-to-Image Translation model. + +This network represents a port of the following work: + + Image-to-Image Translation with Conditional Adversarial Networks + Phillip Isola, Jun-Yan Zhu, Tinghui Zhou and Alexei A. Efros + Arxiv, 2017 + https://phillipi.github.io/pix2pix/ + +A reference implementation written in Lua can be found at: +https://github.com/phillipi/pix2pix/blob/master/models.lua +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import functools + +import tensorflow as tf + +layers = tf.contrib.layers + + +def pix2pix_arg_scope(): + """Returns a default argument scope for isola_net. + + Returns: + An arg scope. + """ + # These parameters come from the online port, which don't necessarily match + # those in the paper. + # TODO(nsilberman): confirm these values with Philip. + instance_norm_params = { + 'center': True, + 'scale': True, + 'epsilon': 0.00001, + } + + with tf.contrib.framework.arg_scope( + [layers.conv2d, layers.conv2d_transpose], + normalizer_fn=layers.instance_norm, + normalizer_params=instance_norm_params, + weights_initializer=tf.random_normal_initializer(0, 0.02)) as sc: + return sc + + +def upsample(net, num_outputs, kernel_size, method='nn_upsample_conv'): + """Upsamples the given inputs. + + Args: + net: A `Tensor` of size [batch_size, height, width, filters]. + num_outputs: The number of output filters. + kernel_size: A list of 2 scalars or a 1x2 `Tensor` indicating the scale, + relative to the inputs, of the output dimensions. For example, if kernel + size is [2, 3], then the output height and width will be twice and three + times the input size. + method: The upsampling method. + + Returns: + An `Tensor` which was upsampled using the specified method. + + Raises: + ValueError: if `method` is not recognized. + """ + net_shape = tf.shape(net) + height = net_shape[1] + width = net_shape[2] + + if method == 'nn_upsample_conv': + net = tf.image.resize_nearest_neighbor( + net, [kernel_size[0] * height, kernel_size[1] * width]) + net = layers.conv2d(net, num_outputs, [4, 4], activation_fn=None) + elif method == 'conv2d_transpose': + net = layers.conv2d_transpose( + net, num_outputs, [4, 4], stride=kernel_size, activation_fn=None) + else: + raise ValueError('Unknown method: [%s]', method) + + return net + + +class Block( + collections.namedtuple('Block', ['num_filters', 'decoder_keep_prob'])): + """Represents a single block of encoder and decoder processing. + + The Image-to-Image translation paper works a bit differently than the original + U-Net model. In particular, each block represents a single operation in the + encoder which is concatenated with the corresponding decoder representation. + A dropout layer follows the concatenation and convolution of the concatenated + features. + """ + pass + + +def _default_generator_blocks(): + """Returns the default generator block definitions. + + Returns: + A list of generator blocks. + """ + return [ + Block(64, 0.5), + Block(128, 0.5), + Block(256, 0.5), + Block(512, 0), + Block(512, 0), + Block(512, 0), + Block(512, 0), + ] + + +def pix2pix_generator(net, + num_outputs, + blocks=None, + upsample_method='nn_upsample_conv', + is_training=False): # pylint: disable=unused-argument + """Defines the network architecture. + + Args: + net: A `Tensor` of size [batch, height, width, channels]. Note that the + generator currently requires square inputs (e.g. height=width). + num_outputs: The number of (per-pixel) outputs. + blocks: A list of generator blocks or `None` to use the default generator + definition. + upsample_method: The method of upsampling images, one of 'nn_upsample_conv' + or 'conv2d_transpose' + is_training: Whether or not we're in training or testing mode. + + Returns: + A `Tensor` representing the model output and a dictionary of model end + points. + + Raises: + ValueError: if the input heights do not match their widths. + """ + end_points = {} + + blocks = blocks or _default_generator_blocks() + + input_size = net.get_shape().as_list() + + input_size[3] = num_outputs + + upsample_fn = functools.partial(upsample, method=upsample_method) + + encoder_activations = [] + + ########### + # Encoder # + ########### + with tf.variable_scope('encoder'): + with tf.contrib.framework.arg_scope( + [layers.conv2d], + kernel_size=[4, 4], + stride=2, + activation_fn=tf.nn.leaky_relu): + + for block_id, block in enumerate(blocks): + # No normalizer for the first encoder layers as per 'Image-to-Image', + # Section 5.1.1 + if block_id == 0: + # First layer doesn't use normalizer_fn + net = layers.conv2d(net, block.num_filters, normalizer_fn=None) + elif block_id < len(blocks) - 1: + net = layers.conv2d(net, block.num_filters) + else: + # Last layer doesn't use activation_fn nor normalizer_fn + net = layers.conv2d( + net, block.num_filters, activation_fn=None, normalizer_fn=None) + + encoder_activations.append(net) + end_points['encoder%d' % block_id] = net + + ########### + # Decoder # + ########### + reversed_blocks = list(blocks) + reversed_blocks.reverse() + + with tf.variable_scope('decoder'): + # Dropout is used at both train and test time as per 'Image-to-Image', + # Section 2.1 (last paragraph). + with tf.contrib.framework.arg_scope([layers.dropout], is_training=True): + + for block_id, block in enumerate(reversed_blocks): + if block_id > 0: + net = tf.concat([net, encoder_activations[-block_id - 1]], axis=3) + + # The Relu comes BEFORE the upsample op: + net = tf.nn.relu(net) + net = upsample_fn(net, block.num_filters, [2, 2]) + if block.decoder_keep_prob > 0: + net = layers.dropout(net, keep_prob=block.decoder_keep_prob) + end_points['decoder%d' % block_id] = net + + with tf.variable_scope('output'): + # Explicitly set the normalizer_fn to None to override any default value + # that may come from an arg_scope, such as pix2pix_arg_scope. + logits = layers.conv2d( + net, num_outputs, [4, 4], activation_fn=None, normalizer_fn=None) + logits = tf.reshape(logits, input_size) + + end_points['logits'] = logits + end_points['predictions'] = tf.tanh(logits) + + return logits, end_points + + +def pix2pix_discriminator(net, num_filters, padding=2, is_training=False): + """Creates the Image2Image Translation Discriminator. + + Args: + net: A `Tensor` of size [batch_size, height, width, channels] representing + the input. + num_filters: A list of the filters in the discriminator. The length of the + list determines the number of layers in the discriminator. + padding: Amount of reflection padding applied before each convolution. + is_training: Whether or not the model is training or testing. + + Returns: + A logits `Tensor` of size [batch_size, N, N, 1] where N is the number of + 'patches' we're attempting to discriminate and a dictionary of model end + points. + """ + del is_training + end_points = {} + + num_layers = len(num_filters) + + def padded(net, scope): + if padding: + with tf.variable_scope(scope): + spatial_pad = tf.constant( + [[0, 0], [padding, padding], [padding, padding], [0, 0]], + dtype=tf.int32) + return tf.pad(net, spatial_pad, 'REFLECT') + else: + return net + + with tf.contrib.framework.arg_scope( + [layers.conv2d], + kernel_size=[4, 4], + stride=2, + padding='valid', + activation_fn=tf.nn.leaky_relu): + + # No normalization on the input layer. + net = layers.conv2d( + padded(net, 'conv0'), num_filters[0], normalizer_fn=None, scope='conv0') + + end_points['conv0'] = net + + for i in range(1, num_layers - 1): + net = layers.conv2d( + padded(net, 'conv%d' % i), num_filters[i], scope='conv%d' % i) + end_points['conv%d' % i] = net + + # Stride 1 on the last layer. + net = layers.conv2d( + padded(net, 'conv%d' % (num_layers - 1)), + num_filters[-1], + stride=1, + scope='conv%d' % (num_layers - 1)) + end_points['conv%d' % (num_layers - 1)] = net + + # 1-dim logits, stride 1, no activation, no normalization. + logits = layers.conv2d( + padded(net, 'conv%d' % num_layers), + 1, + stride=1, + activation_fn=None, + normalizer_fn=None, + scope='conv%d' % num_layers) + end_points['logits'] = logits + end_points['predictions'] = tf.sigmoid(logits) + return logits, end_points diff --git a/lessonFour/cyclegan/static/images/00500.jpg b/lessonFour/cyclegan/static/images/00500.jpg new file mode 100644 index 0000000..f465f6b Binary files /dev/null and b/lessonFour/cyclegan/static/images/00500.jpg differ diff --git a/lessonFour/cyclegan/static/images/scenery.jpg b/lessonFour/cyclegan/static/images/scenery.jpg new file mode 100644 index 0000000..814f4b7 Binary files /dev/null and b/lessonFour/cyclegan/static/images/scenery.jpg differ diff --git a/lessonFour/cyclegan/style_img/guernica.jpg b/lessonFour/cyclegan/style_img/guernica.jpg new file mode 100644 index 0000000..d2bb2d3 Binary files /dev/null and b/lessonFour/cyclegan/style_img/guernica.jpg differ diff --git a/lessonFour/cyclegan/style_img/harlequin.jpg b/lessonFour/cyclegan/style_img/harlequin.jpg new file mode 100644 index 0000000..60b6eeb Binary files /dev/null and b/lessonFour/cyclegan/style_img/harlequin.jpg differ diff --git a/lessonFour/cyclegan/style_img/pattern.jpg b/lessonFour/cyclegan/style_img/pattern.jpg new file mode 100644 index 0000000..9425046 Binary files /dev/null and b/lessonFour/cyclegan/style_img/pattern.jpg differ diff --git a/lessonFour/cyclegan/style_img/scream.jpg b/lessonFour/cyclegan/style_img/scream.jpg new file mode 100644 index 0000000..17ab7a9 Binary files /dev/null and b/lessonFour/cyclegan/style_img/scream.jpg differ diff --git a/lessonFour/cyclegan/style_img/starry_night.jpg b/lessonFour/cyclegan/style_img/starry_night.jpg new file mode 100644 index 0000000..3f767fc Binary files /dev/null and b/lessonFour/cyclegan/style_img/starry_night.jpg differ diff --git a/lessonFour/cyclegan/templates/upload.html b/lessonFour/cyclegan/templates/upload.html new file mode 100644 index 0000000..4f0b9f9 --- /dev/null +++ b/lessonFour/cyclegan/templates/upload.html @@ -0,0 +1,17 @@ + + +
+ +