{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Variational Autoencoder in Pytorch","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Thought it would be fun to try using a variational autoencoder approach and see what the latent space looks like. This is a demo using 15 of the most common classes.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"https://github.com/hsinyilin19/ResNetVAE/blob/master/ResNetVAE_reconstruction.ipynb","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# 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\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nfrom PIL import Image\nimport torch\nfrom torch import optim\nimport torch.nn as nn\nfrom torch.autograd import Variable\nimport torch.nn.functional as F\nimport torchvision.models as models\nimport torchvision.transforms as transforms\nimport torch.utils.data as data\nimport torchvision\nfrom torch.utils.data import Dataset, DataLoader, TensorDataset\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nimport os\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\nimport matplotlib.cm as cm\nfrom sklearn.manifold import TSNE\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train=pd.read_csv('../input/landmark-recognition-2020/train.csv')\nsubmission=pd.read_csv('../input/landmark-recognition-2020/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## How many landmarks are there?\nThis could influence our choice for the dimensionality of the latent space.\n\nThere is a considerable class imbalance with the rarest landmarks containing less than 10 images and the most common containing 1000s.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train.landmark_id.unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.hist(train.landmark_id,bins=100)\nplt.xscale('log')\nplt.title('Histogram of number of images per landmark id')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dataset\nThe dataset is relatively simple for this challenge (with large parts borrowed from https://www.kaggle.com/rhtsingh/pytorch-training-inference-efficientnet-baseline). Each time it is called for an item we read the relevant file, apply some transformations, and resize to the relevant size for the base model (here a resnet50).","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class RetrievalDataset(Dataset):\n    def __init__(self,ids,df,train=True):\n        self.train=train\n        if self.train:\n            self.root='../input/landmark-recognition-2020/train/'\n        else:\n            self.root='../input/landmark-recognition-2020/test/'\n        self.df=df.iloc[ids]\n        self.image_ids=self.df.id.values\n        self.landmark_ids=self.df.landmark_id.values\n        transforms_list = []\n        if self.train:\n            # Increase image size from (64,64) to higher resolution,\n            # Make sure to change in RandomResizedCrop as well.\n            transforms_list = [\n                transforms.Resize((224,224)),\n                transforms.RandomHorizontalFlip(),\n                transforms.RandomChoice([\n                    transforms.RandomResizedCrop(224),\n                    transforms.ColorJitter(0.2, 0.2, 0.2, 0.2),\n                    transforms.RandomAffine(degrees=15, translate=(0.2, 0.2),\n                                            scale=(0.8, 1.2), shear=15,\n                                            resample=Image.BILINEAR)\n                ]),\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                      std=[0.229, 0.224, 0.225]),\n            ]\n        else:\n            transforms_list.extend([\n                # Keep this resize same as train\n                transforms.Resize((224,224)),\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                      std=[0.229, 0.224, 0.225]),\n            ])\n        self.transforms = transforms.Compose(transforms_list)\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        image_id=self.image_ids[idx]\n        img=Image.open(self.root+image_id[0]+'/'+image_id[1]+'/'+image_id[2]+'/'+image_id+'.jpg')\n        img = self.transforms(img)\n        if self.train:\n            label=self.landmark_ids[idx]\n            return {'image':img, 'label':label}\n        else:\n            return {'image':img}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The Metric\nThis is an implementation for the competition metric - generalized average precision.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def GAP(predicts: torch.Tensor, confs: torch.Tensor, targets: torch.Tensor):\n    ''' Simplified GAP@1 metric: only one prediction per sample is supported '''\n    assert len(predicts.shape) == 1\n    assert len(confs.shape) == 1\n    assert len(targets.shape) == 1\n    assert predicts.shape == confs.shape and confs.shape == targets.shape\n\n    _, indices = torch.sort(confs, descending=True)\n\n    confs = confs.cpu().numpy()\n    predicts = predicts[indices].cpu().numpy()\n    targets = targets[indices].cpu().numpy()\n\n    res, true_pos = 0.0, 0\n\n    for i, (c, p, t) in enumerate(zip(confs, predicts, targets)):\n        rel = int(p == t)\n        true_pos += rel\n\n        res += true_pos / (i + 1) * rel\n\n    res /= targets.shape[0]-(targets == 0).sum()\n    return res","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The Loss function\nThe variational autoencoder loss function has two parts. The mean squared error component assures that the model produces faithful reconstructions. The 'Kullback-Liebler Divergence' ensures that the latent space is fit to a multivariate gaussian. ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def vae_loss_function(recon_x, x, mu, logvar):\n    # MSE = F.mse_loss(recon_x, x, reduction='sum')\n    MSE = F.binary_cross_entropy(recon_x, x, reduction='sum')\n    KLD = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())\n    return MSE + KLD","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Functions for training and validating the model for an epoch","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model,train_loader):\n    optimizer = optim.Adam(model.parameters())\n    criterion = nn.CrossEntropyLoss()\n    epoch_losses=[]\n    model.train()\n    epoch_loss=0\n    for i, data in enumerate(train_loader): \n        batch_size, _, _, _ = data['image'].shape\n        optimizer.zero_grad()\n        X_reconst, z, mu, logvar = model(data['image'].to(device))  # VAE\n        loss = vae_loss_function(X_reconst, data['image'].to(device), mu, logvar)\n        epoch_loss+=loss.item()\n        loss.backward()\n        optimizer.step()\n        print(\"Batch loss \",i,\": \",loss)\n    return model,epoch_loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def validate_model(model,val_loader):\n    criterion = nn.CrossEntropyLoss()\n    all_y, all_z, all_mu, all_logvar = [], [], [], []\n    model.eval()\n    epoch_loss=0\n    for i, data in enumerate(val_loader): \n        batch_size, _, _, _ = data['image'].shape\n        X_reconst, z, mu, logvar = model(data['image'].to(device))  # VAE\n        loss = vae_loss_function(X_reconst, data['image'].to(device), mu, logvar)\n        epoch_loss+=loss.item()\n        print(loss)\n        all_y.extend(data['label'].data.cpu().numpy())\n        all_z.extend(z.data.cpu().numpy())\n        all_mu.extend(mu.data.cpu().numpy())\n        all_logvar.extend(logvar.data.cpu().numpy())\n    return epoch_loss, all_y, all_z, all_mu, all_logvar","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Function for prediction","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def inference(data_loader, model):\n    model.eval()\n    activation = nn.Softmax(dim=1)\n    all_predicts, all_confs, all_targets = [], [], []\n\n    with torch.no_grad():\n        for i, data in enumerate(tqdm(data_loader, disable=IN_KERNEL)):\n            if dataloader.dataset.train:\n                image, target = data['image'], data['target']\n            else:\n                image, target = data['image'], None\n\n            output = model(image.to(device))\n            output = activation(output)\n\n            confs, predicts = torch.topk(output, NUM_TOP_PREDICTS)\n            all_confs.append(confs)\n            all_predicts.append(predicts)\n\n            if target is not None:\n                all_targets.append(target)\n\n    predicts = torch.cat(all_predicts)\n    confs = torch.cat(all_confs)\n    targets = torch.cat(all_targets) if len(all_targets) else None\n\n    return predicts, confs, targets","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Function for generating submissions","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_submission(test_loader, model, label_encoder):\n    sample_sub = pd.read_csv('../input/landmark-recognition-2020/sample_submission.csv')\n\n    predicts_gpu, confs_gpu, _ = inference(test_loader, model)\n    predicts, confs = predicts_gpu.cpu().numpy(), confs_gpu.cpu().numpy()\n\n    labels = [label_encoder.inverse_transform(pred) for pred in predicts]\n    print('labels')\n    print(np.array(labels))\n    print('confs')\n    print(np.array(confs))\n\n    sub = test_loader.dataset.df\n    def concat(label: np.ndarray, conf: np.ndarray) -> str:\n        return ' '.join([f'{L} {c}' for L, c in zip(label, conf)])\n    sub['landmarks'] = [concat(label, conf) for label, conf in zip(labels, confs)]\n\n    sample_sub = sample_sub.set_index('id')\n    sub = sub.set_index('id')\n    sample_sub.update(sub)\n\n    sample_sub.to_csv('submission.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The Model","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Since this competition is offline, we need to load pre-trained models using kaggle datasets.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_pretrained_model(model_name):\n    \"\"\"Retrieve a pre-trained model from torchvision\n\n    Params\n    -------\n        model_name (str): name of the model (currently only accepts vgg16 and resnet50)\n\n    Return\n    --------\n        model (PyTorch model): cnn\n\n    \"\"\"\n\n    if model_name == 'vgg16':\n        model = models.vgg16(pretrained=False)\n        model.load_state_dict(torch.load('../input/vgg16/vgg16.pth'))\n\n        # Freeze early layers\n        for param in model.parameters():\n            param.requires_grad = False\n        #n_outputs = model.classifier[6].out_features\n\n    elif model_name == 'resnet50':\n        model = models.resnet50(pretrained=False)\n        model.load_state_dict(torch.load('../input/resnet50/resnet50.pth'))\n\n        for param in model.parameters():\n            param.requires_grad = False\n\n        #n_outputs = model.fc.out_features\n\n    return model#, n_outputs","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### The VAE\nThe variational autoencoder is similar to the autoencoder. It has an encoder (here the resnet50) and a decoder (another CNN). However the variational autoencoder encodes the latent variables as means and variances of a guassian distribution rather than as deterministic variables. When we decode, we take a sample from this multivariate distribution as the input to the decoder rather than deterministic variables. This sampling takes place in the reparameterize step.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNet_VAE(nn.Module):\n    def __init__(self, fc_hidden1=1024, fc_hidden2=768, drop_p=0.3, CNN_embed_dim=256,model_name='resnet50'):\n        super(ResNet_VAE, self).__init__()\n\n        self.fc_hidden1, self.fc_hidden2, self.CNN_embed_dim = fc_hidden1, fc_hidden2, CNN_embed_dim\n\n        # CNN architechtures\n        self.ch1, self.ch2, self.ch3, self.ch4 = 16, 32, 64, 128\n        self.k1, self.k2, self.k3, self.k4 = (5, 5), (3, 3), (3, 3), (3, 3)      # 2d kernal size\n        self.s1, self.s2, self.s3, self.s4 = (2, 2), (2, 2), (2, 2), (2, 2)      # 2d strides\n        self.pd1, self.pd2, self.pd3, self.pd4 = (0, 0), (0, 0), (0, 0), (0, 0)  # 2d padding\n\n        # encoding components\n        resnet = get_pretrained_model(model_name)\n        modules = list(resnet.children())[:-1]      # delete the last fc layer.\n        self.resnet_modules=modules\n        self.resnet = nn.Sequential(*modules)\n        self.fc1 = nn.Linear(resnet.fc.in_features, self.fc_hidden1)\n        self.bn1 = nn.BatchNorm1d(self.fc_hidden1, momentum=0.01)\n        self.fc2 = nn.Linear(self.fc_hidden1, self.fc_hidden2)\n        self.bn2 = nn.BatchNorm1d(self.fc_hidden2, momentum=0.01)\n        # Latent vectors mu and sigma\n        self.fc3_mu = nn.Linear(self.fc_hidden2, self.CNN_embed_dim)      # output = CNN embedding latent variables\n        self.fc3_logvar = nn.Linear(self.fc_hidden2, self.CNN_embed_dim)  # output = CNN embedding latent variables\n\n        # Sampling vector\n        self.fc4 = nn.Linear(self.CNN_embed_dim, self.fc_hidden2)\n        self.fc_bn4 = nn.BatchNorm1d(self.fc_hidden2)\n        self.fc5 = nn.Linear(self.fc_hidden2, 64 * 4 * 4)\n        self.fc_bn5 = nn.BatchNorm1d(64 * 4 * 4)\n        self.relu = nn.ReLU(inplace=True)\n\n        # Decoder\n        self.convTrans6 = nn.Sequential(\n            nn.ConvTranspose2d(in_channels=64, out_channels=32, kernel_size=self.k4, stride=self.s4,\n                               padding=self.pd4),\n            nn.BatchNorm2d(32, momentum=0.01),\n            nn.ReLU(inplace=True),\n        )\n        self.convTrans7 = nn.Sequential(\n            nn.ConvTranspose2d(in_channels=32, out_channels=8, kernel_size=self.k3, stride=self.s3,\n                               padding=self.pd3),\n            nn.BatchNorm2d(8, momentum=0.01),\n            nn.ReLU(inplace=True),\n        )\n\n        self.convTrans8 = nn.Sequential(\n            nn.ConvTranspose2d(in_channels=8, out_channels=3, kernel_size=self.k2, stride=self.s2,\n                               padding=self.pd2),\n            nn.BatchNorm2d(3, momentum=0.01),\n            nn.Sigmoid()    # y = (y1, y2, y3) \\in [0 ,1]^3\n        )\n\n\n    def encode(self, x):\n        x = self.resnet(x)  # ResNet\n        x = x.view(x.size(0), -1)  # flatten output of conv\n\n        # FC layers\n        x = self.bn1(self.fc1(x))\n        x = self.relu(x)\n        x = self.bn2(self.fc2(x))\n        x = self.relu(x)\n        # x = F.dropout(x, p=self.drop_p, training=self.training)\n        mu, logvar = self.fc3_mu(x), self.fc3_logvar(x)\n        return mu, logvar\n\n    def reparameterize(self, mu, logvar):\n        if self.training:\n            std = logvar.mul(0.5).exp_()\n            eps = Variable(std.data.new(std.size()).normal_())\n            return eps.mul(std).add_(mu)\n        else:\n            return mu\n\n    def decode(self, z):\n        x = self.fc4(z)\n        x = self.relu(self.fc_bn4(x))\n        x = self.fc5(x)\n        x = self.relu(self.fc_bn5(x)).view(-1, 64, 4, 4)\n        x = self.convTrans6(x)\n        x = self.convTrans7(x)\n        x = self.convTrans8(x)\n        x = F.interpolate(x, size=(224, 224), mode='bilinear')\n        return x\n\n    def forward(self, x):\n        mu, logvar = self.encode(x)\n        z = self.reparameterize(mu, logvar)\n        x_reconst = self.decode(z)\n        return x_reconst, z, mu, logvar","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# EncoderCNN architecture\nCNN_fc_hidden1, CNN_fc_hidden2 = 1024, 1024\nCNN_embed_dim = 256     # latent dim extracted by 2D CNN\nres_size = 224        # ResNet image size\ndropout_p = 0.2       # dropout probability\n\n\n# training parameters\nepochs = 100        # training epochs\nbatch_size = 50\nlearning_rate = 1e-3\nlog_interval = 10   # interval for displaying training info","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create model\nmodel = ResNet_VAE(fc_hidden1=CNN_fc_hidden1, fc_hidden2=CNN_fc_hidden2, drop_p=dropout_p, CNN_embed_dim=CNN_embed_dim).to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_params = list(model.parameters())\noptimizer = torch.optim.Adam(model_params, lr=learning_rate)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"MIN_SAMPLES_PER_CLASS = 50\ncounts = train.landmark_id.value_counts()\nselected_classes = counts[counts >= MIN_SAMPLES_PER_CLASS].index\nnum_classes = selected_classes.shape[0]\nprint('classes with at least N samples:', num_classes)\ntrain = train.loc[train.landmark_id.isin(selected_classes)]\nprint(train.shape)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### For this demo select a small subset of the classes to train on","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Demo mode to get a random subset of classes\ndemo=True\nnum_classes_demo=15\nif demo:\n    random_class_subset=np.random.choice(train.landmark_id.unique(),num_classes_demo,replace=False)\n    train = train.loc[train.landmark_id.isin(random_class_subset)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_examples(train,random_class_subset,n_examples):\n    root='../input/landmark-recognition-2020/train/'\n    l=len(random_class_subset)\n    fig, axs=plt.subplots(len(random_class_subset),n_examples,figsize=(50,100))\n    for c in range(l):\n        c_ids=train.loc[train.landmark_id==random_class_subset[c]][:n_examples].id.values\n        for i in range(n_examples):\n            image_id=c_ids[i]\n            axs[c,i].imshow(Image.open(root+image_id[0]+'/'+image_id[1]+'/'+image_id[2]+'/'+image_id+'.jpg'))\n            plt.axis('off')\n            axs[c,i].set_title('Landmark '+ str(random_class_subset[c])+': Example '+ str(i))\n    plt.tight_layout()\n    plt.show()\n\nplot_examples(train,random_class_subset,3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size=32\n\nids = np.arange(len(train))\nnp.random.shuffle(ids)\nids=np.array(ids)\n\ntrain_ids,val_ids=np.split(ids, [int(round(0.9 * len(ids), 0))])\n\n\ntrain_dataset=RetrievalDataset(train_ids,train)\nval_dataset=RetrievalDataset(val_ids,train)\ntrain_loader=DataLoader(train_dataset, batch_size=batch_size,\n                              shuffle=True, num_workers=5)\nval_loader=DataLoader(val_dataset, batch_size=batch_size,\n                              shuffle=True, num_workers=5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Benchmarking Loader","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import time\nbatch_size=32\nworkers=4\nk=30\ntrain_loader=DataLoader(train_dataset, batch_size=batch_size,\n                              shuffle=False, num_workers=workers,pin_memory=True)\nt0=time.time()\nfor i, data in enumerate(train_loader): \n    if i==k:\n        break\n        \nprint(\"Time per image: \" , (time.time()-t0)/(k*32), \" seconds\")\nprint(\"Time per epoch: \" , (time.time()-t0)*len(train_loader)/(k*60), \" minutes\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs=50\nimport time\n\nt0=time.time()\nfor epoch in range(epochs):\n    model,epoch_loss=train_model(model,train_loader)\n    epoch_loss, all_y, all_z, all_mu, all_logvar = validate_model(model,val_loader)\n    \nprint(time.time()-t0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes = random_class_subset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_train = np.array(all_y)\nz_train = np.array(all_z)\n\nfig = plt.figure(figsize=(12, 10))\nplots = []\n#markers = ['o', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']\nfor i, c in enumerate(classes):\n    ind = (y_train == c).tolist() or ([j < N // len(classes) for j in range(len(y_train))])\n    color = cm.jet([i / len(classes)] * sum(ind))\n    plots.append(plt.scatter(z_train[ind, 1], z_train[ind, 2], c=color, s=8, label=i))\n\nplt.axis('off')\nplt.legend(plots, classes, fontsize=14, loc='upper right')\nplt.title('direct projection:  2-dim')\n#plt.savefig(\"./ResNetVAE_{}_direct_plot.png\".format(exp), bbox_inches='tight', dpi=600)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"z_embed = TSNE(n_components=2, n_iter=12000).fit_transform(z_train)\n\nfig = plt.figure(figsize=(12, 10))\nplots = []\n#markers = ['o', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']  # select different markers\nfor i, c in enumerate(classes):\n    ind = (y_train == c).tolist()\n    color = cm.jet([i / len(classes)] * sum(ind))\n    # plot each category one at a time \n    plots.append(plt.scatter(z_embed[ind, 0], z_embed[ind, 1], c=color, s=8, label=i))\n\nplt.axis('off')\nplt.legend(plots, classes, fontsize=14, loc='upper right')\nplt.title('t-SNE: 2-dim')\n#plt.savefig(\"./ResNetVAE_{}_embedded_plot.png\".format(exp), bbox_inches='tight', dpi=600)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"z_embed3D = TSNE(n_components=3, n_iter=12000).fit_transform(z_train)\n\nfig = plt.figure(figsize=(12, 10))\nax = fig.add_subplot(111, projection='3d')\n\nplots = []\n#markers = ['o', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']  # select different markers\nfor i, c in enumerate(classes):\n    ind = (y_train == c).tolist()\n    color = cm.jet([i / len(classes)] * sum(ind))\n    # plot each category one at a time \n    ax.scatter(z_embed3D[ind, 0], z_embed3D[ind, 1], c=color, s=8, label=i)\n\nax.axis('on')\n\n#r_max = 20\n#r_min = -r_max\n\nax.set_xlim(r_min, r_max)\nax.set_ylim(r_min, r_max)\nax.set_zlim(r_min, r_max)\nax.set_xlabel('z-dim 1')\nax.set_ylabel('z-dim 2')\nax.set_zlabel('z-dim 3')\nax.set_title('t-SNE: 3-dim')\nax.legend(plots, classes, fontsize=14, loc='upper right')\n#plt.savefig(\"./ResNetVAE_{}_embedded_3Dplot.png\".format(exp), bbox_inches='tight', dpi=600)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}