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 @@ + + + + + 图片风格迁移demo + + +

上传你的图片,开始体验图片风格迁移的魅力吧

+
+ +
+ 请上传你的图片: + + +
+ + diff --git a/lessonFour/cyclegan/test_data/00500.jpg b/lessonFour/cyclegan/test_data/00500.jpg new file mode 100755 index 0000000..f465f6b Binary files /dev/null and b/lessonFour/cyclegan/test_data/00500.jpg differ diff --git a/lessonFour/cyclegan/train.py b/lessonFour/cyclegan/train.py new file mode 100755 index 0000000..4f37275 --- /dev/null +++ b/lessonFour/cyclegan/train.py @@ -0,0 +1,213 @@ + + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow as tf +import data_provider +import networks + +tfgan = tf.contrib.gan +import getConfig +gConfig={} +gConfig=getConfig.get_config(config_file='config.ini') + +""" +NHWC: +N代表数量, C代表channel,H代表高度,W代表宽度。 + +""" + +def _define_model(images_x, images_y): + """ +这里我们定义一个cycleganmodel,需要用到高级API tfgan.cyclegan_model + + +tfgan.eval.add_cyclegan_image_summaries: + + + """ + cyclegan_model = tfgan.cyclegan_model( + generator_fn=networks.generator, + discriminator_fn=networks.discriminator, + data_x=images_x, + data_y=images_y) + + # 为生成图片增加摘要. + tfgan.eval.add_cyclegan_image_summaries(cyclegan_model) + + return cyclegan_model + + +""" + +tf.train.polynomial_decay + +polynomial_decay( + learning_rate, + global_step, + decay_steps, + end_learning_rate=0.0001, + power=1.0, + cycle=False, + name=None +) + + earning_rate:初始值 +  global_step:全局step数 +  decay_steps:学习率衰减的步数,也代表学习率每次更新相隔的步数 +  end_learning_rate:衰减最终值 +  power:多项式衰减系数 +  cycle:step超出decay_steps之后是否继续循环 + +tf.cond:类似于ifelse语句 +""" + +def _get_lr(base_lr): + + global_step = tf.train.get_or_create_global_step() + lr_constant_steps = gConfig['max_number_of_steps'] // 2 + +#这里定义学习率的自动下降功能,大家回忆一下我们前面几个课程是如何做的? + + def _lr_decay(): + return tf.train.polynomial_decay( + learning_rate=base_lr, + global_step=(global_step - lr_constant_steps), + decay_steps=(gConfig['max_number_of_steps'] - lr_constant_steps), + end_learning_rate=0.0) + + return tf.cond(global_step < lr_constant_steps, lambda: base_lr, _lr_decay) + +""" +定义一个优化器,其参数只有一个lr,包括两个优化器,一个是生成器的,一个是识别器的。 +tf.train.AdamOptimizer,这里的use_locking是True的说明是要加更新锁定 +""" +def _get_optimizer(gen_lr, dis_lr): + + gen_opt = tf.train.AdamOptimizer(gen_lr, beta1=0.5, use_locking=True) + dis_opt = tf.train.AdamOptimizer(dis_lr, beta1=0.5, use_locking=True) + return gen_opt, dis_opt + + +def _define_train_ops(cyclegan_model, cyclegan_loss): + """ + 定以ops,Tensor,这个就是定义训练的运行计算图 + tf.contrib.gan.gan_train_ops + + + tf.contrib.gan.gan_train_ops( + model, + loss, + generator_optimizer, + discriminator_optimizer, + check_for_unused_update_ops=True, + **kwargs +) + +Args: +model: A GANModel. +loss: A GANLoss. +generator_optimizer: The optimizer for generator updates. +discriminator_optimizer: The optimizer for the discriminator updates. +check_for_unused_update_ops: If True, throws an exception if there are update ops outside of the generator or discriminator scopes. +**kwargs: Keyword args to pass directly to training.create_train_op for both the generator and discriminator train op. + + + + """ + gen_lr = _get_lr(gConfig['generator_lr']) + dis_lr = _get_lr(gConfig['discriminator_lr']) + gen_opt, dis_opt = _get_optimizer(gen_lr, dis_lr) + train_ops = tfgan.gan_train_ops( + cyclegan_model, + cyclegan_loss, + generator_optimizer=gen_opt, + discriminator_optimizer=dis_opt, + summarize_gradients=True, + colocate_gradients_with_ops=True, + aggregation_method=tf.AggregationMethod.EXPERIMENTAL_ACCUMULATE_N) + + tf.summary.scalar('generator_lr', gen_lr) + tf.summary.scalar('discriminator_lr', dis_lr) + return train_ops + + +""" +定义主函数 + +tf.device: + +tf.train.replica_device_setter: + + +""" + +def main(_): + #safe编程,这里大家要注意一下,就是我们写的代码一定要避免出现这种OSbug,这里就是先判断文件夹是否存在,如果不存在就重现创建一下。 + if not tf.gfile.Exists(gConfig['train_log_dir']): + tf.gfile.MakeDirs(gConfig['train_log_dir']) + + with tf.device(tf.train.replica_device_setter(gConfig['ps_tasks'])): + with tf.name_scope('inputs'): + images_x, images_y = data_provider.provide_custom_data( + [gConfig['image_set_x_file_pattern'],gConfig['image_set_y_file_pattern']], + batch_size=gConfig['batch_size'], + patch_size=gConfig['patch_size']) + # Set batch size for summaries. + + """ + set_shape:转变维度,将images_x转换成我们所需要的维度。 + tf.contrib.gan.cyclegan_loss: + + tf.contrib.gan.features.tensor_pool: + + tf.contrib.gan.GANTrainSteps: + + tf.train.StopAtStepHook: + + tf.train.LoggingTensorHook: + + tf.train.get_sequential_train_hooks: + + """ + images_x.set_shape([gConfig['batch_size'], None, None, None]) + images_y.set_shape([gConfig['batch_size'], None, None, None]) + + # Define CycleGAN model. + cyclegan_model = _define_model(images_x, images_y) + + # Define CycleGAN loss. + cyclegan_loss = tfgan.cyclegan_loss( + cyclegan_model, + cycle_consistency_loss_weight=gConfig['cycle_consistency_loss_weight'], + tensor_pool_fn=tfgan.features.tensor_pool) + + # Define CycleGAN train ops. + train_ops = _define_train_ops(cyclegan_model, cyclegan_loss) + + # Training + train_steps = tfgan.GANTrainSteps(1, 1) + status_message = tf.string_join( + [ + 'Starting train step: ', + tf.as_string(tf.train.get_or_create_global_step()) + ], + name='status_message') + if not gConfig['max_number_of_steps']: + return + tfgan.gan_train( + train_ops, + gConfig['train_log_dir'], + get_hooks_fn=tfgan.get_sequential_train_hooks(train_steps), + hooks=[ + tf.train.StopAtStepHook(num_steps=gConfig['max_number_of_steps']), + tf.train.LoggingTensorHook([status_message], every_n_iter=10) + ], + master=gConfig['master'], + is_chief=gConfig['task'] == 0) + +if __name__ == '__main__': + tf.app.run() + \ No newline at end of file diff --git a/lessonFour/cyclegan/train_img/architechture.jpg b/lessonFour/cyclegan/train_img/architechture.jpg new file mode 100644 index 0000000..96f002b Binary files /dev/null and b/lessonFour/cyclegan/train_img/architechture.jpg differ diff --git a/lessonFour/cyclegan/train_img/deadpool.jpg b/lessonFour/cyclegan/train_img/deadpool.jpg new file mode 100644 index 0000000..7bfa385 Binary files /dev/null and b/lessonFour/cyclegan/train_img/deadpool.jpg differ diff --git a/lessonFour/cyclegan/train_img/marvel.jpg b/lessonFour/cyclegan/train_img/marvel.jpg new file mode 100644 index 0000000..0b05d1a Binary files /dev/null and b/lessonFour/cyclegan/train_img/marvel.jpg differ diff --git a/lessonFour/cyclegan/train_img/scenery.jpg b/lessonFour/cyclegan/train_img/scenery.jpg new file mode 100644 index 0000000..814f4b7 Binary files /dev/null and b/lessonFour/cyclegan/train_img/scenery.jpg differ diff --git a/lessonFour/cyclegan/train_img/sky.jpg b/lessonFour/cyclegan/train_img/sky.jpg new file mode 100644 index 0000000..39c2f25 Binary files /dev/null and b/lessonFour/cyclegan/train_img/sky.jpg differ diff --git a/lessonFour/cyclegan/trans_out_img/00500.jpg b/lessonFour/cyclegan/trans_out_img/00500.jpg new file mode 100644 index 0000000..f12f767 Binary files /dev/null and b/lessonFour/cyclegan/trans_out_img/00500.jpg differ diff --git a/lessonFour/cyclegan/trans_out_img/scenery.jpg b/lessonFour/cyclegan/trans_out_img/scenery.jpg new file mode 100644 index 0000000..24ae7c3 Binary files /dev/null and b/lessonFour/cyclegan/trans_out_img/scenery.jpg differ diff --git a/lessonFour/cyclegan/trans_style.py b/lessonFour/cyclegan/trans_style.py new file mode 100755 index 0000000..4b95357 --- /dev/null +++ b/lessonFour/cyclegan/trans_style.py @@ -0,0 +1,190 @@ + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import os +from absl import app +from absl import flags +import numpy as np +import PIL +import tensorflow as tf +import data_provider +import networks + +import getConfig + +from flask import Flask,render_template,request,redirect,url_for,make_response,jsonify +from werkzeug.utils import secure_filename +import os +import cv2 + +from datetime import timedelta + + +gConfig={} + +gConfig=getConfig.get_config(config_file='config.ini') + +tfgan = tf.contrib.gan + + +""" +这里定义一个判断函数,判断文件是否存在 + +""" +#文件操作,创建文件 +def _make_dir_if_not_exists(dir_path): + """Make a directory if it does not exist.""" + if not tf.gfile.Exists(dir_path): + tf.gfile.MakeDirs(dir_path) + +#文件操作,创建文件 +def _file_output_path(dir_path, input_file_path): + """Create output path for an individual file.""" + return os.path.join(dir_path, os.path.basename(input_file_path)) + +#定义一个预测图用来做预测 +def make_inference_graph(model_name, patch_dim): + """Build the inference graph for either the X2Y or Y2X GAN. + + Args: + model_name: The var scope name 'ModelX2Y' or 'ModelY2X'. + patch_dim: An integer size of patches to feed to the generator. + + Returns: + Tuple of (input_placeholder, generated_tensor). + 知识点: + tf.variable_scope: + + tf.get_variable(, , ) 创建或返回给定名称的变量 + tf.variable_scope() 管理传给get_variable()的变量名称的作用域 + + tf.expand_dims: + + 想要维度增加一维,可以使用tf.expand_dims(input, dim, name=None)函数。 + 当然,我们常用tf.reshape(input, shape=[])也可以达到相同效果, + 但是有些时候在构建图的过程中,placeholder没有被feed具体的值,这时就会包下面的错误:TypeError: Expected binary or unicode string, got 1 + """ + input_hwc_pl = tf.placeholder(tf.float32, [None, None, 3]) + + # Expand HWC to NHWC + images_x = tf.expand_dims( + data_provider.full_image_to_patch(input_hwc_pl, patch_dim), 0) + + with tf.variable_scope(model_name): + with tf.variable_scope('Generator'): + generated = networks.generator(images_x) + return input_hwc_pl, generated + +#定义预测输出函数,将风格迁移后的图片输出到文件夹中 + +def export(sess, input_pl, output_tensor, input_file_pattern, output_dir): + """Exports inference outputs to an output directory. + + Args: + sess: tf.Session with variables already loaded. + input_pl: tf.Placeholder for input (HWC format). + output_tensor: Tensor for generated outut images. + input_file_pattern: Glob file pattern for input images. + output_dir: Output directory. + """ + #如果output_dir配置了,要判断其是否存在 + if output_dir: + _make_dir_if_not_exists(output_dir) + + + """ +tf.gfile.Glob + +tf.gfile.Glob(filename) + +查找匹配pattern的文件并以列表的形式返回,filename可以是一个具体的文件名,也可以是包含通配符的正则表达式。 +关于gfile的操作可以查看:https://blog.csdn.net/a373595475/article/details/79693430 + + +PIL:是一个python进行图片处理的库,可以参考文档http://effbot.org/imagingbook/ + +PIL.Image.fromarray + + """ + + if input_file_pattern: + for file_path in tf.gfile.Glob(input_file_pattern): + # Grab a single image and run it through inference + input_np = np.asarray(PIL.Image.open(file_path)) + output_np = sess.run(output_tensor, feed_dict={input_pl: input_np}) + image_np = data_provider.undo_normalize_image(output_np) + output_path = _file_output_path(output_dir, file_path) + PIL.Image.fromarray(image_np).save(output_path) + return output_path + + +def trans(img_path): + + + + """ + 这里提供了双方的风格迁移,一个是从一个风格迁移到我们想要的风格,另外一个是将我们迁移后的风格图片还原。 + """ + images_x_hwc_pl, generated_y = make_inference_graph('ModelX2Y', + gConfig['patch_dim']) + images_y_hwc_pl, generated_x = make_inference_graph('ModelY2X', + gConfig['patch_dim']) + + # 重新加载我们在训练阶段保存的模型,然后进行图片的风格迁移 + saver = tf.train.Saver() + with tf.Session() as sess: + saver.restore(sess, gConfig['checkpoint_path']) + #获取风格迁移周的图片路径 + img_path=export(sess, images_x_hwc_pl, generated_y,img_path , + gConfig['generated_y_dir']) + export(sess, images_y_hwc_pl, generated_x, gConfig['image_set_y_glob'], + gConfig['generated_x_dir']) + + print(img_path) + return img_path + +"""下面是一个APP应用,作用很简单就是将图片上传,并显示风格迁移后的图片""" + + + +#设置允许的文件格式 +ALLOWED_EXTENSIONS = set(['png', 'jpg', 'JPG', 'PNG', 'bmp']) + +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS + +app = Flask(__name__) +# 设置静态文件缓存过期时间 +app.send_file_max_age_default = timedelta(seconds=1) + +@app.route('/upload', methods=['POST', 'GET']) # 添加路由 +def upload(): + if request.method == 'POST': + f = request.files['file'] + + if not (f and allowed_file(f.filename)): + return jsonify({"error": 1001, "msg": "请检查上传的图片类型,仅限于png、PNG、jpg、JPG、bmp"}) + + user_input = request.form.get("name") + + basepath = os.path.dirname(__file__) # 当前文件所在路径 + + upload_path = os.path.join(basepath, 'static/images',secure_filename(f.filename)) #注意:没有的文件夹一定要先创建,不然会提示没有该路径 + f.save(upload_path) + trans_img_path=trans(upload_path) + + + image_data = open(trans_img_path, "rb").read() + response = make_response(image_data) + response.headers['Content-Type'] = 'image/png' + return response + + return render_template('upload.html') + + + +if __name__ == '__main__': + #tf.app.run() + app.run(host = '0.0.0.0',port = 8989,debug= False) + diff --git a/lessonOne/imgClassifierWeb/execute.py b/lessonOne/imgClassifierWeb/execute.py index 8451944..5688c34 100644 --- a/lessonOne/imgClassifierWeb/execute.py +++ b/lessonOne/imgClassifierWeb/execute.py @@ -6,6 +6,7 @@ import time import getConfig import sys +import random gConfig = {} def read_data(dataset_path, im_dim, num_channels,num_files,images_per_file): @@ -69,10 +70,14 @@ def create_model(session,forward_only): #获取批量处理数据,考虑到配置不同,如果没有GPU建议将percent调小一点,即将训练集调小 def get_batch(data,labels,percent): num_elements = np.uint32(percent * data.shape[0] / 100) - shuffled_labels = labels - np.random.shuffle(shuffled_labels) - return data[shuffled_labels[:num_elements], :, :, :], shuffled_labels[:num_elements] - + #之所以没有采用tf自带的tf.train.batch是因为那个接口对内存的消耗太大了,我们采用这种随机取index的方法简单又实用。 + n=np.random.randint(len(labels),size=num_elements) + shuffle_datas=[] + shuffled_labels=[] + for i in n: + shuffle_datas.append(data[i,:,:,:]) + shuffled_labels.append(labels[i]) + return shuffle_datas,shuffled_labels #定义训练函数 def train(): @@ -93,37 +98,37 @@ def train(): config = tf.ConfigProto() config.gpu_options.allocator_type = 'BFC' - + #读取训练集的数据到内存中 dataset_array, dataset_labels = read_data(dataset_path=gConfig['dataset_path'], im_dim=gConfig['im_dim'], num_channels=gConfig['num_channels'],num_files=gConfig['num_files'],images_per_file=gConfig['images_per_file']) - - - dataset_array_test, dataset_labels_test = read_data(dataset_path=gConfig['dataset_test'], im_dim=gConfig['im_dim'], num_channels=gConfig['num_channels'],num_files=1,images_per_file=gConfig['images_per_file']) + #打印训练数据的维度 print("Size of data : ", dataset_array.shape) + #读取测试数据到内存中 + dataset_array_test, dataset_labels_test = read_data(dataset_path=gConfig['dataset_test'], im_dim=gConfig['im_dim'], num_channels=gConfig['num_channels'],num_files=1,images_per_file=gConfig['images_per_file']) + #打印测试数据的维度 + print("Size of data : ", dataset_array_test.shape) + with tf.Session(config=config) as sess: model,_=create_model(sess,False) - # 开始训练循环,这里没有设置结束条件,知道最终我们手动结束为止,不过大家可以思考一下该如何设置合适的结束条件以及如何设置? + step_time, accuracy = 0.0, 0.0 current_step = 0 previous_correct = [] - + # 开始训练循环,这里没有设置结束条件,当学习率下降到为0时停止 while model.learning_rate.eval()>gConfig['end_learning_rate']: - shuffled_data, shuffled_labels = get_batch(data=dataset_array, labels=dataset_labels, + shuffled_datas, shuffled_labels = get_batch(data=dataset_array, labels=dataset_labels, percent=gConfig['percent']) - #print(shuffled_data) - - shuffled_data_test, shuffled_labels_test = get_batch(data=dataset_array_test, labels=dataset_labels_test, - percent=5*gConfig['percent']) - + shuffled_datas_test, shuffled_labels_test = get_batch(data=dataset_array_test, labels=dataset_labels_test, + percent=gConfig['percent']*5) start_time = time.time() - step_correct=model.step(sess,shuffled_data,shuffled_labels,False) + step_correct=model.step(sess,shuffled_datas,shuffled_labels,False) step_time += (time.time() - start_time) / gConfig['steps_per_checkpoint'] accuracy += step_correct / gConfig['steps_per_checkpoint'] current_step += 1 - # 达到一个训练模型保存点后,将模型保存下来 + # 达到一个训练模型保存点后,将模型保存下来,并打印出这个保存点的平均准确率 if current_step % gConfig['steps_per_checkpoint'] == 0: #如果超过三次预测正确率没有升高则改变学习率 if len(previous_correct) > 2 and accuracy == min(previous_correct[-3:]): @@ -133,18 +138,18 @@ def train(): #saver=tf.train.Saver() model.saver.save(sess, checkpoint_path,global_step=model.global_step) - #sess.run(tf.global_variables_initializer()) + #以下为增加模型在测试集上的准确率测试 graph = tf.get_default_graph() - + #以下获取默认计算图的参数 softmax_propabilities = graph.get_tensor_by_name(name="softmax_probs:0") softmax_predictions = tf.argmax(softmax_propabilities, axis=1) data_tensor = graph.get_tensor_by_name(name="data_tensor:0") label_tensor = graph.get_tensor_by_name(name="label_tensor:0") keep_prop = graph.get_tensor_by_name(name="keep_prop:0") - feed_dict_testing = {data_tensor: shuffled_data_test, - label_tensor: shuffled_labels_test, + feed_dict_testing = {data_tensor: shuffled_datas_test, + label_tensor: shuffled_labels_test, keep_prop: 1.0} softmax_propabilities_, softmax_predictions_ = sess.run([softmax_propabilities, softmax_predictions], @@ -152,13 +157,15 @@ def train(): correct = np.array(np.where(softmax_predictions_ == shuffled_labels_test)) correct = correct.size - print("模型在测试集上的准确率为 : ", correct/(gConfig['percent']*gConfig['dataset_size']/100)) - - + #打印出模型在训练集上的准确率 print("在", str(gConfig['percent'] *gConfig['dataset_size']/100),"个训练集上训练的准确率", ' : ', accuracy) print("学习率 %.4f 每步耗时 %.2f " % ( model.learning_rate.eval(),step_time)) step_time, accuracy = 0.0,0.0 - sys.stdout.flush() + + #打印出模型在测试集上的准确率 + print("模型在测试集上的准确率为 : ", correct/(gConfig['percent']*gConfig['dataset_size']/100)) + + sys.stdout.flush() def init_session(sess,conf='config.ini'): global gConfig diff --git a/lessonThree/Anti-Fraud-App/VAE.py b/lessonThree/Anti-Fraud-App/VAE.py index c807900..7cba1b2 100644 --- a/lessonThree/Anti-Fraud-App/VAE.py +++ b/lessonThree/Anti-Fraud-App/VAE.py @@ -9,6 +9,13 @@ #定义训练数据的维度 seq_len=gConfig['seqlen'] +#class vaeModel(object): + + # def __init__(self, learning_rate,learning_rate_decay_factor): + # self.learning_rate=tf.Variable(float(learning_rate), trainable=False) + # self.learning_rate_decay_op = self.learning_rate.assign(self.learning_rate * learning_rate_decay_factor) + # self.global_step = tf.Variable(0, trainable=False) + #读取数据 def read_data(source_file): data=pd.read_csv(source_file,encoding='utf-8') @@ -18,7 +25,6 @@ def read_data(source_file): tf.reset_default_graph() -batch_size = 64 X_in = tf.placeholder(dtype=tf.float32, shape=[None, seq_len], name='X') Y = tf.placeholder(dtype=tf.float32, shape=[None, seq_len], name='Y') Y_flat = tf.reshape(Y, shape=[-1, seq_len * 1]) @@ -27,52 +33,51 @@ def read_data(source_file): dec_in_channels = 1 #encoder输出的数据维度 n_latent = gConfig['encoutlen'] -print(n_latent) +#print(n_latent) reshaped_dim = [-1, 7, 7, dec_in_channels] inputs_decoder = 49 * dec_in_channels // 2 #定义激活函数 def lrelu(x, alpha=0.3): - return tf.maximum(x, tf.multiply(x, alpha)) + return tf.maximum(x, tf.multiply(x, alpha)) #定义编码机 def encoder(X_in, keep_prob): activation = lrelu with tf.variable_scope("encoder", reuse=None): - X = tf.reshape(X_in, shape=[-1, seq_len, 1, 1]) - x = tf.layers.conv2d(X, filters=64, kernel_size=4, strides=2, padding='same', activation=activation) - x = tf.nn.dropout(x, keep_prob) - x = tf.layers.conv2d(x, filters=64, kernel_size=4, strides=2, padding='same', activation=activation) - x = tf.nn.dropout(x, keep_prob) - x = tf.layers.conv2d(x, filters=64, kernel_size=4, strides=1, padding='same', activation=activation) - x = tf.nn.dropout(x, keep_prob) - x = tf.contrib.layers.flatten(x) - mn = tf.layers.dense(x, units=n_latent) - sd = 0.5 * tf.layers.dense(x, units=n_latent) - epsilon = tf.random_normal(tf.stack([tf.shape(x)[0], n_latent])) - z = mn + tf.multiply(epsilon, tf.exp(sd)) - return z, mn, sd + X = tf.reshape(X_in, shape=[-1, seq_len, 1, 1]) + x1_layer = tf.layers.conv2d(X, filters=32, kernel_size=4, strides=2, padding='same', activation=activation) + x1_dropout = tf.nn.dropout(x1_layer, keep_prob) + x2_layer = tf.layers.conv2d(x1_dropout, filters=32, kernel_size=4, strides=2, padding='same', activation=activation) + x2_dropout = tf.nn.dropout(x2_layer, keep_prob) + x3_layer = tf.layers.conv2d(x2_dropout, filters=32, kernel_size=4, strides=1, padding='same', activation=activation) + x3_dropout = tf.nn.dropout(x3_layer, keep_prob) + x_out = tf.contrib.layers.flatten(x3_dropout) + mn = tf.layers.dense(x_out, units=n_latent) + sd = 0.5 * tf.layers.dense(x_out, units=n_latent) + epsilon = tf.random_normal(tf.stack([tf.shape(x_out)[0], n_latent])) + z = mn + tf.multiply(epsilon, tf.exp(sd)) + return z, mn, sd #定义解码机 def decoder(sampled_z, keep_prob): with tf.variable_scope("decoder", reuse=None): - x = tf.layers.dense(sampled_z, units=inputs_decoder, activation=lrelu) - x = tf.layers.dense(x, units=inputs_decoder * 2 + 1, activation=lrelu) - x = tf.reshape(x, reshaped_dim) - x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=2, padding='same', activation=tf.nn.relu) - x = tf.nn.dropout(x, keep_prob) - x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu) - x = tf.nn.dropout(x, keep_prob) - x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu) + y = tf.layers.dense(sampled_z, units=inputs_decoder, activation=lrelu) + y = tf.layers.dense(y, units=inputs_decoder * 2 + 1, activation=lrelu) + y = tf.reshape(y, reshaped_dim) + y1_layer = tf.layers.conv2d_transpose(y, filters=64, kernel_size=4, strides=2, padding='same', activation=tf.nn.relu) + y1_dropout = tf.nn.dropout(y1_layer, keep_prob) + y2_layer = tf.layers.conv2d_transpose(y1_dropout, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu) + y2_dropout = tf.nn.dropout(y2_layer, keep_prob) + y3_layer = tf.layers.conv2d_transpose(y2_dropout, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu) - x = tf.contrib.layers.flatten(x) - x = tf.layers.dense(x, units=seq_len * 1, activation=tf.nn.sigmoid) - decoder_set = tf.reshape(x, shape=[-1, seq_len, 1]) - return decoder_set + y_flatten = tf.contrib.layers.flatten(y3_layer) + y_out = tf.layers.dense(y_flatten, units=seq_len * 1, activation=tf.nn.sigmoid) + decoder_set = tf.reshape(y_out, shape=[-1, seq_len, 1]) + return decoder_set #定义计算loss以及进行优化器优化的一系列tensor sampled, mn, sd = encoder(X_in, keep_prob) dec = decoder(sampled, keep_prob) - unreshaped = tf.reshape(dec, [-1, seq_len*1]) img_loss = tf.reduce_sum(tf.squared_difference(unreshaped, Y_flat), 1) latent_loss = -0.5 * tf.reduce_sum(1.0 + 2.0 * sd - tf.square(mn) - tf.exp(2.0 * sd), 1) @@ -81,6 +86,7 @@ def decoder(sampled_z, keep_prob): optimizer = tf.train.AdamOptimizer(gConfig['learning_rate']).minimize(loss) sess = tf.Session() sess.run(tf.global_variables_initializer()) + #开始vae的训练 for i in range(gConfig['vae_steps']): @@ -93,6 +99,4 @@ def decoder(sampled_z, keep_prob): #保存训练的encode的结果,就是要进行特征压缩后的特征 sampled_data=pd.DataFrame(sampled_data) -sampled_data.to_csv(gConfig['sampled_path']) - - +sampled_data.to_csv(gConfig['sampled_path']) \ No newline at end of file diff --git a/lessonThree/Anti-Fraud-App/autoencoder.py b/lessonThree/Anti-Fraud-App/autoencoder.py deleted file mode 100644 index 9454148..0000000 --- a/lessonThree/Anti-Fraud-App/autoencoder.py +++ /dev/null @@ -1,88 +0,0 @@ -import tensorflow as tf -import numpy as np -import getConfig -import data_util -from functools import partial - -import pandas as pd - -gConfig={} - -gConfig=getConfig.get_config(config_file='config.ini') - -n_inputs = 1 -n_hidden1 = 500 -n_hidden2 = 500 -n_hidden3 = 20 # codings -n_hidden4 = n_hidden2 -n_hidden5 = n_hidden1 -n_outputs = n_inputs -learning_rate = 0.001 - -initializer = tf.contrib.layers.variance_scaling_initializer() -my_dense_layer = partial( - tf.layers.dense, - activation=tf.nn.elu, - kernel_initializer=initializer) - -X = tf.placeholder(tf.float32, [429398, n_inputs]) -hidden1 = my_dense_layer(X, n_hidden1) -hidden2 = my_dense_layer(hidden1, n_hidden2) -hidden3_mean = my_dense_layer(hidden2, n_hidden3, activation=None) -hidden3_gamma = my_dense_layer(hidden2, n_hidden3, activation=None) -noise = tf.random_normal(tf.shape(hidden3_gamma), dtype=tf.float32) -hidden3 = hidden3_mean + tf.exp(0.5 * hidden3_gamma) * noise -hidden4 = my_dense_layer(hidden3, n_hidden4) -hidden5 = my_dense_layer(hidden4, n_hidden5) -logits = my_dense_layer(hidden5, n_outputs, activation=None) -outputs = tf.sigmoid(logits) - -xentropy = tf.nn.sigmoid_cross_entropy_with_logits(labels=X, logits=logits) -reconstruction_loss = tf.reduce_sum(xentropy) -latent_loss = 0.5 * tf.reduce_sum( - tf.exp(hidden3_gamma) + tf.square(hidden3_mean) - 1 - hidden3_gamma) -loss = reconstruction_loss + latent_loss - -optimizer = tf.train.AdamOptimizer(learning_rate=gConfig['learning_rate']) -training_op = optimizer.minimize(reconstruction_loss) - -init = tf.global_variables_initializer() -saver = tf.train.Saver() - - - -n_epochs = 50 -batch_size = 150 -def read_data(source_file): - data=pd.read_csv(source_file,encoding='gbk') - dataset=data.fillna(-1).values - return dataset -def get_batch(data,percent): - num_elements = np.uint32(percent * data.shape[0] / 100) - shuffled_data = data - np.random.shuffle(data) - return data[shuffled_data[:num_elements]] - -with tf.Session() as sess: - - init.run() - k=gConfig['training_epochs'] - data_set=read_data(gConfig['input_file']) - while k>0 : - n_batches = int(100/gConfig['percent'])+1 - for iteration in range(n_batches): - X_batch = data_set - print (X_batch) - #get_batch(data_set,gConfig['percent']) - #sess.run(training_op, feed_dict={X: X_batch}) - loss_val, reconstruction_loss_val, latent_loss_val = sess.run([loss, reconstruction_loss, latent_loss], feed_dict={X: X_batch}) - print("\r{}".format(k), "Train total cost:", loss_val, "\tReconstruction loss:", reconstruction_loss_val, "\tLatent loss:", latent_loss_val) - saver.save(sess, "./my_model_variational_variant.ckpt") - k=k-1 - #codings = hidden3 - # saver.restore(sess,"./my_model_variational.ckpt") - #codings_eval = codings.eval(feed_dict={X:data_set}) - - - - diff --git a/lessonThree/Anti-Fraud-App/config.ini b/lessonThree/Anti-Fraud-App/config.ini index 29bc0dc..f00bc62 100644 --- a/lessonThree/Anti-Fraud-App/config.ini +++ b/lessonThree/Anti-Fraud-App/config.ini @@ -13,8 +13,15 @@ seqlen=12 #vae encoder输出的中间向量的长度 encoutlen=8 +percent=100 + +steps_per_checkpoint=10 + [floats] learning_rate = 0.01 +learning_rate_decay_factor=0.5 +end_learning_rate=0.0 +keeps=0.5 [strings] mode = train working_directory=working_directory/ @@ -23,6 +30,10 @@ input_file=train_data/train_data.csv model_path=kmeansMode/1542258970 sampled_path=train_data/sampled_data.csv +#vaemodel的存放路径 + +vae_model=vaemodel/ + diff --git a/lessonThree/Anti-Fraud-App/test.py b/lessonThree/Anti-Fraud-App/test.py deleted file mode 100644 index 665ff1b..0000000 --- a/lessonThree/Anti-Fraud-App/test.py +++ /dev/null @@ -1,28 +0,0 @@ -import numpy as np -import tensorflow as tf - -from six.moves import xrange - -num_points = 100 -dimensions = 2 -points = np.random.uniform(0, 1000, [num_points, dimensions]) - -def input_fn(): - return tf.train.limit_epochs( - tf.convert_to_tensor(points, dtype=tf.float32), num_epochs=1) - -num_clusters = 5 -kmeans = tf.contrib.factorization.KMeansClustering( - num_clusters=num_clusters, use_mini_batch=False) - -# train -num_iterations = 10 -previous_centers = None -for _ in xrange(num_iterations): - kmeans.train(input_fn) - cluster_centers = kmeans.cluster_centers() - if previous_centers is not None: - print ('delta:', cluster_centers - previous_centers) - previous_centers = cluster_centers - print ('score:', kmeans.score(input_fn)) -print ('cluster centers:', cluster_centers) \ No newline at end of file