{"cells":[{"metadata":{"_uuid":"23dc4b0aac8a9f7716834e5e3017682add156b1f"},"cell_type":"markdown","source":"# Freesound General-Purpose Audio Tagging Challenge"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import copy\nimport gzip\nimport os\nimport time\nfrom functools import reduce # only in Python 3\nfrom glob import glob\n\nimport librosa\nfrom librosa.display import *\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.preprocessing import LabelBinarizer, LabelEncoder, StandardScaler\nfrom torch.nn import LSTM\nfrom torch.nn.utils.rnn import (pack_padded_sequence, pad_packed_sequence,\n                                pad_sequence)\nfrom torch.utils.data import DataLoader, Dataset, random_split\n\n# setting device on GPU if available, else CPU\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Using device:', device)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nprint(plt.style.available)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2e94f3c6847f1da69b1e60aeaa50ecbca3b5da67"},"cell_type":"markdown","source":"Exploring the dataset"},{"metadata":{"trusted":true,"_uuid":"ebc20d87bf5f52b2aaf5788a02fb102441c7c42e"},"cell_type":"code","source":"print(os.listdir('../input'))\ntrain = pd.read_csv(\"../input/train.csv\")\ntest = pd.read_csv(\"../input/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"de1c9705d9cd3561e48730180e4d36ce03f4d541"},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a9999e67ab32083a0cb1a108e8c4d4bd244b4c52"},"cell_type":"code","source":"print('The dataset consists of {} training examples'.format(len(train)))\nprint('The dataset contains audio files from {} different categories'.format(len(train.label.unique())))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3d06607abc0b16c5b1ead0abad8bddaad78d3998"},"cell_type":"markdown","source":"Some of the samples are manually verified while others not"},{"metadata":{"trusted":true,"_uuid":"154710aa53eec943d45ae9016a84313a15b8e7d5"},"cell_type":"code","source":"category_group = train.groupby(['label', 'manually_verified']).count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6167b66dcf0d795738f95bd998c683507ee2b99e"},"cell_type":"code","source":"plot = category_group.unstack().reindex(category_group.unstack().sum(axis=1).sort_values().index)\\\n          .plot(kind='bar', stacked=True, title=\"Number of Audio Samples per Category\", figsize=(16,10))\nplot.set_xlabel(\"Category\")\nplot.set_ylabel(\"Number of Samples\")\nplt.legend(['Not verified', 'Verified']);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0ccdaa770399f5223fb5d4b9be3f560b4a90723e"},"cell_type":"code","source":"class LabelTransformer(LabelEncoder):\n    def inverse(self, y):\n        try:\n            return super(LabelTransformer, self).inverse_transform(y)\n        except:\n            return super(LabelTransformer, self).inverse_transform([y])\n\n    def transform(self, y):\n        try:\n            return super(LabelTransformer, self).transform(y)\n        except:\n            return super(LabelTransformer, self).transform([y])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9fb31157dce29325ab5ad45c3fbada7ccfa3e611"},"cell_type":"code","source":"import wave\nclass FGPA_Dataset(Dataset):\n    \n    def __init__(self, path, filenames, labels, use_mfcc=False):\n        super(FGPA_Dataset, self).__init__()\n        self.dir = path\n        self.sr = 44100 if use_mfcc else 16000 \n        self.max_duration_in_sec = 4\n        self.max_length = self.sr * self.max_duration_in_sec\n        self.use_mfcc = use_mfcc\n        self.n_mfccs = 40\n        \n        self.filenames = filenames\n        self.labels = labels\n        \n        self.sequences = np.array([self.load_data_from(filename) for filename in filenames])\n        print(self.sequences.shape)\n        \n    def __getitem__(self, index):\n        return self.sequences[index], self.labels[index]\n    \n    def __len__(self):\n        return len(self.sequences)\n    \n    def load_data_from(self, filename):\n\n        original_samples = self.read_waveform(filename)\n\n        if len(original_samples) > self.max_length:\n            max_offset = len(original_samples) - self.max_length\n            offset = np.random.randint(max_offset)\n            samples = original_samples[offset:(self.max_length+offset)]\n        else:\n            if self.max_length > len(original_samples):\n                max_offset = self.max_length - len(original_samples)\n                offset = np.random.randint(max_offset)\n            else:\n                offset = 0\n            samples = np.pad(original_samples, (offset, self.max_length - len(original_samples) - offset), \"constant\")\n\n        if self.use_mfcc:\n            samples = librosa.feature.mfcc(samples, sr=self.sr, n_mfcc=self.n_mfccs)\n        else:\n            pass\n        \n        return samples\n    \n    def read_waveform(self, filename):\n        return librosa.core.load(self.dir+filename, sr=self.sr,res_type='kaiser_fast')[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a1652c46e2367e60376f2252b9e670cd68c3015d"},"cell_type":"code","source":"train_csv = pd.read_csv(\"../input/train.csv\")\ntrain_csv = train_csv.iloc[np.random.randint(low=len(train_csv), size=1000)]\ntrain_filenames = train_csv['fname'].values\ntrain_labels = train_csv['label'].values\nlen(np.unique(train_labels))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d5a6a8144dbc9a6e1483fb5a30b61260b88f23cc"},"cell_type":"code","source":"label_transformer = LabelTransformer()\nlabel_transformer = label_transformer.fit(train_labels)\ntrain_label_ids = label_transformer.transform(train_labels)\nlen(np.unique(train_label_ids))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"226d4b6ba2a474e46d50c1fe56def97bd4f304bc"},"cell_type":"code","source":"test_csv = pd.read_csv(\"../input/test_post_competition.csv\")\ntest_csv = test_csv[test_csv.usage != 'Ignored']\ntest_filenames = test_csv['fname'].values\ntest_labels = test_csv['label'].values\ntest_label_ids = label_transformer.transform(test_labels)\nlen(np.unique(test_label_ids))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c89165b075dec2293108d1b295920050187b74b3"},"cell_type":"code","source":"train_idx, validation_idx = next(iter(StratifiedKFold(n_splits=5).split(np.zeros_like(train_label_ids), train_label_ids)))\ntrain_files = train_filenames[train_idx]\ntrain_labels = train_label_ids[train_idx]\nval_files = train_filenames[validation_idx]\nval_labels = train_label_ids[validation_idx]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c89165b075dec2293108d1b295920050187b74b3"},"cell_type":"code","source":"d_train[0:2][0].shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"706a00a15167d356fd95950be3663bbcaf62b8fd"},"cell_type":"code","source":"label_df = pd.DataFrame({'labels':train_labels, 'count': np.ones_like(train_labels)}).groupby(['labels'], as_index=True).count()\nlabel_count_dict = label_df.to_dict()['count']\nplt.figure(num=None, figsize=(16,10))\nplt.bar(label_count_dict.keys(), label_count_dict.values())\nplt.xticks(rotation=90)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e6af3ab9d0f2684f0cd8be765533bb7ad4aee113"},"cell_type":"code","source":"def predict(model, test_dataset, device, batch_size=16):\n    \n    # Set the model to evaluation mode\n    model = model.eval()\n    \n    # Wrap with no grad because the operations here\n    # should not affect the gradient computations\n    with torch.no_grad():\n        \n        predictions = np.array([])\n        actual  = np.array([])\n        correct = np.array([])\n        \n        for i, data in enumerate(DataLoader(test_dataset, batch_size)):\n            \n            # Load the batch\n            X_batch, y_batch = data\n            # Send to device for faster computations\n            X_batch, y_batch = X_batch.to(device), y_batch.to(device)\n            \n            # Get the output of the model\n            out = model(X_batch.float()).max(1)[1]\n            # Send to device for faster computations\n            out = out.to(device)\n            \n            actual = np.append(actual, y_batch.cpu().detach().numpy())\n            correct = np.append(correct, (out == y_batch).cpu().detach().numpy())\n            predictions = np.append(predictions, out.cpu().detach().numpy())\n                            \n    return predictions, correct, actual\n\ndef train(model, train_dataset, optimizer, criterion, device, epochs=30, batch_size=16, validation_dataset=None, model_name=None):\n\n    if validation_dataset is not None:\n        datasets = {\n            'train': train_dataset,\n            'validation': validation_dataset\n        }\n        previous_loss = 100\n        phases = ['train', 'validation']\n    else:\n        train_dataset = train_dataset\n        datasets = {\n            'train': train_dataset,\n            'validation': None\n        }\n        phases = ['train']\n    \n    if torch.cuda.device_count() > 1:\n        print('Training computations are running on {} GPUs.'.format(torch.cuda.device_count()))\n        model = nn.DataParallel(model)\n    \n    # Send to device for faster computations\n    model = model.to(device) \n\n    train_loss = np.array([])\n    validation_loss = np.array([])\n    \n    for epoch in range(epochs):\n        print('Epoch {}/{}'.format(epoch, epochs - 1))\n        print('-' * 10)\n        for phase in phases:\n            if phase == 'train':\n                print('Entering the training phase..')\n                # Set the model to training mode\n                model = model.train()\n            else:\n                print('Entering the validation phase..')\n                # Set the model to evaluation mode\n                model = model.eval()\n\n            # Clear loss for this epoch\n            running_loss = 0.0\n\n            for i, data in enumerate(DataLoader(datasets[phase], batch_size=batch_size, drop_last=True)):\n                # Load the batch\n                X_batch, y_batch = data\n                # Send to device for faster computations\n                X_batch, y_batch  = X_batch.to(device), y_batch.to(device)\n\n                # Clear gradients\n                optimizer.zero_grad()\n                \n                with torch.set_grad_enabled(phase == 'train'):\n                    # Get the output of the model\n                    out = model(X_batch.float())\n                    # Send to device for faster computations\n                    out = out.to(device)\n                       \n                    # Compute loss\n                    loss = criterion(out.float(), y_batch)\n\n                    if phase == 'train':\n                        # Compute the new gradients\n                        loss.backward()\n                        # Update the weights\n                        optimizer.step()\n                \n                # Accumulate loss for this batch\n                running_loss += loss.item()\n\n            print('{} loss: {}'.format(phase, running_loss / (i+1)))\n\n            if phase == 'validation':\n                current_loss = running_loss / (i+1)\n                if current_loss < previous_loss:\n                    \n                    print('Loss decreased. Saving the model..')\n                    # If loss decreases,\n                    # save the current model as the best-shot checkpoint\n                    torch.save(model.state_dict(), '{}.pt'.format(model_name))\n\n                    # update the value of the loss\n                    previous_loss = current_loss\n                else:\n                    pass\n\n            if phase=='train':\n                train_loss = np.append(train_loss, running_loss / (i+1))\n            else:\n                validation_loss = np.append(validation_loss, current_loss)\n                \n            print()\n    \n    plt.figure(figsize=(8,6))\n    plt.plot(train_loss, c='b')\n    plt.plot(validation_loss, c='r')\n    plt.xticks(np.arange(len(train_loss)))\n    plt.legend(['Training loss', 'Validation loss'])\n    plt.show()\n    model.load_state_dict(torch.load('{}.pt'.format(model_name), map_location=device))\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0183473cd37cd78a418d60f369ddc5519c8dc7bc"},"cell_type":"code","source":"class CNN_1D(torch.nn.Module):\n\n    def __init__(self, n_features, n_classes):\n        \n        super(CNN_1D, self).__init__()\n        \n        self.n_features = n_features\n        self.n_classes = n_classes\n        \n        self.conv_layer11 = nn.Conv1d(\n            in_channels = 1,\n            out_channels = 16,\n            kernel_size = 9\n        )\n        self.conv_layer12 = nn.Conv1d(\n            in_channels = 16,\n            out_channels = 16,\n            kernel_size = 9\n        )\n        self.max_pool1 = nn.MaxPool1d(\n            kernel_size=16\n        )\n        self.dropout1 = nn.Dropout(0.1)\n        self.conv_layer21 = nn.Conv1d(\n            in_channels = 16,\n            out_channels = 32,\n            kernel_size = 3\n        )\n        self.conv_layer22 = nn.Conv1d(\n            in_channels = 32,\n            out_channels = 32,\n            kernel_size = 3\n        )\n        self.max_pool2 = nn.MaxPool1d(\n            kernel_size=4\n        )\n        self.dropout2 = nn.Dropout(0.1)\n        self.conv_layer31 = nn.Conv1d(\n            in_channels = 32,\n            out_channels = 32,\n            kernel_size = 3\n        )\n        self.conv_layer32 = nn.Conv1d(\n            in_channels = 32,\n            out_channels = 32,\n            kernel_size = 3\n        )\n        self.max_pool3 = nn.MaxPool1d(\n            kernel_size=4\n        )\n        self.dropout3 = nn.Dropout(0.1)\n        self.conv_layer41 = nn.Conv1d(\n            in_channels = 32,\n            out_channels = 256,\n            kernel_size = 3\n        )\n        self.conv_layer42 = nn.Conv1d(\n            in_channels = 256,\n            out_channels = 256,\n            kernel_size = 3\n        )\n        self.max_pool4 = nn.MaxPool1d(\n            kernel_size=1869\n        )\n        self.conv_layers = nn.Sequential(\n            self.conv_layer11,\n            self.conv_layer12,\n            self.max_pool1,\n            self.dropout1,\n            self.conv_layer21,\n            self.conv_layer22,\n            self.max_pool2,\n            self.dropout2,\n            self.conv_layer31,\n            self.conv_layer32,\n            self.max_pool3,\n            self.dropout3,\n            self.conv_layer41,\n            self.conv_layer42,\n            self.max_pool4\n        )\n        self.dense_layers = nn.Sequential(\n            nn.Linear(256, 128),\n            nn.Linear(128, 41)\n        )\n    \n    def forward(self, input):\n        conv_out = self.conv_layers(input.unsqueeze(dim=1)).squeeze()\n        dense_out = self.dense_layers(conv_out)\n        return dense_out\n\ncnn1d = CNN_1D(1, 41)\n# cnn1d.forward(torch.FloatTensor([[d[0][0].numpy()]])).detach().numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8d4ff948ff48f9586dc779647e5ee7fe0f358b4b"},"cell_type":"code","source":"class CNN_2D(torch.nn.Module):\n\n    def __init__(self, n_features, n_classes):\n        \n        super(CNN_2D, self).__init__()\n        \n        self.n_features = n_features\n        self.n_classes = n_classes\n        \n        self.conv_layer1 = nn.Conv2d(\n            in_channels = 1,\n            out_channels = 32,\n            kernel_size = (4,10)\n        )\n        self.batch_norm1 = nn.BatchNorm2d(32)\n        self.max_pool1 = nn.MaxPool2d(2)\n        self.relu1 = nn.ReLU()\n        \n        self.conv_layer2 = nn.Conv2d(\n            in_channels = 32,\n            out_channels = 32,\n            kernel_size = (4,10)\n        )\n        self.batch_norm2 = nn.BatchNorm2d(32)\n        self.max_pool2 = nn.MaxPool2d(2)\n        self.relu2 = nn.ReLU()\n        \n        self.conv_layer3 = nn.Conv2d(\n            in_channels = 32,\n            out_channels = 32,\n            kernel_size = (4,10)\n        )\n        self.batch_norm3 = nn.BatchNorm2d(32)\n        self.max_pool3 = nn.MaxPool2d(2)\n        self.relu3 = nn.ReLU()\n        \n        self.conv_layers = nn.Sequential(\n            self.conv_layer1,\n            self.max_pool1,\n            self.batch_norm1,\n            self.relu1,\n            self.conv_layer2,\n            self.max_pool2,\n            self.batch_norm2,\n            self.relu2,\n            self.conv_layer3,\n            self.max_pool3,\n            self.batch_norm3,\n            self.relu3\n        )\n        self.dense_layers = nn.Sequential(\n            nn.Linear(32*2*35, 256),\n            nn.Dropout(0.5),\n            nn.Linear(256, 41)\n        )\n    \n    def forward(self, input):\n        conv_out = self.conv_layers(input.unsqueeze(dim=1)).squeeze()\n        dense_out = self.dense_layers(conv_out.view(conv_out.size()[0], -1))\n        return dense_out\n\ncnn2d = CNN_2D(1, 41)\n# cnn1d.forward(torch.FloatTensor([[d[0][0].numpy()]])).detach().numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2da3546ce22caa473a75b3b3515fece619eca1ba"},"cell_type":"code","source":"train_dataset_wave = FGPA_Dataset(\"../input/audio_train/audio_train/\", train_files, train_labels, use_mfcc=False)\nvalidation_dataset_wave = FGPA_Dataset(\"../input/audio_train/audio_train/\", val_files, val_labels, use_mfcc=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b45b1316bdf70135aae78fbd2bc52d24d427fea2"},"cell_type":"code","source":"cnn1d = train(cnn1d, train_dataset_wave, torch.optim.Adam(cnn1d.parameters()), nn.CrossEntropyLoss(), torch.device('cuda'), epochs=20, batch_size=32, validation_dataset=validation_dataset_wave, model_name='cnn1d')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"83617a8537814e62acd8ba5efde4abaccc7f4901"},"cell_type":"code","source":"import gc\ndel train_dataset_wave; del validation_dataset_wave; \ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c5ce0a9f9a45ea48cdb56179c025ce4abc4b2cff"},"cell_type":"code","source":"train_dataset_mfccs = FGPA_Dataset(\"../input/audio_train/audio_train/\", train_files, train_labels, use_mfcc=True)\nvalidation_dataset_mfccs = FGPA_Dataset(\"../input/audio_train/audio_train/\", val_files, val_labels, use_mfcc=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"03806ca9773641d77d2b3c85a64c27ce91417bb5"},"cell_type":"code","source":"cnn2d = train(cnn2d, train_dataset_mfccs, torch.optim.Adam(cnn2d.parameters()), nn.CrossEntropyLoss(), torch.device('cuda'), epochs=10, batch_size=32, validation_dataset=validation_dataset_mfccs, model_name='cnn2d')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"83617a8537814e62acd8ba5efde4abaccc7f4901"},"cell_type":"code","source":"test_dataset_wave = FGPA_Dataset(\"../input/audio_test/audio_test/\", test_filenames, test_label_ids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9bf680743b0e0de3bc13ae72c2f3f95e8652916f"},"cell_type":"code","source":"predictions, correct, actual = predict(cnn1d, test_dataset_wave, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6fd4fb3dd73eea40ec20c17f1c87614db307557c"},"cell_type":"code","source":"test_dataset_mfccs = FGPA_Dataset(\"../input/audio_test/audio_test/\", test_filenames, test_label_ids, use_mfcc=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6fd4fb3dd73eea40ec20c17f1c87614db307557c"},"cell_type":"code","source":"predictions, correct, actual= predict(cnn2d, test_dataset_mfccs, device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d7139d9edc9b680957a309dc16db6db9e710b567"},"cell_type":"code","source":"print(label_transformer.inverse_transform(predictions.astype('int64')))\nprint(correct.sum() / len(predictions))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f5e6e7b16189465fdc82cf2cef121f9f4bc81e9f"},"cell_type":"code","source":"pred_df = pd.DataFrame({'prediction':label_transformer.inverse_transform(predictions.astype('int64')), 'count': np.ones_like(predictions)}).groupby(['prediction'], as_index=True).count()\npred_count_dict = pred_df.to_dict()['count']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"34ea1bcbe043f0016df6f7fb6a860cdfd8f1f056"},"cell_type":"code","source":"plt.figure(num=None, figsize=(16,10))\nplt.bar(pred_count_dict.keys(), pred_count_dict.values())\nplt.xticks(rotation=90)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"02a0882b44924790eaf32dbedb6b0d5778bc0007"},"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport itertools\n\ndef plot_confusion_matrix(cm, classes,\n                          normalize=False,\n                          title='Confusion matrix',\n                          cmap=plt.cm.Blues):\n    \"\"\"\n    This function prints and plots the confusion matrix.\n    Normalization can be applied by setting `normalize=True`.\n    \"\"\"\n    if normalize:\n        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n        print(\"Normalized confusion matrix\")\n    else:\n        print('Confusion matrix, without normalization')\n\n    print(cm)\n\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(classes))\n    plt.xticks(tick_marks, classes, rotation=90)\n    plt.yticks(tick_marks, classes)\n\n    fmt = '.2f' if normalize else 'd'\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, format(cm[i, j], fmt),\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8977f59c476c06de1d18010941e2769595daa654"},"cell_type":"code","source":"# Compute confusion matrix\ncnf_matrix = confusion_matrix(actual, predictions)\nnp.set_printoptions(precision=2)\n\n# Plot non-normalized confusion matrix\nplt.figure(figsize=(16,16))\nplot_confusion_matrix(cnf_matrix, classes=label_transformer.classes_,\n                      title='Confusion matrix, without normalization (Acc: 54.875%)')\n\n# Plot normalized confusion matrix\n# plt.figure(figsize=(20,20))\n# plot_confusion_matrix(cnf_matrix, classes=label_transformer.classes_, normalize=True,\n#                       title='Normalized confusion matrix')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad08f936b34e4a8bb98658db4639451abb0f2375"},"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.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}