{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"scrolled":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom keras.layers import *\nfrom keras.models import *\nfrom keras.callbacks import *\nfrom sklearn.model_selection import train_test_split\nfrom PIL import Image\nfrom skimage.morphology import binary_opening, disk, label\nimport os\nimport matplotlib.pyplot as plt\nimport sys\nimport gc\nimport time\nfrom keras import backend as K\nimport tensorflow as tf\nprint(os.listdir(\"../input\"))\n\nprint('start!!')\n\nparam={\n    #model training relevent\n    'samplesize':100,# use how many training samples to train\n    'validatesize':2,#how many samples to use for validation \n    'bufferSize':200,# load how many training images from disk to memory at a time\n    'batchSize':20,# train_on_batch batch size\n    'epoch':1,#how many epochs to train\n    \n    #submission relevent\n    'test':True,#if true ,only predict and submit a number of test images specified by 'testSize'\n    'testSize':10,#number of test images for prediction and submission\n    'subBatchSize':200#predict and submit a batch of test samples at a time(limited memory)\n}\n","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"def rle_decode(mask_rle, shape=(768, 768)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T  # Needed to align to RLE direction","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a9372dfb03d7202428090094451b78329e092c06"},"cell_type":"code","source":"def multi_rle_encode(img, **kwargs):\n    '''\n    Encode connected regions as separated masks\n    '''\n    labels = label(img)\n    if img.ndim > 2:\n        return [rle_encode(np.sum(labels==k, axis=2), **kwargs) for k in np.unique(labels[labels>0])]\n    else:\n        return [rle_encode(labels==k, **kwargs) for k in np.unique(labels[labels>0])]\n    \n    \n# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_encode(img, min_max_threshold=1e-3, max_mean_threshold=None):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    if np.max(img) < min_max_threshold:\n        return '' ## no need to encode if it's all zeros\n    if max_mean_threshold and np.mean(img) > max_mean_threshold:\n        return '' ## ignore overfilled mask\n    pixels = img.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ba352a6ca53a7dfab20d5f99853a45dd7429754"},"cell_type":"code","source":"def imageToArray(filepath):\n    arr=np.array(Image.open(filepath),dtype=np.uint8,copy=False)\n    return arr\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b6d91a3943d6337670fa593e639e22c55578bd86"},"cell_type":"code","source":"os.chdir(r'../input/')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5dd697ec4af176b88611e79dc64a551b8d5caabe","scrolled":false},"cell_type":"code","source":"mask_train=pd.read_csv('train_ship_segmentations.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"66d9c6222c7233cf58f9120a85bb4d2b4bcc79ca"},"cell_type":"code","source":"ship=mask_train.EncodedPixels.apply(lambda x:isinstance(x,str)+0)\ntmp=mask_train.drop('EncodedPixels',axis=1)\ntmp['ship']=ship","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1bf753de14d17e5c79c8469c49791e4b0aa996e3"},"cell_type":"code","source":"unique_id=tmp.groupby(by='ImageId').agg(sum)\n(unique_id.ship>0).sum()\n(unique_id.ship==0).sum()\n\ndownsize_unique=unique_id.query('ship!=0').sample(param['samplesize'])\n\n# 1% validate sample\nid_train,id_validate=train_test_split(downsize_unique.index.values,test_size=param['validatesize'])\n\nmask_train=mask_train.set_index('ImageId')\n\ndownsize_mask_train=mask_train.loc[id_train]\n\ndownsize_mask_validate=mask_train.loc[id_validate]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"df1df33cd193764cec64bded7dd4c9294be186fb"},"cell_type":"code","source":" # helper class to retrieve train image and train masks one batch at a time\n # we can use the getNextBatch function to retrieve train data in batches and feed them to keras train_on_batch function\nclass BatchWrapper:\n    bufferIx = 0\n    innerBufferIx = 0\n    image_train = []  # buffer\n    mask_train = []  # buffer\n\n    def __init__(self, masks, batchSize=param['batchSize'], bufferSize=param['bufferSize']):\n        self.masks = masks\n        self.batchSize = batchSize\n        self.bufferSize = bufferSize\n\n    def hasNext(self):\n        return self.bufferIx <= (len(self.masks) - 1) or self.innerBufferIx <= (len(self.image_train) - 1)\n\n    def getNextBatch(self):\n        if self.innerBufferIx >= len(self.image_train):\n            self.getNextBuffer()\n            self.innerBufferIx = 0\n        aa = self.image_train[self.innerBufferIx:self.innerBufferIx + self.batchSize]\n        bb = self.mask_train[self.innerBufferIx:self.innerBufferIx + self.batchSize]\n        self.innerBufferIx += self.batchSize\n        return (aa, bb)\n\n    def getNextBuffer(self):\n        if self.bufferIx >= len(self.masks):\n            self.bufferIx = 0\n        tmp = self.masks.iloc[self.bufferIx:self.bufferIx + self.bufferSize]\n        self.getImage(tmp)\n        self.bufferIx += self.bufferSize\n\n    def getImage(self, batch_masks):\n        self.image_train = []\n        self.mask_train = []\n        for ix, id in enumerate(batch_masks.index):\n            self.image_train.append(imageToArray(os.path.join(os.curdir, 'train', id)))\n            if isinstance(self.masks.EncodedPixels.loc[id], str):\n                self.mask_train.append(rle_decode(self.masks.EncodedPixels.loc[id]).reshape(768, 768, 1))\n            else:\n                self.mask_train.append(np.zeros((768, 768, 1), dtype=np.uint8))\n        self.image_train = np.array(self.image_train, dtype=np.float32, copy=False) / 255\n        self.mask_train = np.array(self.mask_train)\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eda815ea9b426a5f3406f08ceb7a8bc77af905d6"},"cell_type":"code","source":"train_wrapper=BatchWrapper(masks=downsize_mask_train)\nvalidate_wrapper=BatchWrapper(masks=downsize_mask_validate)\nimage_validate,mask_validate=validate_wrapper.getNextBatch()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f3a693d4f4752674e7b2cf0a8fedb16c0bf5fa9d"},"cell_type":"code","source":"def ioumetric(y_true,y_pred):\n    intersection = K.sum(y_true * y_pred)\n    sum_ = K.sum(y_true + y_pred)\n    jac = intersection / (sum_ - intersection)\n    return jac\n\ndef ioumetric2(y_true,y_pred):\n    sum=0\n    for g,p in zip(y_true,y_pred):\n        intersection = np.sum(y_true * y_pred)\n        sum_ = np.sum(y_true + y_pred)\n        jac = intersection / (sum_ - intersection)\n        sum+=jac\n    return sum/len(y_true)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9754f185d87592a53e0c5c7116f726c5739d797"},"cell_type":"code","source":"def iouloss(y_true,y_pred):\n    intersection = K.sum(y_true * y_pred, axis=-1)\n    sum_ = K.sum(y_true + y_pred, axis=-1)\n    jac = intersection / (sum_ - intersection)\n    return 1 - jac","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8f5baa59532151f02afa6152716f4706ac9e11d8"},"cell_type":"code","source":"def focal_binarycrossentropy(y_true,y_pred):\n    t1=K.binary_crossentropy(y_true, y_pred)\n    t2=tf.where(tf.equal(y_true,0),t1*(y_pred**8),t1*((1-y_pred)**8))\n    return t2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"afd8ed1b1fbdddc97cd2bca2039d2fdc676fcac6"},"cell_type":"code","source":"def biased_crossentropy(y_true,y_pred):\n    t1=K.binary_crossentropy(y_true, y_pred)\n    t2=tf.where(tf.equal(y_true,0),t1*1000,t1)\n    return t2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5ffd43c165bbc3c8dc6f6a3afcddeb70f6492b5f"},"cell_type":"code","source":"visual_test_img=np.array([imageToArray(os.path.join(os.curdir,'test','191e1ae93.jpg'))])/255","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8fbfb1d886a21827401cf4293d20dd63168a0262","scrolled":true},"cell_type":"code","source":"input_image=Input(shape=(768,768,3))\nc1=Conv2D(filters=8,kernel_size=(3,3),padding='same',activation='relu')(input_image)\nc2=Conv2D(filters=8,kernel_size=(3,3),padding='same',activation='relu')(c1)\nc3=MaxPooling2D(pool_size=(2, 2))(c2)\nc21=SpatialDropout2D(rate=0.25)(c3)\nc22=Conv2D(filters=16,kernel_size=(3,3),padding='same',activation='relu')(c21)\nc23=Conv2D(filters=16,kernel_size=(3,3),padding='same',activation='relu')(c22)\nc24=MaxPooling2D(pool_size=(2, 2))(c23)\nc60=SpatialDropout2D(rate=0.25)(c24)\nc61=Conv2D(filters=32,kernel_size=(3,3),padding='same',activation='relu')(c60)\nc62=Conv2D(filters=32,kernel_size=(3,3),padding='same',activation='relu')(c61)\nc63=MaxPooling2D(pool_size=(2, 2))(c62)\nc81=SpatialDropout2D(rate=0.25)(c63)\nc82=Conv2D(filters=64,kernel_size=(3,3),padding='same',activation='relu')(c81)\nc83=UpSampling2D(size=(2,2))(c82)\n\nc100=Concatenate(axis=3)([c83,c62])\nc101=SpatialDropout2D(rate=0.25)(c100)\nc102=Conv2D(filters=32,kernel_size=(3,3),padding='same',activation='relu')(c101)\nc104=Conv2D(filters=32,kernel_size=(3,3),padding='same',activation='relu')(c102)\nc105=UpSampling2D(size=(2,2))(c104)\n\nc121=Concatenate(axis=3)([c105,c23])\nc122=SpatialDropout2D(rate=0.25)(c121)\nc123=Conv2D(filters=16,kernel_size=(3,3),padding='same',activation='relu')(c122)\nc124=Conv2D(filters=16,kernel_size=(3,3),padding='same',activation='relu')(c123)\nc125=UpSampling2D(size=(2,2))(c124)\n\nc141=Concatenate(axis=3)([c125,c2])\nc142=SpatialDropout2D(rate=0.25)(c141)\nc143=Conv2D(filters=8,kernel_size=(3,3),padding='same',activation='relu')(c142)\nc144=Conv2D(filters=8,kernel_size=(3,3),padding='same',activation='relu')(c143)\nc145=Conv2D(filters=1,kernel_size=(3,3),padding='same',activation='sigmoid')(c144)\n\nunet=Model(inputs=input_image,outputs=c145)\nunet.compile(loss=focal_binarycrossentropy, optimizer=\"adam\", metrics=[ioumetric])\nunet.summary()\nloss_track=[]\nmin_loss=100\nfor ite in range(param['epoch']):\n    print('');print('epoch:'+str(ite+1))\n    loss_epoch=[]\n    while train_wrapper.hasNext():\n        image_batch,mask_batch=train_wrapper.getNextBatch()\n        loss=unet.train_on_batch(x=image_batch,y=mask_batch)#insufficient memory\n        loss_epoch.append(loss[0])\n        predict_mask_validate=unet.predict(x=image_validate)\n        ioumetric_validate=ioumetric2(mask_validate,predict_mask_validate)\n        print(\"loss_train: %s iou_train: %s iou_validate: %s\"%(loss[0],loss[1],ioumetric_validate))\n        visual_test_mask=unet.predict(x=visual_test_img)\n        #print(visual_test_mask.sum())\n        fig,ax=plt.subplots(1,2)\n        ax[0].imshow(visual_test_mask[0].squeeze())\n        ax[0].set_title('probability image')\n        ax[1].imshow(np.round(visual_test_mask[0].squeeze()))\n        ax[1].set_title('mask image')\n        plt.show()\n        del image_batch,mask_batch\n        gc.collect()\n    loss_track.append(loss_epoch)\n    if loss_epoch[-1]<min_loss:#ModelCheckpoint\n        unet.save(filepath='../working/model.h5')\n        min_loss=loss_epoch[-1]\n    if len(loss_track)>1 and loss_epoch[-1]>=loss_track[-2][-1]:#EarlyStopping\n        break\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4d2c4577e7696140c634394297b0eba34db7b965"},"cell_type":"code","source":"sub_id=pd.read_csv('sample_submission.csv').ImageId\nif(param['test']):\n    sub_id=sub_id.sample(param['testSize'])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"780e50ff78931f9df858e2e6bd992b55c9da1711","scrolled":false},"cell_type":"code","source":"print('predicting!!')\nsubmission=pd.DataFrame(columns=['ImageId','EncodedPixels'])\nsubmission.to_csv('../working/mysubmission.csv',index=False,index_label=False)\nsub_ix=0\nwhile(sub_ix<len(sub_id)):\n    gc.collect()\n    aa=sub_id.iloc[sub_ix:sub_ix+param['subBatchSize']]\n    image_test=[]\n    for id in aa:\n        image_test.append(imageToArray(os.path.join(os.curdir,'test',id)))\n    image_test=np.array(image_test,dtype=np.float32,copy=False)/255\n    mask_test=unet.predict(x=image_test)\n    print(\"mask pixels predict: %s\"%((mask_test>0.5).sum()),end=' ')\n    \n    col1=[]\n    col2=[]\n    for ix,img in enumerate((mask_test>0.5).astype(np.uint8)):\n        enc=multi_rle_encode(img)\n        if len(enc)==0:\n            enc=['']\n        for rle_str in enc:\n            col1.append(aa.iloc[ix])\n            col2.append(rle_str)\n    \n    tp=pd.DataFrame({'ImageId':col1,'EncodedPixels':col2})\n    sub=pd.read_csv(r'../working/mysubmission.csv')\n    sub=pd.concat([sub,tp],axis=0)\n    #print(len(sub.query('EncodedPixels==EncodedPixels')))\n    sub.to_csv('../working/mysubmission.csv',index=False,index_label=False)\n    sub_ix+=param['subBatchSize']\n    del image_test,mask_test\n    \nprint('done')\n    ","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}