{"cells":[{"metadata":{"_uuid":"049c4b5886e31b2f3b33f963fe2c4cd7ebc3015f"},"cell_type":"markdown","source":"### This is the best way I've found to work with all of this images!\n\nWe all had problems when we needed to work with HUGE (* Ok, this isn't a huge dataset, but it's large* :D ) dataset of images. But, calm down, we're here to help you!! <br/>\nWe all want to play around with all of these whales, but that can be a challenge. If you've also have the problem of working with large image datasets, this is the Kernel for you.\n\nThinking about exploring this dataset and creating a simpler model? I've also created a more hands on approach to this competition, you can find the Kernel <br/><br/>\n*  [Whales. A Simple Guide!](https://www.kaggle.com/jhonatansilva31415/whales-a-simple-guide/)\n\nTo make a more in depth explanation on the details of this Kernel I've made this video on YouTube \n## Full Video Explanation of this Kernel\n[How to work with large image datasets](https://www.youtube.com/watch?v=myYMrZXpn6U)\n## Full Video Explanation of the previous Kernel\n[KAGGLE KERNELS - HOW TO START AT 2019](https://www.youtube.com/watch?v=AXcTm4gFerE)\n\n<br/> \nIf you are still here ( I'm glad you are .0. ) let's move on :D \n\n## Notebook Content\n1. [The Libraries we all Like](#first-bullet)\n2. [Our Own customizable Whales Class](#second-bullet)\n3. [Having a look at the dataset](#third-bullet)\n4. [Transforming our images ](#forth-bullet)\n5. [Transforming one Whale](#fifth-bullet)\n6. [Creating our transformed dataset](#sixth-bullet)\n7. [Loading it upl](#seventh-bullet)\n\n#### Disclaimer\nThis tutorial was just possible by the great documentation from the PyTorch website, I've made some adaptations from the [DATA LOADING AND PROCESSING TUTORIAL](https://pytorch.org/tutorials/beginner/data_loading_tutorial.html)"},{"metadata":{"_uuid":"5e0395dd8e35ff73b56801b321103714a0140cce"},"cell_type":"markdown","source":"### The Libraries we all Like <a class=\"anchor\" id=\"first-bullet\"></a>\nPandas, Numpy, Matplotlib are in pratically all the Kernels I see. A part from that, we are going to be using **PyTorch** "},{"metadata":{"trusted":true,"_uuid":"270714e96b7ff774ebe850362dfcb1873ac8243b"},"cell_type":"code","source":"from __future__ import print_function, division\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\nimport time\nimport os\nimport copy\n\nfrom os import listdir, makedirs, getcwd, remove\nfrom os.path import isfile, join, abspath, exists, isdir, expanduser\nfrom torch.optim import lr_scheduler\nfrom skimage import io, transform\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, utils\nfrom torchvision import datasets, models, transforms\nfrom torch.autograd import Variable\nfrom IPython.display import clear_output\n\n# Ignore warnings\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nplt.ion()   # interactive mode","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8c44ed3825d6ee7208dcd674a8c5fb40d4851098"},"cell_type":"code","source":"image_size = 128","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0f8f487fcc624e4fb259a0eb654892735e9d39aa"},"cell_type":"code","source":"humpback_whales_path = '/kaggle/input' \ntrain_path = os.path.join(humpback_whales_path,'train.csv')\nhumpback_whales_train_path = os.path.join(humpback_whales_path,'train')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bab4cca0ed51bfc60ba29d7a5bee2c7c16ec38b4"},"cell_type":"markdown","source":"### Our Own customizable Whales Class  <a class=\"anchor\" id=\"second-bullet\"></a>\nTo handle this entire dataset we're going to be creating our own class to him. In this we define what will be the dataframe, what is the root directory, and what transformations we are going to pass to it. <br/> \nAnother thing we need to create ( this is where the **magic** happens ) is the \\__getitem__ , we're going to be using this to iterate throught the dataset <br/>\nLast but not least we are going to be using the same encoding as [here](https://www.kaggle.com/jhonatansilva31415/whales-a-simple-guide/) , you can find out more in the [Video](https://www.youtube.com/watch?v=AXcTm4gFerE)"},{"metadata":{"trusted":true,"_uuid":"ad505c719fc7e341a38532306d62e57224a327e2"},"cell_type":"code","source":"class WhalesDS(Dataset):\n    \"\"\" Humpback Whale Identification Challenge dataset. \"\"\"\n    def __init__(self, csv_file, root_dir, transform=None):\n        \"\"\"\n        Args:\n            csv_file (string): Path to the csv file with annotations.\n            root_dir (string): Directory with all the images.\n            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        self.whales_frame = self.encode()\n        self.root_dir = root_dir\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.whales_frame)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.root_dir,\n                                self.whales_frame.iloc[idx, 0])\n        image = io.imread(img_name)\n        label = self.whales_frame.iloc[idx,1]\n        sample = {'image': image, 'label': label}\n\n        if self.transform:\n            sample = self.transform(sample)\n\n        return sample\n\n    def encode(self):\n        \"\"\" Encoding \"\"\"\n        df = pd.read_csv(train_path)\n        unique_classes = pd.unique(df['Id'])\n        encoding = dict(enumerate(unique_classes))\n        encoding = {value: key for key, value in encoding.items()}\n        df = df.replace(encoding)\n        return df ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5d5f5c963c07130d462755a182a05ae3a22141a6"},"cell_type":"markdown","source":"### Having a look at the dataset <a class=\"anchor\" id=\"third-bullet\"></a>\nWe can instantiate our WhalesDS model and pass the csv path file ( If you've downloaded this Kernel into your **personal computer**, change this to the location of the files). Then we can iterate through it and explore the images ( already a matrix ) with sample['image'] and remember our labels are being transformed on the instantiation of the dataset, so you wont be getting \"new_whale\" **but a number**."},{"metadata":{"trusted":true,"_uuid":"81253c024e939b88bc0b5535927a8258f600c9f5"},"cell_type":"code","source":"whales_ds = WhalesDS(csv_file=train_path,\n                     root_dir=humpback_whales_train_path)\n\nfig = plt.figure()\n\nfor i in range(len(whales_ds)):\n    sample = whales_ds[i]\n    print(i, sample['image'].shape, sample['label'])\n\n    ax = plt.subplot(1, 4, i + 1)\n    ax.set_title('Sample #{}'.format(i))\n    ax.axis('off')\n    plt.imshow(sample['image'])\n\n    if i == 3:\n        plt.show()\n        break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ba88004c7d7612e977e72cdbfe61058635c01345"},"cell_type":"markdown","source":"### Transforming our images  <a class=\"anchor\" id=\"forth-bullet\"></a>\nŃow  we have control over our labels and images. This let us have some work and prepare this to our model. Here we are using some personalized solutions, we are creating our **Rescale**, or **RandomCrop** and Transforming it to **Tensor**, you can have a look at some out of the box solutions from PyTorch [here](https://pytorch.org/docs/stable/torchvision/transforms.html)!\n<br/>\nBut let me tell you why is good to create our own functions, this dataset has different type of images, RGB, grayscale, sometimes **PyTorch** only allows one type of image, and this will led you to a crazy trobleshooting with crazy errors (*Believe me hahah*). <br/>\nIt is **worth** the time to create this classes."},{"metadata":{"trusted":true,"_uuid":"48dbbea99d10ee7e1305ed9ae6c704c7521284bb"},"cell_type":"code","source":"class Rescale(object):\n    \"\"\"Rescale the image in a sample to a given size.\n\n    Args:\n        output_size (tuple or int): Desired output size. If tuple, output is\n            matched to output_size. If int, smaller of image edges is matched\n            to output_size keeping aspect ratio the same.\n    \"\"\"\n\n    def __init__(self, output_size):\n        assert isinstance(output_size, (int, tuple))\n        self.output_size = output_size\n\n    def __call__(self, sample):\n        image, label = sample['image'], sample['label']\n\n        h, w = image.shape[:2]\n        if isinstance(self.output_size, int):\n            if h > w:\n                new_h, new_w = self.output_size * h / w, self.output_size\n            else:\n                new_h, new_w = self.output_size, self.output_size * w / h\n        else:\n            new_h, new_w = self.output_size\n\n        new_h, new_w = int(new_h), int(new_w)\n\n        img = transform.resize(image, (new_h, new_w))\n\n        return {'image': img, 'label': label}\n\n\nclass RandomCrop(object):\n    \"\"\"Crop randomly the image in a sample.\n\n    Args:\n        output_size (tuple or int): Desired output size. If int, square crop\n            is made.\n    \"\"\"\n\n    def __init__(self, output_size):\n        assert isinstance(output_size, (int, tuple))\n        if isinstance(output_size, int):\n            self.output_size = (output_size, output_size)\n        else:\n            assert len(output_size) == 2\n            self.output_size = output_size\n\n    def __call__(self, sample):\n        image, label = sample['image'], sample['label']\n\n        h, w = image.shape[:2]\n        new_h, new_w = self.output_size\n\n        top = np.random.randint(0, h - new_h)\n        left = np.random.randint(0, w - new_w)\n\n        image = image[top: top + new_h,\n                      left: left + new_w]\n\n        return {'image': image, 'label': label}\n\n\nclass ToTensor(object):\n    \"\"\"Convert ndarrays in sample to Tensors.\"\"\"\n\n    def __call__(self, sample):\n        image, label = sample['image'], sample['label']\n\n        # swap color axis because\n        # numpy image: H x W x C\n        # torch image: C X H X W\n        \"\"\" The original code didn't expect gray scale images \"\"\"\n        gray_scale_image = torch.zeros([image_size,image_size]).shape == image.shape\n        if gray_scale_image:\n            image = np.stack((image,)*3, axis=-1)\n        image = image.transpose((2, 0, 1))\n        return {'image': torch.from_numpy(image),\n                'label': torch.tensor(label)}","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1762ba7e1a3379b09266ee74da843462f74f11fa"},"cell_type":"markdown","source":"### Transforming one Whale  <a class=\"anchor\" id=\"fifth-bullet\"></a>\n We can test this out with a random sample whales_ds[65] ( Not that **random** hah )  "},{"metadata":{"trusted":true,"_uuid":"25781c757f0b91bb498ec7c781358c28fdb955b9"},"cell_type":"code","source":"scale = Rescale(int(image_size*1.25))\ncrop = RandomCrop(image_size)\ncomposed = transforms.Compose([Rescale(int(image_size*1.25)),\n                               RandomCrop(image_size)])\n\n# Apply each of the above transforms on sample.\nfig = plt.figure()\nsample = whales_ds[65]\nfor i, tsfrm in enumerate([scale, crop, composed]):\n    transformed_sample = tsfrm(sample)\n\n    ax = plt.subplot(1, 3, i + 1)\n    ax.set_title(type(tsfrm).__name__)\n\n    plt.imshow(transformed_sample['image'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b69d733967a5c06f8fe234bab5d2f54ebcac1e9b"},"cell_type":"markdown","source":"### Creating our transformed dataset  <a class=\"anchor\" id=\"sixth-bullet\"></a>\nWith all of this created we can now instantiate our WhalesDS and pass our transform to the class and that's it!"},{"metadata":{"trusted":true,"_uuid":"320eaac0f0079c59077b1989128039a02f7fa61e"},"cell_type":"code","source":"transformed_dataset = WhalesDS(csv_file=train_path,\n                                           root_dir=humpback_whales_train_path,\n                                           transform=transforms.Compose([\n                                               Rescale(int(image_size*1.25)),\n                                               RandomCrop(image_size),\n                                               ToTensor()\n                                           ]))\n\nfor i in range(len(transformed_dataset)):\n    sample = transformed_dataset[i]\n\n    print(i, sample['image'].size(), sample['label'])\n\n    if i == 3:\n        break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"76a59ec53e923eaf928566227269b710ceac393a"},"cell_type":"markdown","source":"### Loading it up  <a class=\"anchor\" id=\"seventh-bullet\"></a>\nNow we can use the [DataLoader](https://pytorch.org/docs/stable/data.html) and iterate throughout our dataset! This is **IT** <br/>\nYou can now play around with any model"},{"metadata":{"trusted":true,"_uuid":"dda57d23fab08f0925b2c808d4c0c503bcfa3536"},"cell_type":"code","source":"dataloader = DataLoader(transformed_dataset, batch_size=4,\n                        shuffle=True, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e9ff5576e8ee708114e4b83377288540ec22c2c9"},"cell_type":"code","source":"# Helper function to show a batch\ndef show_whale_batch(sample_batched):\n    \"\"\"Show whales for a batch of samples.\"\"\"\n    images_batch, labels_batch = \\\n            sample_batched['image'], sample_batched['label']\n    batch_size = len(images_batch)\n    im_size = images_batch.size(2)\n\n    grid = utils.make_grid(images_batch)\n    plt.imshow(grid.numpy().transpose((1, 2, 0)))\n\n    for i in range(batch_size):\n        plt.title('Batch from dataloader')\n\nfor i_batch, sample_batched in enumerate(dataloader):\n    print(i_batch, sample_batched['image'].size(),\n          sample_batched['label'])\n    # observe 4th batch and stop.\n    if i_batch == 3:\n        plt.figure()\n        show_whale_batch(sample_batched)\n        plt.axis('off')\n        plt.ioff()\n        plt.show()\n        break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f7ab9ec7958b4ec008a527816b5e8f1f814d3874"},"cell_type":"markdown","source":"### Resources  <a class=\"anchor\" id=\"seventh-bullet\"></a>\nHere are some resources that I put together ( disclaimer here, this blog posts are from my site haha )\n\n### Building a very simple sequential model <a class=\"anchor\" id=\"seventh-bullet\"></a>\n\nThis is a great way to play around if you are a begginner in the area. If you don't know much from building Neural Networks I have a few resources \n\n1. [Creating a Perceptron](https://jhonatandasilva.com/build-your-own-perceptron/)\n2. [What are the building blocks of Deep Learning](https://jhonatandasilva.com/perceptrons/) \n3. [Play around with Neural Nets](https://jhonatandasilva.com/play-with-nn/)\n4. [Training your Neural Net](https://jhonatandasilva.com/training-your-neural-networks/)\n5. [When all comes together](https://jhonatandasilva.com/mnist-pytorch/) \n\nExploring more on the Vision side there's also\n\n1. [How Neural Nets sees the world ](https://jhonatandasilva.com/how-nn-sees-the-world/)\n\n<img src=\"https://jhonatandasilva.com/wp-content/uploads/2018/12/cnns.gif\" alt=\"drawing\" width=\"400\"/>\n\nYou can Look it up more resources on CNNs here\n\n* [CNNs made it easy](https://jhonatandasilva.com/cnns-made-it-easy/) \n* [How the layers of CNNs works](https://jhonatandasilva.com/cnns-layers/)\n"}],"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}