{"cells":[{"metadata":{},"cell_type":"markdown","source":"structure from https://github.com/eriklindernoren/Keras-GAN/blob/master/dcgan/dcgan.py"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nfrom __future__ import print_function, division\n# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\nimport cv2\nimport pandas as pd\nimport numpy as np\nimport os\nfrom tqdm import tqdm, tqdm_notebook\nfrom keras.preprocessing.image import load_img\nfrom keras.applications.densenet import preprocess_input\nfrom keras.preprocessing.image import img_to_array\nfrom keras.preprocessing.image import array_to_img\nfrom keras.preprocessing import image\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.\n\n\n\n\nimg_size = 64\nbatch_size = 128\n\n\n\ndef resize_to_square(im):\n    # new_size should be in (width, height) format\n    im = cv2.resize(im, (img_size, img_size))\n    return im\n\ndef load_image2(file):\n    image = cv2.imread(file)\n    new_image = resize_to_square(image)\n    #ew_image = preprocess_input(new_image)\n    return new_image\n\ndef load_image(file):\n    new_image = load_img(file, target_size=(img_size, img_size))\n    new_image = (img_to_array(new_image))\n    #new_image = resize_to_square(img_to_array(new_image))\n    #ew_image = preprocess_input(new_image)\n    return new_image\n    \nif not os.path.exists('../output_images'):\n    os.mkdir('../output_images')\n    \n\n\nfrom keras.datasets import mnist\nfrom keras.layers import Input, Dense, Reshape, Flatten, Dropout, multiply, GaussianNoise\nfrom keras.layers import BatchNormalization, Activation, Embedding, ZeroPadding2D\nfrom keras.layers import MaxPooling2D, concatenate\nfrom keras.layers.advanced_activations import LeakyReLU\nfrom keras.layers.convolutional import UpSampling2D, Conv2D\nfrom keras.models import Sequential, Model\nfrom keras.optimizers import Adam\nfrom keras import losses\nfrom keras.utils import to_categorical\nimport keras.backend as K\n\nimport matplotlib.pyplot as plt\n\nimport numpy as np\n\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from pathlib import Path\nfrom dataclasses import dataclass\nimport warnings\n\nimport numpy as np\nfrom PIL import Image\nfrom scipy import linalg\nimport tensorflow as tf\n\nMODEL_PATH = '../input/dog-face-generation-competition-kid-metric-input/classify_image_graph_def.pb'\nTRAIN_DIR = Path('../input/generative-dog-images/all-dogs/')\nOUT_DIR = Path('../output_images/')\nOUT_DIR.mkdir(exist_ok=True)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\nclass KernelEvalException(Exception):\n    pass\n\n\n@dataclass\nclass MiFIDEvaluator(object):\n    model_path: str\n    train_images_path: str\n    feature_path: str = None\n    imsize: int = 64\n    output_layer: str = 'Pretrained_Net/pool_3:0'\n    input_layer: str = 'Pretrained_Net/ExpandDims:0'\n    output_shape: int = 2048\n    cosine_distance_eps: float = 0.1\n    batch_size: int = 50\n    fid_epsilon: float = 1e-14\n    \n    def __post_init__(self):\n        tf.reset_default_graph()\n        self.create_model_graph()\n        with tf.Session() as sess:\n            if self.feature_path is None:\n                self.mu2, self.sigma2, self.features2 = self._handle_path_memorization(\n                    self.train_images_path, sess, is_checksize=False, is_check_png=False)\n            else:\n                with np.load(self.feature_path) as f:\n                    self.mu2, self.sigma2, self.features2 = f['m'], f['s'], f['features']\n    \n    def create_model_graph(self):\n        with tf.gfile.FastGFile(self.model_path, 'rb') as f:\n            graph_def = tf.GraphDef()\n            graph_def.ParseFromString(f.read())\n            _ = tf.import_graph_def(graph_def, name='Pretrained_Net')\n            \n    def img_read_checks(self, filename, is_checksize=False, is_check_png=False):\n        im = Image.open(str(filename))\n        if is_checksize and im.size != (self.imsize, self.imsize):\n            raise KernelEvalException(f'The images are not of size {check_imsize}')\n        if is_check_png and im.format != 'PNG':\n            raise KernelEvalException('Only PNG images should be submitted.')\n\n        if self.imsize is None:\n            return im\n        else:\n            return im.resize((self.imsize, self.imsize), Image.ANTIALIAS)\n        \n    def _get_model_layer(self, sess):\n        layer = sess.graph.get_tensor_by_name(self.output_layer)\n        ops = layer.graph.get_operations()\n        for op_idx, op in enumerate(ops):\n            for o in op.outputs:\n                shape = o.get_shape()\n                if shape._dims != []:\n                    shape = [s.value for s in shape]\n                    new_shape = []\n                    for j, s in enumerate(shape):\n                        if s == 1 and j == 0:\n                            new_shape.append(None)\n                        else:\n                            new_shape.append(s)\n                    o.__dict__['_shape_val'] = tf.TensorShape(new_shape)\n        return layer\n        \n    def get_activations(self, images, sess):\n        inception_layer = self._get_model_layer(sess)\n        n_images = images.shape[0]\n        if self.batch_size > n_images:\n            warnings.warn('batch size is bigger than the data size. setting batch size to data size')\n            self.batch_size = n_images\n        n_batches = n_images // self.batch_size + 1\n        pred_arr = np.empty((n_images, self.output_shape))\n        for i in range(n_batches):\n            start = i * self.batch_size\n            if start + self.batch_size < n_images:\n                end = start + self.batch_size\n            else:\n                end = n_images\n\n            batch = images[start:end]\n            pred = sess.run(inception_layer, {self.input_layer: batch})\n            pred_arr[start:end] = pred.reshape(-1, self.output_shape)\n        return pred_arr\n        \n    def calculate_activation_statistics(self, images, sess):\n        act = self.get_activations(images, sess)\n        mu = np.mean(act, axis=0)\n        sigma = np.cov(act, rowvar=False)\n        return mu, sigma, act\n            \n    def _handle_path_memorization(self, path, sess, is_checksize, is_check_png):\n        path = Path(path)\n        files = list(path.glob('*.jpg')) + list(path.glob('*.png'))\n\n        # In production we don't resize input images. This is just for demo purpose. \n        x = np.array([np.array(self.img_read_checks(fn, is_checksize, is_check_png)) for fn in files])\n        m, s, features = self.calculate_activation_statistics(x, sess)\n        del x\n        return m, s, features\n    \n    def calculate_frechet_distance(self, mu1, sigma1):\n        mu1 = np.atleast_1d(mu1)\n        mu2 = np.atleast_1d(self.mu2)\n        sigma1 = np.atleast_2d(sigma1)\n        sigma2 = np.atleast_2d(self.sigma2)\n\n        assert mu1.shape == mu2.shape, 'Training and test mean vectors have different lengths'\n        assert sigma1.shape == sigma2.shape, 'Training and test covariances have different dimensions'\n\n        # product might be almost singular\n        covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False)\n        if not np.isfinite(covmean).all():\n            msg = f'fid calculation produces singular product; adding {self.eps} to diagonal of cov estimates'\n            warnings.warn(msg)\n            offset = np.eye(sigma1.shape[0]) * self.eps\n            covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset))\n            \n        # numerical error might give slight imaginary component\n        if np.iscomplexobj(covmean):\n            if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3):\n                m = np.max(np.abs(covmean.imag))\n                raise ValueError(f'Imaginary component {m}')\n            covmean = covmean.real\n        tr_covmean = np.trace(covmean)\n        return (mu1 - mu2).dot(mu1 - mu2) + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean\n    \n    @staticmethod\n    def normalize_rows(x):\n        return np.nan_to_num(x / np.linalg.norm(x, ord=2, axis=1, keepdims=True))\n    \n    def cosine_distance(self, features1):\n        features1_nozero = features1[np.sum(features1, axis=1) != 0]\n        features2_nozero = self.features2[np.sum(self.features2, axis=1) != 0]\n        norm_f1 = self.normalize_rows(features1_nozero)\n        norm_f2 = self.normalize_rows(features2_nozero)\n\n        d = 1.0 - np.abs(np.matmul(norm_f1, norm_f2.T))\n        mean_min_d = np.mean(np.min(d, axis=1))\n        return mean_min_d\n            \n    def calculate_kid_given_paths(self, user_images_unzipped_path):\n        with tf.Session() as sess:\n            sess.run(tf.global_variables_initializer())\n            m1, s1, features1 = self._handle_path_memorization(\n                user_images_unzipped_path, sess, is_checksize=True, is_check_png=True)\n\n            fid_value = self.calculate_frechet_distance(m1, s1)\n            distance = self.cosine_distance(features1)\n            return fid_value, distance\n        \n    def distance_thresholding(self, d):\n        if d < self.cosine_distance_eps:\n            return d\n        else:\n            return 1\n        \n    def evaluate(self, user_images_unzipped_path):\n        fid_value, distance = self.calculate_kid_given_paths(user_images_unzipped_path)\n        distance = self.distance_thresholding(distance)\n        return fid_value, distance, fid_value / (distance + self.fid_epsilon)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\ntrain_datagen = ImageDataGenerator()\n\ntrain_generator = train_datagen.flow_from_directory(\n        '../input/generative-dog-images/all-dogs/',\n        target_size=(64, 64),\n        batch_size=batch_size)\n\ntrain_datagen_augment = ImageDataGenerator( featurewise_center=True,\n        featurewise_std_normalization=True,\n        rotation_range=20,\n        horizontal_flip=True,\n        shear_range=0.2)\n\n\ntrain_generator_augment = train_datagen_augment.flow_from_directory(\n        '../input/generative-dog-images/all-dogs/',\n        target_size=(64, 64),\n        batch_size=batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#plt.imshow(image.array_to_img(train_generator[0][0][0]))\n#plt.show()\n\n#plt.imshow(image.array_to_img(train_generator_augment[0][0][0]))\n#plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DCGAN():\n    def __init__(self):\n        # Input shape\n        self.img_rows = 64\n        self.img_cols = 64\n        self.channels = 3\n        self.img_shape = (self.img_rows, self.img_cols, self.channels)\n        self.latent_dim = 100\n\n        optimizer = Adam(0.001, 0.5)\n\n        # Build and compile the discriminator\n        self.discriminator = self.build_discriminator()\n        self.discriminator.compile(loss='binary_crossentropy',\n            optimizer=optimizer,\n            metrics=['accuracy'])\n\n        # Build the generator\n        self.generator = self.build_generator()\n\n        # The generator takes noise as input and generates imgs\n        z = Input(shape=(self.latent_dim,))\n        img = self.generator(z)\n\n        # For the combined model we will only train the generator\n        self.discriminator.trainable = False\n\n        # The discriminator takes generated images as input and determines validity\n        valid = self.discriminator(img)\n\n        # The combined model  (stacked generator and discriminator)\n        # Trains the generator to fool the discriminator\n        self.combined = Model(z, valid)\n        self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)\n\n    def build_generator(self):\n\n        model = Sequential()\n\n        model.add(Dense(128 * 16 * 16, activation=\"relu\", input_dim=self.latent_dim))\n        model.add(Reshape((16, 16, 128)))\n        model.add(UpSampling2D())\n        model.add(Conv2D(128, kernel_size=3, padding=\"same\"))\n        model.add(BatchNormalization(momentum=0.8))\n        model.add(Activation(\"relu\"))\n        model.add(UpSampling2D())\n        model.add(Conv2D(64, kernel_size=3, padding=\"same\"))\n        model.add(BatchNormalization(momentum=0.8))\n        model.add(Activation(\"relu\"))\n        model.add(Conv2D(self.channels, kernel_size=3, padding=\"same\"))\n        model.add(Activation(\"tanh\"))\n\n        model.summary()\n\n        noise = Input(shape=(self.latent_dim,))\n        img = model(noise)\n\n        return Model(noise, img)\n\n    def build_discriminator(self):\n\n        model = Sequential()\n\n        model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=self.img_shape, padding=\"same\"))\n        model.add(LeakyReLU(alpha=0.2))\n        model.add(Dropout(0.25))\n        model.add(Conv2D(64, kernel_size=3, strides=2, padding=\"same\"))\n        model.add(ZeroPadding2D(padding=((0,1),(0,1))))\n        model.add(BatchNormalization(momentum=0.8))\n        model.add(LeakyReLU(alpha=0.2))\n        model.add(Dropout(0.25))\n        model.add(Conv2D(128, kernel_size=3, strides=2, padding=\"same\"))\n        model.add(BatchNormalization(momentum=0.8))\n        model.add(LeakyReLU(alpha=0.2))\n        model.add(Dropout(0.25))\n        model.add(Conv2D(256, kernel_size=3, strides=1, padding=\"same\"))\n        model.add(BatchNormalization(momentum=0.8))\n        model.add(LeakyReLU(alpha=0.2))\n        model.add(Dropout(0.25))\n        model.add(Flatten())\n        model.add(Dense(1, activation='sigmoid'))\n\n        model.summary()\n\n        img = Input(shape=self.img_shape)\n        validity = model(img)\n\n        return Model(img, validity)\n\n    def train(self, epochs, batch_size=128, save_interval=50,times_augment=0):\n\n        # Load the dataset\n        increase_batch=times_augment+1\n\n       # Adversarial ground truths\n        valid = np.ones((batch_size*increase_batch, 1))\n        fake = np.zeros((batch_size*increase_batch, 1))\n\n        for epoch in range(epochs):\n\n            # ---------------------\n            #  Train Discriminator\n            # ---------------------\n\n            # Select a random half of images\n\n            # Select a random batch of images and encode\n            #idx = np.random.randint(0, len(train_generator)-2)\n            imgs = train_generator[0][0]\n            for i in range(times_augment):\n                imgs_augment =train_generator_augment[0][0]\n                imgs=np.concatenate((imgs,imgs_augment), axis=0)\n            imgs = (imgs - 127.5) / 127.5\n\n            # Sample noise and generate a batch of new images\n            noise = np.random.normal(0, 1, (batch_size*increase_batch, self.latent_dim))\n            gen_imgs = self.generator.predict(noise)\n\n            # Train the discriminator (real classified as ones and generated as zeros)\n            d_loss_real = self.discriminator.train_on_batch(imgs, valid)\n            d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake)\n            d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)\n\n            # ---------------------\n            #  Train Generator\n            # ---------------------\n\n            # Train the generator (wants discriminator to mistake images as real)\n            g_loss = self.combined.train_on_batch(noise, valid)\n\n            # Plot the progress\n            if (epoch % save_interval == 0) or (epoch==epochs):\n                print (\"%d [D loss: %f, acc.: %.2f%%] [G loss: %f]\" % (epoch, d_loss[0], 100*d_loss[1], g_loss))\n\n            # If at save interval => save generated image samples\n            if (epoch % save_interval == 0) or (epoch==epochs):\n                self.save_imgs(epoch)\n                \n            if (epoch % save_interval == 0) or (epoch==epochs):          \n                for i in range(int(5)):\n                    r, c = 5, 5\n                    noise = np.random.normal(0, 1, (r * c, self.latent_dim))\n                    gen_imgs = self.generator.predict(noise)\n\n                    # Rescale images 0 - 1\n                    gen_imgs = 0.5 * gen_imgs + 0.5\n\n                    for j in range(20):\n                        img = image.array_to_img((gen_imgs[j, :,:,:]))\n                        img.save(os.path.join('../output_images/','generated_dog' + str(i) + '_'+ str(j) +'.png')) \n                plt.imshow(image.array_to_img(gen_imgs[3]))\n                plt.show()\n                evaluator = MiFIDEvaluator(MODEL_PATH, TRAIN_DIR / 'all-dogs/')\n                fid_value, distance, mi_fid_score = evaluator.evaluate(OUT_DIR)\n                print(f'FID: {fid_value:.5f}')\n                print(f'distance: {distance:.5f}')\n                print(f'MiFID: {mi_fid_score:.5f}')\n        for i in range(int(5)):\n            r, c = 5, 5\n            noise = np.random.normal(0, 1, (r * c, self.latent_dim))\n            gen_imgs = self.generator.predict(noise)\n\n            # Rescale images 0 - 1\n            gen_imgs = 0.5 * gen_imgs + 0.5\n\n            for j in range(20):\n                img = image.array_to_img((gen_imgs[j, :,:,:]))\n                img.save(os.path.join('../output_images/','generated_dog' + str(i) + '_'+ str(j) +'.png')) \n            plt.imshow(image.array_to_img(gen_imgs[3]))\n            plt.show()\n            evaluator = MiFIDEvaluator(MODEL_PATH, TRAIN_DIR / 'all-dogs/')\n            fid_value, distance, mi_fid_score = evaluator.evaluate(OUT_DIR)\n            print(f'FID: {fid_value:.5f}')\n            print(f'distance: {distance:.5f}')\n            print(f'MiFID: {mi_fid_score:.5f}')\n    def save_imgs(self, epoch):\n        r, c = 5, 5\n        noise = np.random.normal(0, 1, (r * c, self.latent_dim))\n        gen_imgs = self.generator.predict(noise)\n\n        # Rescale images 0 - 1\n        gen_imgs = 0.5 * gen_imgs + 0.5\n\n        fig, axs = plt.subplots(r, c)\n        cnt = 0\n        for i in range(r):\n            for j in range(c):\n                axs[i,j].imshow(gen_imgs[cnt, :,:,])\n                axs[i,j].axis('off')\n                cnt += 1\n        #fig.savefig(\"images/mnist_%d.png\" % epoch)\n        plt.show()\n        plt.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nif __name__ == '__main__':\n    dcgan = DCGAN()\n    dcgan.train(epochs=3000, batch_size=batch_size, save_interval=500,times_augment=0)\n\n    \nimport shutil\nshutil.make_archive('images', 'zip', '../output_images')\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}