{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Imports"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nimport os\nimport torch\nimport torch.nn as nn\nimport torchvision\nfrom torchvision import models, transforms, datasets\nimport time\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"torch.__version__","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import sys\nsys.version","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nprint('Using gpu : %s ' % torch.cuda.is_available())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## data processing"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_dir = '../input/dogscats/dogscats/dogscats/'\nprint(os.listdir('../input/dogscats/dogscats/dogscats/'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                std = [0.229, 0.224, 0.225])\nvgg_format = transforms.Compose([\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    normalize,\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dsets = {x:datasets.ImageFolder(os.path.join(data_dir, x), vgg_format)\n        for x in ['train', 'valid']}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dsets['train'].class_to_idx","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dset_sizes = {x : len(dsets[x]) for x in ['train', 'valid']}\ndset_sizes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dset_classes = dsets['valid'].classes\ndset_classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"load_train = torch.utils.data.DataLoader(dsets['train'], batch_size=64, \n                                        shuffle=True, num_workers=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"load_test = torch.utils.data.DataLoader(dsets['valid'], batch_size=5, \n                                        shuffle=True, num_workers=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"count = 1\nfor data in load_test:\n    print(count , end=',')\n    if count == 1:\n        inputs_try, labels_try = data\n    count += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_try","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inputs_try.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def imshow(inp, title=None):\n    inp = inp.numpy().transpose((1, 2, 0))\n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n    inp = np.clip(std * inp + mean, 0, 1)\n    plt.imshow(inp)\n    if title is not None:\n        plt.title(title)\n    plt.pause(0.001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"out = torchvision.utils.make_grid(inputs_try)\nimshow(out, title=[dset_classes[x] for x in labels_try])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inputs, classes = next(iter(load_train))\n\nn_images =  8\n\nout = torchvision.utils.make_grid(inputs[0:n_images])\n\nimshow(out, title=[dset_classes[x] for x in classes[0:n_images]])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inputs, classes = next(iter(load_test))\n\nn_images =  8\n\nout = torchvision.utils.make_grid(inputs[0:n_images])\n\nimshow(out, title=[dset_classes[x] for x in classes[0:n_images]])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Creating VGG Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model_vgg = models.vgg16(pretrained=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import json\nfpath = '../input/imagenet-class-index/imagenet_class_index.json'\nwith open(fpath) as f:\n    class_dict = json.load(f)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dic_imagenet = [class_dict[str(i)][1] for i in range(len(class_dict))]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inputs_try, lables_try = inputs_try.to(device), labels_try.to(device)\n\nmodel_vgg = model_vgg.to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"outputs_try = model_vgg(inputs_try)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"outputs_try","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"outputs_try.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"m_softm = nn.Softmax(dim=1)\nprobs = m_softm(outputs_try)\nvals_try, preds_try = torch.max(probs, dim=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.sum(probs, 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vals_try","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print([dic_imagenet[i] for i in preds_try.data])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"out = torchvision.utils.make_grid(inputs_try.data.cpu())\nimshow(out, title=[dset_classes[x] for x in labels_try.data.cpu()])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Modifying the last layer and setting the gradient false to all layers"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(model_vgg)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for param in model_vgg.parameters():\n    param.requires_grad = False\nmodel_vgg.classifier._modules['6'] = nn.Linear(4096, 2)\nmodel_vgg.classifier._modules['7'] =  torch.nn.LogSoftmax(dim=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`LogSoftmax`:\n        $$LogSoftmax(x_i) = log(\\frac{exp(x_i)}{\\sum_jexp(x_j)})$$"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(model_vgg.classifier)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_vgg = model_vgg.to(device)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Training fully connected module"},{"metadata":{},"cell_type":"markdown","source":"#### Creating loss function and optimizer"},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = nn.NLLLoss()\nlr = 0.001\noptimizer_vgg = torch.optim.SGD(model_vgg.classifier[6].parameters(), lr = lr)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### training the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model, dataloader, size, epochs=1, optimizer=None):\n    model.train()\n    \n    for epoch in range(epochs):\n        running_loss = 0.0\n        running_corrects = 0\n        for inputs, classes in dataloader:\n            inputs = inputs.to(device)\n            classes = classes.to(device)\n            outputs = model(inputs)\n            loss = criterion(outputs, classes)\n            optimizer = optimizer\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            _, preds = torch.max(outputs.data, 1)\n            #statistics\n            running_loss += loss.data.item()\n            running_corrects += torch.sum(preds == classes.data)\n        epoch_loss = running_loss / size\n        epoch_acc = running_corrects.data.item() / size\n        print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%time\ntrain_model(model_vgg, load_train,\n            size=dset_sizes['train'], epochs=2, optimizer=optimizer_vgg)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_model(model, dataloader, size):\n    model.eval()\n    predictions = np.zeros(size)\n    all_classes = np.zeros(size)\n    all_proba = np.zeros((size, 2))\n    i = 0\n    running_loss = 0.0\n    running_corrects = 0\n    for inputs, classes in dataloader:\n        inputs = inputs.to(device)\n        classes = classes.to(device)\n        outputs = model(inputs)\n        loss = criterion(outputs, classes)\n        _, preds = torch.max(outputs.data, 1)\n        # statistics\n        running_loss += loss.data.item()\n        running_corrects += torch.sum(preds == classes.data)\n        predictions[i : i + len(classes)] = preds.to('cpu').numpy()\n        all_classes[i : i + len(classes)] = classes.to('cpu').numpy()\n        all_proba[i : i + len(classes)] = outputs.data.to('cpu').numpy()\n        \n        i += len(classes)\n    epoch_loss = running_loss / size\n    epoch_acc = running_corrects.data.item() / size\n    print('Loss : {:.4f} Acc : {:.4f}'.format(epoch_loss, epoch_acc))\n    return predictions, all_proba, all_classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%time\npredictions, all_proba, all_classes = test_model(model_vgg, load_test, size=\n                                                dset_sizes['valid'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get a batch of training data\ninputs, classes = next(iter(load_test))\n\nout = torchvision.utils.make_grid(inputs[0: n_images])\n\nimshow(out, title=[dset_classes[x] for x in classes[0:n_images]])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"outputs = model_vgg(inputs[:n_images].to(device))\nprint(torch.exp(outputs))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes[:n_images]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Speeding up the learning by precomputing features"},{"metadata":{"trusted":true},"cell_type":"code","source":"x_try = model_vgg.features(inputs_try)\nx_try.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def preconvfeat(dataloader):\n    conv_features = []\n    labels_list = []\n    for data in dataloader:\n        inputs, labels = data\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n        \n        x = model_vgg.features(inputs)\n        conv_features.extend(x.data.cpu().numpy())\n        labels_list.extend(labels.data.cpu().numpy())\n        conv_features = np.concatenate([[feat] for feat in conv_features])\n        \n        return (conv_features, labels_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nconv_feat_train, labels_train = preconvfeat(load_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"conv_feat_train.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nconv_feat_valid, labels_valid = preconvfeat(load_test)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Creating a new data generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"def data_gen(conv_feat, labels, batch_size=64, shuffle=True):\n    labels = np.array(labels)\n    if shuffle:\n        index = np.random.permutation(len(conv_feat))\n        conv_feat = conv_feat[index]\n        labels = labels[index]\n    for idx in range(0, len(conv_feat), batch_size):\n        yield(conv_feat[idx:idx + batch_size], labels[idx : idx + batch_size])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model, size, epochs=1, optimizer=None):\n    model.train()\n    \n    for epoch in range(epochs):\n        dataloader = data_gen(conv_feat_train, labels_train)\n        running_loss = 0.0\n        running_corrects = int(0)\n        for inputs, classes in dataloader:\n            \n            inputs, classes = torch.from_numpy(inputs).to(device), torch.from_numpy(classes).to(device)\n            inputs = inputs.to(device)\n            classes = classes.to(device)\n            inputs = inputs.view(inputs.size(0), -1)\n            outputs = model(inputs)\n            loss = criterion(outputs, classes)\n            optimizer = optimizer\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            _, preds = torch.max(outputs.data, 1)\n            # statistics\n            running_loss += loss.data.item()\n            running_corrects += torch.sum(preds == classes.data)\n        epoch_loss = running_loss / size\n        epoch_acc = running_corrects.item() / size\n        print('Loss : {:.4f} Acc : {:.4f}'.format(epoch_loss, epoch_acc))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\ntrain_model(model_vgg.classifier, size=dset_sizes['train'], epochs=50,\n           optimizer=optimizer_vgg)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_model(model, size):\n    model.eval()\n    predictions = np.zeros(size)\n    all_classes = np.zeros(size)\n    all_proba = np.zeros((size, 2))\n    i = 0\n    running_loss = 0.0\n    running_corrects = 0\n    for inputs, classes in data_gen(conv_feat_valid, labels_valid, shuffle=False):\n        inputs, classes = torch.from_numpy(inputs).to(device),torch.from_numpy(classes).to(device)\n        inputs = inputs.to(device)\n        classes = classes.to(device)\n        inputs = inputs.view(inputs.size(0), -1) \n        outputs = model(inputs)\n        loss = criterion(outputs, classes)\n        _, preds = torch.max(outputs.data, 1)\n        # statistics\n        running_loss += loss.data.item()\n        running_corrects += torch.sum(preds == classes.data)\n        #print(i)\n        predictions[i:i+len(classes)] = preds.to('cpu').numpy()\n        all_classes[i : i + len(classes)] = classes.to('cpu').numpy()\n        all_proba[i : i + len(classes),:] = outputs.data.to('cpu').numpy()\n        #print(preds.cpu())\n        i += len(classes)\n    epoch_loss = running_loss / size\n    epoch_acc = running_corrects.data.item() / size\n    print('Loss {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))\n    return predictions , all_proba, all_classes\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions, all_proba, all_classes = test_model(model_vgg.classifier,size=dset_sizes['valid'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Viewing model prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"n_view = 8","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"correct = np.where(predictions == all_classes)[0]\ncorrect","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(correct) / dset_sizes['valid']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from numpy.random import random, permutation\nidx = permutation(correct)[:n_view]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idx","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loader_correct = torch.utils.data.DataLoader([dsets['valid'][x] for x\n                                             in idx], batch_size = n_view, shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for data in loader_correct:\n    inputs_cor, labels_cor = data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"out = torchvision.utils.make_grid(inputs_cor)\nimshow(out, title=[l.item() for l in labels_cor])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import Image, display\nfor x in idx:\n    display(Image(filename=dsets['valid'].imgs[x][0], retina=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"incorrect = np.where(predictions!=all_classes)[0]\nfor x in permutation(incorrect)[:n_view]:\n    display(Image(filename=dsets['valid'].imgs[x][0], retina=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"correct_cats = np.where((predictions == 0) & (predictions == all_classes))[0]\nmost_correct_cats = np.argsort(all_proba[correct_cats, 0])[:n_view]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for x in most_correct_cats:\n    display(Image(filename=dsets['valid'].imgs[correct_cats[x]][0], retina=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#3. The images we most confident were dogs, and are actually dogs\ncorrect_dogs = np.where((predictions==1) & (predictions==all_classes))[0]\nmost_correct_dogs = np.argsort(all_proba[correct_dogs,0])[:n_view]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for x in most_correct_dogs:\n    display(Image(filename=dsets['valid'].imgs[correct_dogs[x]][0], retina=True))","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}