{"cells":[{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"ComputeLB = False\nDogsOnly = False\n\nimport numpy as np, pandas as pd, os\nimport xml.etree.ElementTree as ET \nimport matplotlib.pyplot as plt, zipfile \nfrom PIL import Image \n\nROOT = '../input/generative-dog-images/'\nif not ComputeLB: ROOT = '../input/'\nIMAGES = os.listdir(ROOT + 'all-dogs/all-dogs/')\nbreeds = os.listdir(ROOT + 'annotation/Annotation/') \n\nidxIn = 0; namesIn = []\nimagesIn = np.zeros((25000,64,64,3))\n\n# CROP WITH BOUNDING BOXES TO GET DOGS ONLY\nif DogsOnly:\n    for breed in breeds:\n        for dog in os.listdir(ROOT+'annotation/Annotation/'+breed):\n            try: img = Image.open(ROOT+'all-dogs/all-dogs/'+dog+'.jpg') \n            except: continue           \n            tree = ET.parse(ROOT+'annotation/Annotation/'+breed+'/'+dog)\n            root = tree.getroot()\n            objects = root.findall('object')\n            for o in objects:\n                bndbox = o.find('bndbox') \n                xmin = int(bndbox.find('xmin').text)\n                ymin = int(bndbox.find('ymin').text)\n                xmax = int(bndbox.find('xmax').text)\n                ymax = int(bndbox.find('ymax').text)\n                w = np.min((xmax - xmin, ymax - ymin))\n                img2 = img.crop((xmin, ymin, xmin+w, ymin+w))\n                img2 = img2.resize((64,64), Image.ANTIALIAS)\n                imagesIn[idxIn,:,:,:] = np.asarray(img2)\n                #if idxIn%1000==0: print(idxIn)\n                namesIn.append(breed)\n                idxIn += 1\n                \n# RANDOMLY CROP FULL IMAGES\nelse:\n    x = np.random.choice(np.arange(20000),10000)\n    for k in range(len(x)):\n        img = Image.open(ROOT + 'all-dogs/all-dogs/' + IMAGES[x[k]])\n        w = img.size[0]; h = img.size[1];\n        if (k%2==0)|(k%3==0):\n            w2 = 100; h2 = int(h/(w/100))\n            a = 18; b = 0          \n        else:\n            a=0; b=0\n            if w<h:\n                w2 = 64; h2 = int((64/w)*h)\n                b = (h2-64)//2\n            else:\n                h2 = 64; w2 = int((64/h)*w)\n                a = (w2-64)//2\n        img = img.resize((w2,h2), Image.ANTIALIAS)\n        img = img.crop((0+a, 0+b, 64+a, 64+b))  \n        imagesIn[idxIn,:,:,:] = np.asarray(img)\n        namesIn.append(IMAGES[x[k]])\n        #if idxIn%1000==0: print(idxIn)\n        idxIn += 1\n    \n# DISPLAY CROPPED IMAGES\nx = np.random.randint(0,idxIn,25)\nfor k in range(5):\n    plt.figure(figsize=(15,3))\n    for j in range(5):\n        plt.subplot(1,5,j+1)\n        img = Image.fromarray( imagesIn[x[k*5+j],:,:,:].astype('uint8') )\n        plt.axis('off')\n        if not DogsOnly: plt.title(namesIn[x[k*5+j]],fontsize=11)\n        else: plt.title(namesIn[x[k*5+j]].split('-')[1],fontsize=11)\n        plt.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Build Generative Network\nThis generative network is the decoder from my autoencoder kernel [here][1]\n\n[1]: https://www.kaggle.com/cdeotte/dog-autoencoder"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.models import Model\nfrom keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D, Reshape, BatchNormalization\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import LearningRateScheduler\nfrom keras.optimizers import SGD, Adam","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# BUILD GENERATIVE NETWORK\ndirect_input = Input((10000,))\nx = Dense(2048, activation='elu')(direct_input)\nx = Reshape((8,8,32))(x)\nx = Conv2D(128, (3, 3), activation='elu', padding='same')(x)\nx = UpSampling2D((2, 2))(x)\nx = Conv2D(64, (3, 3), activation='elu', padding='same')(x)\nx = UpSampling2D((2, 2))(x)\nx = Conv2D(32, (3, 3), activation='elu', padding='same')(x)\nx = UpSampling2D((2, 2))(x)\ndecoded = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(x)\n\n# COMPILE\ndecoder = Model(direct_input, decoded)\ndecoder.compile(optimizer=Adam(lr=0.003), loss='binary_crossentropy')\n\n# DISPLAY ARCHITECTURE\ndecoder.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train Generative Network"},{"metadata":{"trusted":true},"cell_type":"code","source":"# TRAINING DATA\nidx = np.random.randint(0,idxIn,10000)\ntrain_y = imagesIn[idx,:,:,:]/255.\ntrain_X = np.zeros((10000,10000))\nfor i in range(10000): train_X[i,i] = 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# TRAIN NETWORK\nlr = 0.005\nfor k in range(50):\n    annealer = LearningRateScheduler(lambda x: lr)\n    h = decoder.fit(train_X, train_y, epochs = 20, batch_size=256, callbacks=[annealer], verbose=0)\n    if k%5==4: print('Epoch',(k+1)*10,'/500 - loss =',h.history['loss'][-1] )\n    if h.history['loss'][-1]<0.54: lr = 0.001","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Delete Training Images\nOur generative network has now memorized all the training images. We will now delete the training images. As per the rules [here][1], our generative network can now \"stand alone\" without the assistance of training images.\n\n[1]: https://www.kaggle.com/c/generative-dog-images/discussion/98183"},{"metadata":{"trusted":true},"cell_type":"code","source":"del train_X, train_y, imagesIn","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Generate Random Dogs\nBut inputting a random vector of length 10000 into our generative network, we will get out a random dog image. This is how a VAE or GAN works. "},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Generate Random Dogs')    \nfor k in range(5):\n    plt.figure(figsize=(15,3))\n    for j in range(5):\n        xx = np.zeros((10000))\n        xx[np.random.randint(10000)] = 1\n        xx[np.random.randint(10000)] = 0.75\n        #xx[np.random.randint(10000)] = 0.25\n        xx = xx/(np.sqrt(xx.dot(xx.T)))\n        plt.subplot(1,5,j+1)\n        img = decoder.predict(xx.reshape((-1,10000)))\n        img = Image.fromarray( (255*img).astype('uint8').reshape((64,64,3)))\n        plt.axis('off')\n        plt.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Recall from Memory Dogs\nSimilar to a VAE or GAN, we can get a random image from our generative network by inputting a random vector of length 10000. What is special about our network is that we used supervised training to organize memory such that inputting the vector `x1 = [1, 0, ,0, ..., 0, 0]` will output the memorized version of training image 1. And `x2 = [0, 1, 0, ..., 0, 0]` will output memorized training image 2. Below we display 25 memorized images."},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Recall from Memory Dogs')    \nfor k in range(5):\n    plt.figure(figsize=(15,3))\n    for j in range(5):\n        xx = np.zeros((10000))\n        xx[np.random.randint(10000)] = 1\n        plt.subplot(1,5,j+1)\n        img = decoder.predict(xx.reshape((-1,10000)))\n        img = Image.fromarray( (255*img).astype('uint8').reshape((64,64,3)))\n        plt.axis('off')\n        plt.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Walking in the Latent Space\nA test to determine if your GAN memorized or generalized is to walk in latent space. (More info about latent space in my first kernel [here][3]). Starting from one seed `x1`, move in a straight line through latent space to seed `x2`. For each intermediate seed, output the assoicated generated image. If the images are simple pixel blends of image `x1` with `x2` then most likely you're memorizing. If all the intermediate images are valid images themselves (and don't look like simple blends) then most likely you're generalizing. See section 6.1 [here][2] for more info.\n\nThe following example from the cited paper above shows that walking in latent space from one bedroom image to another bedroom image produces valid intermediate images. Notice how the intermediate images are not simple pixel blends. Instead they conceptually change objects on the walls through a series of different valid objects.\n\n![image](http://playagricola.com/Kaggle/walk7319.png)\n\nBecause our GAN's memory is organized such that training image 1 can be retrieved with seed `x1 = [1, 0, 0, ...,0, 0]` and training image 2 with seed `x2 = [0, 1, 0, ..., 0, 0]`, we will walk from training image 1 to training image 2. We just need to set one vector element as `theta` (where `0 <= theta <= 1`) and the other as `1-theta` then we get `theta`% of image 1 and `(1-theta)`% of image 2. Then we vary `theta` from 0 to 1.\n\nIn the sequences below, you will observe akward middle images. If we perform the following experiment with a GAN that learns to **generalize** then we won't see middle images of awkward blends. A well designed adversarial discriminative network could insure that every image outputted by our generative network is a valid realistic dog image. Currently, our supervised GN only made sure that the 10000 images that it memorized are valid. A full **generalizing** GAN can output millions of valid pictures! And it can make smooth transistions between input seeds. See [here][1] for a video example.\n\n[1]: https://towardsdatascience.com/do-gans-really-model-the-true-data-distribution-or-are-they-just-cleverly-fooling-us-d08df69f25eb\n[2]: https://arxiv.org/abs/1511.06434\n[3]: https://www.kaggle.com/cdeotte/dog-autoencoder"},{"metadata":{"trusted":true},"cell_type":"code","source":"for k in range(6):\n    if (k==0)|(k==2)|(k==4):\n        print('Walk in Latent Space') \n        a = np.random.randint(10000)\n        b = np.random.randint(10000)\n    plt.figure(figsize=(15,3))\n    for j in range(5):\n        xx = np.zeros((10000))\n        theta = ((k%2)*5+j)/9\n        xx[a] = theta; xx[b] = 1-theta\n        xx = xx/(np.sqrt(xx.dot(xx.T)))\n        plt.subplot(1,5,j+1)\n        img = decoder.predict(xx.reshape((-1,10000)))\n        img = Image.fromarray( (255*img).astype('uint8').reshape((64,64,3)))\n        plt.axis('off')\n        plt.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submit to Kaggle\nThe problem with generative methods that memorize training images is that it allows the submission of essentially original images. For example submit 99% original image 1 with 1% original image 2 added. Then essentially we would be submitting image 1. Furthermore the MiFID metric doesn't recognize that cropped images are the same as original images. Therefore a **memorizing** generative method using cropped images can score very low LB."},{"metadata":{"trusted":true},"cell_type":"code","source":"# SAVE TO ZIP FILE NAMED IMAGES.ZIP\nz = zipfile.PyZipFile('images.zip', mode='w')\nfor k in range(10000):\n    # GENERATE NEW DOGS\n    xx = np.zeros((10000))\n    xx[np.random.randint(10000)] = 0.99\n    xx[np.random.randint(10000)] = 0.01\n    img = decoder.predict(xx.reshape((-1,10000)))\n    img = Image.fromarray( (255*img).astype('uint8').reshape((64,64,3)))\n    # SAVE TO ZIP FILE  \n    f = str(k)+'.png'\n    img.save(f,'PNG'); z.write(f); os.remove(f)\n    #if k % 1000==0: print(k)\nz.close()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Calculate LB Score\nIf you wish to compute LB, you must add the LB metric dataset [here][1] to this kernel and change the boolean variable to `True` in the first code cell block. If you wish to submit `Images.zip` to Kaggle, then you must remove the LB metric dataset and change the boolean variable to `False`.\n\n[1]: https://www.kaggle.com/wendykan/dog-face-generation-competition-kid-metric-input"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from __future__ import absolute_import, division, print_function\nimport numpy as np\nimport os\nimport gzip, pickle\nimport tensorflow as tf\nfrom scipy import linalg\nimport pathlib\nimport urllib\nimport warnings\nfrom tqdm import tqdm\nfrom PIL import Image\n\nclass KernelEvalException(Exception):\n    pass\n\nmodel_params = {\n    'Inception': {\n        'name': 'Inception', \n        'imsize': 64,\n        'output_layer': 'Pretrained_Net/pool_3:0', \n        'input_layer': 'Pretrained_Net/ExpandDims:0',\n        'output_shape': 2048,\n        'cosine_distance_eps': 0.1\n        }\n}\n\ndef create_model_graph(pth):\n    \"\"\"Creates a graph from saved GraphDef file.\"\"\"\n    # Creates graph from saved graph_def.pb.\n    with tf.gfile.FastGFile( pth, '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\ndef _get_model_layer(sess, model_name):\n    # layername = 'Pretrained_Net/final_layer/Mean:0'\n    layername = model_params[model_name]['output_layer']\n    layer = sess.graph.get_tensor_by_name(layername)\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\ndef get_activations(images, sess, model_name, batch_size=50, verbose=False):\n    \"\"\"Calculates the activations of the pool_3 layer for all images.\n\n    Params:\n    -- images      : Numpy array of dimension (n_images, hi, wi, 3). The values\n                     must lie between 0 and 256.\n    -- sess        : current session\n    -- batch_size  : the images numpy array is split into batches with batch size\n                     batch_size. A reasonable batch size depends on the disposable hardware.\n    -- verbose    : If set to True and parameter out_step is given, the number of calculated\n                     batches is reported.\n    Returns:\n    -- A numpy array of dimension (num images, 2048) that contains the\n       activations of the given tensor when feeding inception with the query tensor.\n    \"\"\"\n    inception_layer = _get_model_layer(sess, model_name)\n    n_images = images.shape[0]\n    if batch_size > n_images:\n        print(\"warning: batch size is bigger than the data size. setting batch size to data size\")\n        batch_size = n_images\n    n_batches = n_images//batch_size + 1\n    pred_arr = np.empty((n_images,model_params[model_name]['output_shape']))\n    for i in tqdm(range(n_batches)):\n        if verbose:\n            print(\"\\rPropagating batch %d/%d\" % (i+1, n_batches), end=\"\", flush=True)\n        start = i*batch_size\n        if start+batch_size < n_images:\n            end = start+batch_size\n        else:\n            end = n_images\n                    \n        batch = images[start:end]\n        pred = sess.run(inception_layer, {model_params[model_name]['input_layer']: batch})\n        pred_arr[start:end] = pred.reshape(-1,model_params[model_name]['output_shape'])\n    if verbose:\n        print(\" done\")\n    return pred_arr\n\n\n# def calculate_memorization_distance(features1, features2):\n#     neigh = NearestNeighbors(n_neighbors=1, algorithm='kd_tree', metric='euclidean')\n#     neigh.fit(features2) \n#     d, _ = neigh.kneighbors(features1, return_distance=True)\n#     print('d.shape=',d.shape)\n#     return np.mean(d)\n\ndef normalize_rows(x: np.ndarray):\n    \"\"\"\n    function that normalizes each row of the matrix x to have unit length.\n\n    Args:\n     ``x``: A numpy matrix of shape (n, m)\n\n    Returns:\n     ``x``: The normalized (by row) numpy matrix.\n    \"\"\"\n    return np.nan_to_num(x/np.linalg.norm(x, ord=2, axis=1, keepdims=True))\n\n\ndef cosine_distance(features1, features2):\n    # print('rows of zeros in features1 = ',sum(np.sum(features1, axis=1) == 0))\n    # print('rows of zeros in features2 = ',sum(np.sum(features2, axis=1) == 0))\n    features1_nozero = features1[np.sum(features1, axis=1) != 0]\n    features2_nozero = features2[np.sum(features2, axis=1) != 0]\n    norm_f1 = normalize_rows(features1_nozero)\n    norm_f2 = normalize_rows(features2_nozero)\n\n    d = 1.0-np.abs(np.matmul(norm_f1, norm_f2.T))\n    print('d.shape=',d.shape)\n    print('np.min(d, axis=1).shape=',np.min(d, axis=1).shape)\n    mean_min_d = np.mean(np.min(d, axis=1))\n    print('distance=',mean_min_d)\n    return mean_min_d\n\n\ndef distance_thresholding(d, eps):\n    if d < eps:\n        return d\n    else:\n        return 1\n\ndef calculate_frechet_distance(mu1, sigma1, mu2, sigma2, eps=1e-6):\n    \"\"\"Numpy implementation of the Frechet Distance.\n    The Frechet distance between two multivariate Gaussians X_1 ~ N(mu_1, C_1)\n    and X_2 ~ N(mu_2, C_2) is\n            d^2 = ||mu_1 - mu_2||^2 + Tr(C_1 + C_2 - 2*sqrt(C_1*C_2)).\n            \n    Stable version by Dougal J. Sutherland.\n\n    Params:\n    -- mu1 : Numpy array containing the activations of the pool_3 layer of the\n             inception net ( like returned by the function 'get_predictions')\n             for generated samples.\n    -- mu2   : The sample mean over activations of the pool_3 layer, precalcualted\n               on an representive data set.\n    -- sigma1: The covariance matrix over activations of the pool_3 layer for\n               generated samples.\n    -- sigma2: The covariance matrix over activations of the pool_3 layer,\n               precalcualted on an representive data set.\n\n    Returns:\n    --   : The Frechet Distance.\n    \"\"\"\n\n    mu1 = np.atleast_1d(mu1)\n    mu2 = np.atleast_1d(mu2)\n\n    sigma1 = np.atleast_2d(sigma1)\n    sigma2 = np.atleast_2d(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    diff = mu1 - mu2\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 = \"fid calculation produces singular product; adding %s to diagonal of cov estimates\" % eps\n        warnings.warn(msg)\n        offset = np.eye(sigma1.shape[0]) * eps\n        # covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset))\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(\"Imaginary component {}\".format(m))\n        covmean = covmean.real\n\n    # covmean = tf.linalg.sqrtm(tf.linalg.matmul(sigma1,sigma2))\n\n    print('covmean.shape=',covmean.shape)\n    # tr_covmean = tf.linalg.trace(covmean)\n\n    tr_covmean = np.trace(covmean)\n    return diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean\n    # return diff.dot(diff) + tf.linalg.trace(sigma1) + tf.linalg.trace(sigma2) - 2 * tr_covmean\n#-------------------------------------------------------------------------------\n\n\ndef calculate_activation_statistics(images, sess, model_name, batch_size=50, verbose=False):\n    \"\"\"Calculation of the statistics used by the FID.\n    Params:\n    -- images      : Numpy array of dimension (n_images, hi, wi, 3). The values\n                     must lie between 0 and 255.\n    -- sess        : current session\n    -- batch_size  : the images numpy array is split into batches with batch size\n                     batch_size. A reasonable batch size depends on the available hardware.\n    -- verbose     : If set to True and parameter out_step is given, the number of calculated\n                     batches is reported.\n    Returns:\n    -- mu    : The mean over samples of the activations of the pool_3 layer of\n               the incption model.\n    -- sigma : The covariance matrix of the activations of the pool_3 layer of\n               the incption model.\n    \"\"\"\n    act = get_activations(images, sess, model_name, batch_size, verbose)\n    mu = np.mean(act, axis=0)\n    sigma = np.cov(act, rowvar=False)\n    return mu, sigma, act\n    \ndef _handle_path_memorization(path, sess, model_name, is_checksize, is_check_png):\n    path = pathlib.Path(path)\n    files = list(path.glob('*.jpg')) + list(path.glob('*.png'))\n    imsize = model_params[model_name]['imsize']\n\n    # In production we don't resize input images. This is just for demo purpose. \n    x = np.array([np.array(img_read_checks(fn, imsize, is_checksize, imsize, is_check_png)) for fn in files])\n    m, s, features = calculate_activation_statistics(x, sess, model_name)\n    del x #clean up memory\n    return m, s, features\n\n# check for image size\ndef img_read_checks(filename, resize_to, is_checksize=False, check_imsize = 64, is_check_png = False):\n    im = Image.open(str(filename))\n    if is_checksize and im.size != (check_imsize,check_imsize):\n        raise KernelEvalException('The images are not of size '+str(check_imsize))\n    \n    if is_check_png and im.format != 'PNG':\n        raise KernelEvalException('Only PNG images should be submitted.')\n\n    if resize_to is None:\n        return im\n    else:\n        return im.resize((resize_to,resize_to),Image.ANTIALIAS)\n\ndef calculate_kid_given_paths(paths, model_name, model_path, feature_path=None, mm=[], ss=[], ff=[]):\n    ''' Calculates the KID of two paths. '''\n    tf.reset_default_graph()\n    create_model_graph(str(model_path))\n    with tf.Session() as sess:\n        sess.run(tf.global_variables_initializer())\n        m1, s1, features1 = _handle_path_memorization(paths[0], sess, model_name, is_checksize = True, is_check_png = True)\n        if len(mm) != 0:\n            m2 = mm\n            s2 = ss\n            features2 = ff\n        elif feature_path is None:\n            m2, s2, features2 = _handle_path_memorization(paths[1], sess, model_name, is_checksize = False, is_check_png = False)\n        else:\n            with np.load(feature_path) as f:\n                m2, s2, features2 = f['m'], f['s'], f['features']\n\n        print('m1,m2 shape=',(m1.shape,m2.shape),'s1,s2=',(s1.shape,s2.shape))\n        print('starting calculating FID')\n        fid_value = calculate_frechet_distance(m1, s1, m2, s2)\n        print('done with FID, starting distance calculation')\n        distance = cosine_distance(features1, features2)        \n        return fid_value, distance, m2, s2, features2","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"if ComputeLB:\n    \n    # UNCOMPRESS OUR IMGAES\n    with zipfile.ZipFile(\"../working/images.zip\",\"r\") as z:\n        z.extractall(\"../tmp/images2/\")\n\n    # COMPUTE LB SCORE\n    m2 = []; s2 =[]; f2 = []\n    user_images_unzipped_path = '../tmp/images2/'\n    images_path = [user_images_unzipped_path,'../input/generative-dog-images/all-dogs/all-dogs/']\n    public_path = '../input/dog-face-generation-competition-kid-metric-input/classify_image_graph_def.pb'\n\n    fid_epsilon = 10e-15\n\n    fid_value_public, distance_public, m2, s2, f2 = calculate_kid_given_paths(images_path, 'Inception', public_path, mm=m2, ss=s2, ff=f2)\n    distance_public = distance_thresholding(distance_public, model_params['Inception']['cosine_distance_eps'])\n    print(\"FID_public: \", fid_value_public, \"distance_public: \", distance_public, \"multiplied_public: \",\n            fid_value_public /(distance_public + fid_epsilon))\n    \n    # REMOVE FILES TO PREVENT KERNEL ERROR OF TOO MANY FILES\n    ! rm -r ../tmp","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}