{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Carvana Image Masking Challenge"},{"metadata":{},"cell_type":"markdown","source":"https://www.kaggle.com/c/carvana-image-masking-challenge"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_ROWS = 480\nIMG_COLS = 320\n\nTEST_IMG_ROWS = 1918\nTEST_IMG_COLS = 1280","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Загружаем исходные изображения"},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2\nimport numpy as np\nfrom scipy import ndimage\nfrom glob import glob\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\nSAMPLE = 1500\n\ntrain_img_paths = sorted(glob('../input/train/*.jpg'))[:SAMPLE]\ntrain_mask_paths = sorted(glob('../input/train_masks/*.gif'))[:SAMPLE]\n\ntrain_imgs = np.array([cv2.resize(plt.imread(path), (IMG_ROWS, IMG_COLS)) for path in train_img_paths])\n\ntrain_masks = np.array([cv2.resize(plt.imread(path), (IMG_ROWS, IMG_COLS)) for path in train_mask_paths], dtype=\"float32\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_masks_2 = []\nfor num, i in enumerate(train_masks):\n    train_masks_2.append(cv2.cvtColor(i, cv2.COLOR_BGR2GRAY))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_masks = np.array(train_masks_2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.imshow(train_masks[1], cmap='gray')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_masks[train_masks<=127] = 0.\ntrain_masks[train_masks>127] = 1.\ntrain_masks = np.reshape(train_masks, (*train_masks.shape, 1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\nfrom matplotlib import pyplot as plt\nfig = plt.figure(0, figsize=(20, 20))\nfig.add_subplot(1, 2, 1)\nplt.imshow(train_imgs[0])\nfig.add_subplot(1, 2, 2)\nplt.imshow(np.squeeze(train_masks[0]), cmap='gray')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Инициализируем архитектуру U-Net"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.layers import Input\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import Conv2DTranspose\nfrom keras.layers import BatchNormalization\nfrom keras.layers import concatenate\nfrom keras.models import Model\n\ninputs = Input((IMG_COLS, IMG_ROWS, 3))\nbnorm1 = BatchNormalization()(inputs)\nconv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(bnorm1)\nconv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)\npool1 = MaxPooling2D(pool_size=(2, 2))(conv1)\n\nconv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)\nconv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)\npool2 = MaxPooling2D(pool_size=(2, 2))(conv2)\n\nconv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)\nconv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)\npool3 = MaxPooling2D(pool_size=(2, 2))(conv3)\n\nconv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)\nconv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)\npool4 = MaxPooling2D(pool_size=(2, 2))(conv4)\n\nconv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4)\nconv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5)\n\nup6 = concatenate([Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5), conv4], axis=3)\nconv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6)\nconv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6)\n\nup7 = concatenate([Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6), conv3], axis=3)\nconv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7)\nconv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7)\n\nup8 = concatenate([Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7), conv2], axis=3)\nconv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8)\nconv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8)\n\nup9 = concatenate([Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(conv8), conv1], axis=3)\nconv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9)\nconv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9)\n\nconv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9)\n\nmodel = Model(inputs=[inputs], outputs=[conv10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Задаем функцию потерь"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras import backend as K\nfrom keras.losses import binary_crossentropy\n\nSMOOTH = 1.\n\ndef dice_coef(y_true, y_pred):\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = K.sum(y_true_f * y_pred_f)\n    return (2. * intersection + SMOOTH) / (K.sum(y_true_f) + K.sum(y_pred_f) + SMOOTH)\n\ndef bce_dice_loss(y_true, y_pred):\n    return 0.5 * binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Запускаем процесс обучения"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.optimizers import Adam\nmodel.compile(Adam(lr=1e-4),\n              bce_dice_loss,\n              metrics=[binary_crossentropy, dice_coef])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":true},"cell_type":"code","source":"model.fit(train_imgs[50:], train_masks[50:],\n          batch_size=12, epochs=20, \n          validation_data=(train_imgs[:50], train_masks[:50]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Предсказание модели"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_paths = sorted(glob('../input/test/*.jpg'))\n\ndef test_img_generator(test_paths):\n    while True:\n        for path in test_paths:\n            yield np.array([cv2.resize(plt.imread(path), (IMG_ROWS, IMG_COLS))])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred = model.predict_generator(test_img_generator(test_paths[:10]), len(test_paths[:10]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Визуализируем результат"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(0, figsize=(20, 10))\nk = 5\nfig.add_subplot(2, 2, 1)\nplt.imshow(plt.imread(test_paths[k]))\nfig.add_subplot(2, 2, 2)\nplt.imshow(np.squeeze(cv2.resize(pred[k], (TEST_IMG_ROWS, TEST_IMG_COLS))), cmap='gray')\nfig.add_subplot(2, 2, 3)\nplt.imshow(plt.imread(test_paths[k+1]))\nfig.add_subplot(2, 2, 4)\nplt.imshow(np.squeeze(cv2.resize(pred[k+1], (TEST_IMG_ROWS, TEST_IMG_COLS))), cmap='gray')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Подготавливаем данные для отправки"},{"metadata":{"trusted":true},"cell_type":"code","source":"def rle_encode(mask):\n    pixels = mask.flatten()\n    pixels[0] = 0\n    pixels[-1] = 0\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    runs[1::2] = runs[1::2] - runs[:-1:2]\n    return runs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('submit.csv', 'w') as dst:\n    dst.write('img,rle_mask\\n')\n    for path in test_paths:\n        img = np.array([cv2.resize(ndimage.imread(path), (IMG_ROWS, IMG_COLS))])\n        pred_mask = model.predict(img)[0]\n        bin_mask = 255. * cv2.resize(pred_mask, (TEST_IMG_ROWS, TEST_IMG_COLS))\n        bin_mask[bin_mask<=127] = 0\n        bin_mask[bin_mask>127] = 1\n        rle = rle_encode(bin_mask.astype(np.uint8))\n        rle = ' '.join(str(x) for x in rle)\n        dst.write('%s,%s\\n' % (path.split('/')[-1], rle))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 20 epochs\n# loss: -0.9891 - binary_crossentropy: 0.0077 - dice_coef: 0.9930\n# val_loss: -0.9889 - val_binary_crossentropy: 0.0085 - val_dice_coef: 0.9932\n# kaggle: 0.9926","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.7.3"},"widgets":{"state":{},"version":"1.1.2"}},"nbformat":4,"nbformat_minor":1}