{"cells":[{"metadata":{},"cell_type":"markdown","source":"# This kernel is U-Net Baseline written by PyTorch\nIn this kernel, there are many places that are simplified now.  \nSo, you should fix these bad points.  \n\n[U-Net web site](https://lmb.informatik.uni-freiburg.de/people/ronneber/u-net/)  \n[U-Net paper](https://arxiv.org/abs/1505.04597)  \n\nI reference [this blog post](https://lp-tech.net/articles/hzfn7?page=2  ) in U-Net installation.  \nThank you awesome this blog post.  \n\nThis is [my EDA](https://www.kaggle.com/go1dfish/fgvc6-simple-eda).  \nIf you don't know this competition rule and data, this EDA might help you.  "},{"metadata":{},"cell_type":"markdown","source":"# Import modules"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nprint(os.listdir(\"../input\"))\nimport cv2\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom tqdm import tqdm_notebook as tqdm\n\nimport torch\nimport torch.nn as nn\nfrom torch import optim\nimport torchvision.transforms as transforms\nimport torch.nn.functional as F\nfrom torch.autograd import Function, Variable\nfrom pathlib import Path\nfrom itertools import groupby","execution_count":1,"outputs":[{"output_type":"stream","text":"['test', 'train', 'train.csv', 'sample_submission.csv', 'label_descriptions.json']\n","name":"stdout"}]},{"metadata":{"trusted":true},"cell_type":"code","source":"input_dir = \"../input/\"\ntrain_img_dir = \"../input/train/\"\ntest_img_dir = \"../input/test/\"\n\nWIDTH = 512\nHEIGHT = 512\ncategory_num = 46 + 1\n\nratio = 8\n\nepoch_num = 8\nbatch_size = 4\n\ndevice = \"cuda:0\"","execution_count":2,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(os.listdir(\"../input/train/\"))","execution_count":3,"outputs":[{"output_type":"execute_result","execution_count":3,"data":{"text/plain":"45625"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(os.listdir(\"../input/test/\"))","execution_count":4,"outputs":[{"output_type":"execute_result","execution_count":4,"data":{"text/plain":"3200"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(input_dir + \"train.csv\")\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.shape","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true},"cell_type":"markdown","source":"# Define utils\nFor simplicity, It focus only category"},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_onehot_vec(x):\n    vec = np.zeros(category_num)\n    vec[x] = 1\n    return vec","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_mask_img(segment_df):\n    seg_width = segment_df.at[0, \"Width\"]\n    seg_height = segment_df.at[0, \"Height\"]\n    seg_img = np.full(seg_width*seg_height, category_num-1, dtype=np.int32)\n    for encoded_pixels, class_id in zip(segment_df[\"EncodedPixels\"].values, segment_df[\"ClassId\"].values):\n        pixel_list = list(map(int, encoded_pixels.split(\" \")))\n        for i in range(0, len(pixel_list), 2):\n            start_index = pixel_list[i] - 1\n            index_len = pixel_list[i+1] - 1\n            seg_img[start_index:start_index+index_len] = int(class_id.split(\"_\")[0])\n    seg_img = seg_img.reshape((seg_height, seg_width), order='F')\n    seg_img = cv2.resize(seg_img, (WIDTH, HEIGHT), interpolation=cv2.INTER_NEAREST)\n    \"\"\"\n    seg_img_onehot = np.zeros((HEIGHT, WIDTH, category_num), dtype=np.int32)\n    #seg_img_onehot = np.zeros((seg_height//ratio, seg_width//ratio, category_num), dtype=np.int32)\n    # OPTIMIZE: slow\n    for ind in range(HEIGHT):\n        for col in range(WIDTH):\n            seg_img_onehot[ind, col] = make_onehot_vec(seg_img[ind, col])\n    \"\"\"\n    return seg_img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_generator(df, batch_size):\n    img_ind_num = df.groupby(\"ImageId\")[\"ClassId\"].count()\n    index = df.index.values[0]\n    trn_images = []\n    seg_images = []\n    for i, (img_name, ind_num) in enumerate(img_ind_num.items()):\n        img = cv2.imread(train_img_dir + img_name)\n        img = cv2.resize(img, (WIDTH, HEIGHT), interpolation=cv2.INTER_AREA)\n        segment_df = (df.loc[index:index+ind_num-1, :]).reset_index(drop=True)\n        index += ind_num\n        if segment_df[\"ImageId\"].nunique() != 1:\n            raise Exception(\"Index Range Error\")\n        seg_img = make_mask_img(segment_df)\n        \n        # HWC -> CHW\n        img = img.transpose((2, 0, 1))\n        #seg_img = seg_img.transpose((2, 0, 1))\n        \n        trn_images.append(img)\n        seg_images.append(seg_img)\n        if((i+1) % batch_size == 0):\n            yield np.array(trn_images, dtype=np.float32) / 255, np.array(seg_images, dtype=np.int32)\n            trn_images = []\n            seg_images = []\n    if(len(trn_images) != 0):\n        yield np.array(trn_images, dtype=np.float32) / 255, np.array(seg_images, dtype=np.int32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_generator(df):\n    img_names = df[\"ImageId\"].values\n    for img_name in img_names:\n        img = cv2.imread(test_img_dir + img_name)\n        img = cv2.resize(img, (WIDTH, HEIGHT), interpolation=cv2.INTER_AREA)\n        # HWC -> CHW\n        img = img.transpose((2, 0, 1))\n        yield img_name, np.asarray([img], dtype=np.float32) / 255","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def encode(input_string):\n    return [(len(list(g)), k) for k,g in groupby(input_string)]\n\ndef run_length(label_vec):\n    encode_list = encode(label_vec)\n    index = 1\n    class_dict = {}\n    for i in encode_list:\n        if i[1] != category_num-1:\n            if i[1] not in class_dict.keys():\n                class_dict[i[1]] = []\n            class_dict[i[1]] = class_dict[i[1]] + [index, i[0]]\n        index += i[0]\n    return class_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Network"},{"metadata":{"trusted":true},"cell_type":"code","source":"class double_conv(nn.Module):\n    '''(conv => BN => ReLU) * 2'''\n    def __init__(self, in_ch, out_ch):\n        super(double_conv, self).__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, 3, padding=1),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_ch, out_ch, 3, padding=1),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        x = self.conv(x)\n        return x\n\n\nclass inconv(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(inconv, self).__init__()\n        self.conv = double_conv(in_ch, out_ch)\n\n    def forward(self, x):\n        x = self.conv(x)\n        return x\n\n\nclass down(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(down, self).__init__()\n        self.mpconv = nn.Sequential(\n            nn.MaxPool2d(2),\n            double_conv(in_ch, out_ch)\n        )\n\n    def forward(self, x):\n        x = self.mpconv(x)\n        return x\n\n\nclass up(nn.Module):\n    def __init__(self, in_ch, out_ch, bilinear=True):\n        super(up, self).__init__()\n\n        #  would be a nice idea if the upsampling could be learned too,\n        #  but my machine do not have enough memory to handle all those weights\n        if bilinear:\n            self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)\n        else:\n            self.up = nn.ConvTranspose2d(in_ch//2, in_ch//2, 2, stride=2)\n\n        self.conv = double_conv(in_ch, out_ch)\n\n    def forward(self, x1, x2):\n        x1 = self.up(x1)\n        diffX = x1.size()[2] - x2.size()[2]\n        diffY = x1.size()[3] - x2.size()[3]\n        x2 = F.pad(x2, (diffX // 2, int(diffX / 2),\n                        diffY // 2, int(diffY / 2)))\n        x = torch.cat([x2, x1], dim=1)\n        x = self.conv(x)\n        return x\n\n\nclass outconv(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(outconv, self).__init__()\n        self.conv = nn.Conv2d(in_ch, out_ch, 1)\n\n    def forward(self, x):\n        x = self.conv(x)\n        return x\n\n    \nclass UNet(nn.Module):\n    def __init__(self, n_channels, n_classes):\n        super(UNet, self).__init__()\n        self.inc = inconv(n_channels, 64)\n        self.down1 = down(64, 128)\n        self.down2 = down(128, 256)\n        self.down3 = down(256, 512)\n        self.down4 = down(512, 512)\n        self.up1 = up(1024, 256)\n        self.up2 = up(512, 128)\n        self.up3 = up(256, 64)\n        self.up4 = up(128, 64)\n        self.outc = outconv(64, n_classes)\n\n    def forward(self, x):\n        x1 = self.inc(x)\n        x2 = self.down1(x1)\n        x3 = self.down2(x2)\n        x4 = self.down3(x3)\n        x5 = self.down4(x4)\n        x = self.up1(x5, x4)\n        x = self.up2(x, x3)\n        x = self.up3(x, x2)\n        x = self.up4(x, x1)\n        x = self.outc(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"333415 // 4","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.iloc[83348:83354, :]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.iloc[73350:73354, :]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For simplicity, use about 25% data.  "},{"metadata":{"trusted":true},"cell_type":"code","source":"net = UNet(n_channels=3, n_classes=category_num).to(device)\n\noptimizer = optim.SGD(\n    net.parameters(),\n    lr=0.1,\n    momentum=0.9,\n    weight_decay=0.0005\n)\n\ncriterion = nn.CrossEntropyLoss()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_sta = 73352\nval_end = 83351\ntrain_loss = []\nvalid_loss = []\nfor epoch in range(epoch_num):\n    epoch_trn_loss = 0\n    train_len = 0\n    net.train()\n    for iteration, (X_trn, Y_trn) in enumerate(tqdm(train_generator(train_df.iloc[:val_sta, :], batch_size))):\n        X = torch.tensor(X_trn, dtype=torch.float32).to(device)\n        Y = torch.tensor(Y_trn, dtype=torch.long).to(device)\n        train_len += len(X)\n        \n        #Y_flat = Y.view(-1)\n        mask_pred = net(X)\n        #mask_prob = torch.softmax(mask_pred, dim=1)\n        #mask_prob_flat = mask_prob.view(-1)\n        loss = criterion(mask_pred, Y)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        epoch_trn_loss += loss.item()\n        \n        if iteration % 100 == 0:\n            print(\"train loss in {:0>2}epoch  /{:>5}iter:    {:<10.8}\".format(epoch+1, iteration, epoch_trn_loss/(iteration+1)))\n        \n    train_loss.append(epoch_trn_loss/(iteration+1))\n    print(\"train {}epoch loss({}iteration):    {:10.8}\".format(epoch+1, iteration, train_loss[-1]))\n    \n    epoch_val_loss = 0\n    val_len = 0\n    net.eval()\n    for iteration, (X_val, Y_val) in enumerate(tqdm(train_generator(train_df.iloc[val_sta:val_end, :], batch_size))):\n        X = torch.tensor(X_val, dtype=torch.float32).to(device)\n        Y = torch.tensor(Y_val, dtype=torch.long).to(device)\n        val_len += len(X)\n        \n        #Y_flat = Y.view(-1)\n        \n        mask_pred = net(X)\n        #mask_prob = torch.softmax(mask_pred, dim=1)\n        #mask_prob_flat = mask_prob.view(-1)\n        loss = criterion(mask_pred, Y)\n        epoch_val_loss += loss.item()\n        \n        if iteration % 100 == 0:\n            print(\"valid loss in {:0>2}epoch  /{:>5}iter:    {:<10.8}\".format(epoch+1, iteration, epoch_val_loss/(iteration+1)))\n        \n    valid_loss.append(epoch_val_loss/(iteration+1))\n    print(\"valid {}epoch loss({}iteration):    {:10.8}\".format(epoch+1, iteration, valid_loss[-1]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#plt.plot(list(range(epoch_num)), train_loss, color='green')\n#plt.plot(list(range(epoch_num)), valid_loss, color='blue')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Test"},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_df = pd.read_csv(input_dir + \"sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"import torch\nimport gc\nfor obj in gc.get_objects():\n    try:\n        if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):\n            print(type(obj), obj.size())\n    except:\n        pass","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_list = []\nnet.eval()\nfor img_name, img in test_generator(sample_df):\n    X = torch.tensor(img, dtype=torch.float32).to(device)\n    mask_pred = net(X)\n    mask_pred = mask_pred.cpu().detach().numpy()\n    mask_prob = np.argmax(mask_pred, axis=1)\n    mask_prob = mask_prob.ravel(order='F')\n    class_dict = run_length(mask_prob)\n    if len(class_dict) == 0:\n        sub_list.append([img_name, \"1 1\", 1])\n    else:\n        for key, val in class_dict.items():\n            sub_list.append([img_name, \" \".join(map(str, val)), key])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Make Submission File"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df = pd.DataFrame(sub_list, columns=sample_df.columns.values)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Thank you for watching!\nPlease tell me when I make mistakes in program and English.  \nI hope this kernel will help.  \nIf you think this kernel is useful, please upvote. If you do, I feel happy and get enough sleep.  "},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.4"}},"nbformat":4,"nbformat_minor":1}