File size: 36,588 Bytes
c0f21d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n",
      "C:\\Users\\Admin\\Anaconda3\\lib\\site-packages\\dicom\\__init__.py:53: UserWarning: \n",
      "This code is using an older version of pydicom, which is no longer \n",
      "maintained as of Jan 2017.  You can access the new pydicom features and API \n",
      "by installing `pydicom` from PyPI.\n",
      "See 'Transitioning to pydicom 1.x' section at pydicom.readthedocs.org \n",
      "for more information.\n",
      "\n",
      "  warnings.warn(msg)\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from skimage.transform import resize\n",
    "from skimage.io import imsave\n",
    "import numpy as np\n",
    "from skimage.segmentation import mark_boundaries\n",
    "from keras.models import Model\n",
    "from keras.layers import Input, concatenate, Conv2D, MaxPooling2D, Conv2DTranspose\n",
    "from keras.optimizers import Adam, SGD\n",
    "from keras.callbacks import ModelCheckpoint\n",
    "from keras import backend as K\n",
    "from skimage.exposure import rescale_intensity\n",
    "from keras.callbacks import History\n",
    "from skimage import io\n",
    "from data import load_train_data, load_test_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "K.set_image_data_format('channels_last')  # TF dimension ordering in this code\n",
    "\n",
    "img_rows = int(512/2)\n",
    "img_cols = int(512/2)\n",
    "smooth = 1.\n",
    "#We divide here the number of rows and columns by two because we undersample our data (We take one pixel over two) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def 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",
    "\n",
    "\n",
    "def dice_coef_loss(y_true, y_pred):\n",
    "    return -dice_coef(y_true, y_pred)\n",
    "\n",
    "#The functions return our metric and loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_unet():\n",
    "    inputs = Input((img_rows, img_cols, 1))\n",
    "    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)\n",
    "    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)\n",
    "    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)\n",
    "\n",
    "    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)\n",
    "    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)\n",
    "    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)\n",
    "\n",
    "    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)\n",
    "    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)\n",
    "    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)\n",
    "\n",
    "    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)\n",
    "    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)\n",
    "    pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)\n",
    "\n",
    "    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4)\n",
    "    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5)\n",
    "\n",
    "    up6 = concatenate([Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5), conv4], axis=3)\n",
    "    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6)\n",
    "    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6)\n",
    "\n",
    "    up7 = concatenate([Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6), conv3], axis=3)\n",
    "    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7)\n",
    "    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7)\n",
    "\n",
    "    up8 = concatenate([Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7), conv2], axis=3)\n",
    "    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8)\n",
    "    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8)\n",
    "\n",
    "    up9 = concatenate([Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(conv8), conv1], axis=3)\n",
    "    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9)\n",
    "    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9)\n",
    "\n",
    "    conv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9)\n",
    "\n",
    "    model = Model(inputs=[inputs], outputs=[conv10])\n",
    "\n",
    "    model.compile(optimizer=Adam(lr=1e-3), loss=dice_coef_loss, metrics=[dice_coef])\n",
    "\n",
    "    return model\n",
    "\n",
    "#The different layers in our neural network model (including convolutions, maxpooling and upsampling)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess(imgs):\n",
    "    imgs_p = np.ndarray((imgs.shape[0], img_rows, img_cols), dtype=np.uint8)\n",
    "    for i in range(imgs.shape[0]):\n",
    "        imgs_p[i] = resize(imgs[i], (img_cols, img_rows), preserve_range=True)\n",
    "\n",
    "    imgs_p = imgs_p[..., np.newaxis]\n",
    "    return imgs_p\n",
    "\n",
    "#We adapt here our dataset samples dimension so that we can feed it to our network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_and_predict():\n",
    "    print('-'*30)\n",
    "    print('Loading and preprocessing train data...')\n",
    "    print('-'*30)\n",
    "    imgs_train, imgs_mask_train = load_train_data()\n",
    "\n",
    "    imgs_train = preprocess(imgs_train)\n",
    "    imgs_mask_train = preprocess(imgs_mask_train)\n",
    "\n",
    "    imgs_train = imgs_train.astype('float32')\n",
    "    mean = np.mean(imgs_train)  # mean for data centering\n",
    "    std = np.std(imgs_train)  # std for data normalization\n",
    "\n",
    "    imgs_train -= mean\n",
    "    imgs_train /= std\n",
    "    #Normalization of the train set\n",
    "\n",
    "    imgs_mask_train = imgs_mask_train.astype('float32')\n",
    "\n",
    "    print('-'*30)\n",
    "    print('Creating and compiling model...')\n",
    "    print('-'*30)\n",
    "    model = get_unet()\n",
    "    model_checkpoint = ModelCheckpoint('weights.h5', monitor='val_loss', save_best_only=True)\n",
    "    #Saving the weights and the loss of the best predictions we obtained\n",
    "\n",
    "    print('-'*30)\n",
    "    print('Fitting model...')\n",
    "    print('-'*30)\n",
    "    history=model.fit(imgs_train, imgs_mask_train, batch_size=10, epochs=20, verbose=1, shuffle=True,\n",
    "              validation_split=0.2,\n",
    "              callbacks=[model_checkpoint])\n",
    "\n",
    "    print('-'*30)\n",
    "    print('Loading and preprocessing test data...')\n",
    "    print('-'*30)\n",
    "    imgs_test, imgs_id_test = load_test_data()\n",
    "    imgs_test = preprocess(imgs_test)\n",
    "\n",
    "    imgs_test = imgs_test.astype('float32')\n",
    "    imgs_test -= mean\n",
    "    imgs_test /= std\n",
    "    #Normalization of the test set\n",
    "\n",
    "    print('-'*30)\n",
    "    print('Loading saved weights...')\n",
    "    print('-'*30)\n",
    "    model.load_weights('weights.h5')\n",
    "\n",
    "    print('-'*30)\n",
    "    print('Predicting masks on test data...')\n",
    "    print('-'*30)\n",
    "    imgs_mask_test = model.predict(imgs_test, verbose=1)\n",
    "    np.save('imgs_mask_test.npy', imgs_mask_test)\n",
    "    print('-' * 30)\n",
    "    print('Saving predicted masks to files...')\n",
    "    print('-' * 30)\n",
    "    pred_dir = 'preds'\n",
    "    if not os.path.exists(pred_dir):\n",
    "        os.mkdir(pred_dir)\n",
    "\n",
    "    for k in range(len(imgs_mask_test)):\n",
    "        a=rescale_intensity(imgs_test[k][:,:,0],out_range=(-1,1))\n",
    "        b=(imgs_mask_test[k][:,:,0]).astype('uint8')\n",
    "        io.imsave(os.path.join(pred_dir, str(k) + '_pred.png'),mark_boundaries(a,b))\n",
    "    #Saving our predictions in the directory 'preds'\n",
    "    plt.plot(history.history['dice_coef'])\n",
    "    plt.plot(history.history['val_dice_coef'])\n",
    "    plt.title('Model dice coeff')\n",
    "    plt.ylabel('Dice coeff')\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.legend(['Train', 'Test'], loc='upper left')\n",
    "    plt.show()\n",
    "    #plotting our dice coeff results in function of the number of epochs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------------\n",
      "Loading and preprocessing train data...\n",
      "------------------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\Admin\\Anaconda3\\lib\\site-packages\\skimage\\transform\\_warps.py:105: UserWarning: The default mode, 'constant', will be changed to 'reflect' in skimage 0.15.\n",
      "  warn(\"The default mode, 'constant', will be changed to 'reflect' in \"\n",
      "C:\\Users\\Admin\\Anaconda3\\lib\\site-packages\\skimage\\transform\\_warps.py:110: UserWarning: Anti-aliasing will be enabled by default in skimage 0.15 to avoid aliasing artifacts when down-sampling images.\n",
      "  warn(\"Anti-aliasing will be enabled by default in skimage 0.15 to \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------------\n",
      "Creating and compiling model...\n",
      "------------------------------\n",
      "WARNING:tensorflow:From C:\\Users\\Admin\\Anaconda3\\lib\\site-packages\\tensorflow\\python\\framework\\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Colocations handled automatically by placer.\n",
      "------------------------------\n",
      "Fitting model...\n",
      "------------------------------\n",
      "Train on 1155 samples, validate on 289 samples\n",
      "Epoch 1/20\n",
      "1155/1155 [==============================] - 28s 24ms/step - loss: -0.6598 - dice_coef: 0.6598 - val_loss: -0.5496 - val_dice_coef: 0.5496\n",
      "Epoch 2/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.8656 - dice_coef: 0.8656 - val_loss: -0.7948 - val_dice_coef: 0.7948\n",
      "Epoch 3/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.8893 - dice_coef: 0.8893 - val_loss: -0.7885 - val_dice_coef: 0.7885\n",
      "Epoch 4/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9105 - dice_coef: 0.9105 - val_loss: -0.8283 - val_dice_coef: 0.8283\n",
      "Epoch 5/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9240 - dice_coef: 0.9240 - val_loss: -0.8433 - val_dice_coef: 0.8433\n",
      "Epoch 6/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9339 - dice_coef: 0.9339 - val_loss: -0.8622 - val_dice_coef: 0.8622\n",
      "Epoch 7/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9486 - dice_coef: 0.9486 - val_loss: -0.8153 - val_dice_coef: 0.8153\n",
      "Epoch 8/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9564 - dice_coef: 0.9564 - val_loss: -0.8305 - val_dice_coef: 0.8305\n",
      "Epoch 9/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9608 - dice_coef: 0.9608 - val_loss: -0.8910 - val_dice_coef: 0.8910\n",
      "Epoch 10/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9664 - dice_coef: 0.9664 - val_loss: -0.8900 - val_dice_coef: 0.8900 9s - loss: -0.9669 - - ETA -\n",
      "Epoch 11/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9699 - dice_coef: 0.9699 - val_loss: -0.9139 - val_dice_coef: 0.9139\n",
      "Epoch 12/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9718 - dice_coef: 0.9718 - val_loss: -0.9070 - val_dice_coef: 0.9070\n",
      "Epoch 13/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9698 - dice_coef: 0.9698 - val_loss: -0.9066 - val_dice_coef: 0.9066\n",
      "Epoch 14/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9734 - dice_coef: 0.9734 - val_loss: -0.9192 - val_dice_coef: 0.9192\n",
      "Epoch 15/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9734 - dice_coef: 0.9734 - val_loss: -0.8997 - val_dice_coef: 0.8997\n",
      "Epoch 16/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9723 - dice_coef: 0.9723 - val_loss: -0.9127 - val_dice_coef: 0.9127\n",
      "Epoch 17/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9781 - dice_coef: 0.9781 - val_loss: -0.9189 - val_dice_coef: 0.9189\n",
      "Epoch 18/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9591 - dice_coef: 0.9591 - val_loss: -0.8179 - val_dice_coef: 0.8179\n",
      "Epoch 19/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9296 - dice_coef: 0.9296 - val_loss: -0.8700 - val_dice_coef: 0.8700\n",
      "Epoch 20/20\n",
      "1155/1155 [==============================] - 13s 11ms/step - loss: -0.9587 - dice_coef: 0.9587 - val_loss: -0.8235 - val_dice_coef: 0.8235\n",
      "------------------------------\n",
      "Loading and preprocessing test data...\n",
      "------------------------------\n",
      "------------------------------\n",
      "Loading saved weights...\n",
      "------------------------------\n",
      "------------------------------\n",
      "Predicting masks on test data...\n",
      "------------------------------\n",
      "935/935 [==============================] - 5s 5ms/step\n",
      "------------------------------\n",
      "Saving predicted masks to files...\n",
      "------------------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\Admin\\Anaconda3\\lib\\site-packages\\skimage\\util\\dtype.py:141: UserWarning: Possible precision loss when converting from float32 to uint8\n",
      "  .format(dtypeobj_in, dtypeobj_out))\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "    train_and_predict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}