Diff of /ndv/training-1cycle.ipynb [000000] .. [64faee]

Switch to unified view

a b/ndv/training-1cycle.ipynb
1
{
2
 "cells": [
3
  {
4
   "cell_type": "code",
5
   "execution_count": 1,
6
   "metadata": {},
7
   "outputs": [
8
    {
9
     "name": "stdout",
10
     "output_type": "stream",
11
     "text": [
12
      "47 items written into valid.txt.\n"
13
     ]
14
    }
15
   ],
16
   "source": [
17
    "import torch, fastai, sys, os\n",
18
    "from fastai.vision import *\n",
19
    "import ants\n",
20
    "from ants.core.ants_image import ANTsImage\n",
21
    "from jupyterthemes import jtplot\n",
22
    "sys.path.insert(0, './exp')\n",
23
    "jtplot.style(theme='gruvboxd')\n",
24
    "\n",
25
    "import model\n",
26
    "from model import SoftDiceLoss, KLDivergence, L2Loss\n",
27
    "import dataloader \n",
28
    "from dataloader import data"
29
   ]
30
  },
31
  {
32
   "cell_type": "code",
33
   "execution_count": 2,
34
   "metadata": {},
35
   "outputs": [
36
    {
37
     "data": {
38
      "text/plain": [
39
       "1"
40
      ]
41
     },
42
     "execution_count": 2,
43
     "metadata": {},
44
     "output_type": "execute_result"
45
    }
46
   ],
47
   "source": [
48
    "torch.cuda.set_device(1)\n",
49
    "torch.cuda.current_device()"
50
   ]
51
  },
52
  {
53
   "cell_type": "code",
54
   "execution_count": 3,
55
   "metadata": {},
56
   "outputs": [],
57
   "source": [
58
    "autounet = model.autounet.cuda()\n",
59
    "sdl = SoftDiceLoss()\n",
60
    "kld = KLDivergence()\n",
61
    "l2l = L2Loss()"
62
   ]
63
  },
64
  {
65
   "cell_type": "code",
66
   "execution_count": 4,
67
   "metadata": {},
68
   "outputs": [],
69
   "source": [
70
    "class AutoUNetCallback(LearnerCallback):\n",
71
    "    \"Custom callback for implementing `AutoUNet` training loop\"\n",
72
    "    _order=0\n",
73
    "    \n",
74
    "    def __init__(self, learn:Learner):\n",
75
    "        super().__init__(learn)\n",
76
    "    \n",
77
    "    def on_batch_begin(self, last_input:Tensor, last_target:Tensor, **kwargs):\n",
78
    "        \"Store the states to be later used to calculate the loss\"\n",
79
    "        self.top_y, self.bottom_y = last_target.data, last_input.data\n",
80
    "        \n",
81
    "    def on_loss_begin(self, last_output:Tuple[Tensor,Tensor], **kwargs):\n",
82
    "        \"Stroe the states to be later used to calculate the loss\"\n",
83
    "        self.top_res, self.bottom_res = last_output\n",
84
    "        self.z_mean, self.z_log_var = model.hooks.stored[3], model.hooks.stored[4]\n",
85
    "        return {'last_output': (self.top_res, self.bottom_res,\n",
86
    "                                self.z_mean, self.z_log_var,\n",
87
    "                                self.top_y, self.bottom_y)}"
88
   ]
89
  },
90
  {
91
   "cell_type": "code",
92
   "execution_count": 5,
93
   "metadata": {},
94
   "outputs": [],
95
   "source": [
96
    "class AutoUNetLoss(nn.Module):\n",
97
    "    \"Combining all the loss functions defined for `AutoUNet`\"\n",
98
    "    def __init__(self):\n",
99
    "        super().__init__()\n",
100
    "    \n",
101
    "    def forward(self, top_res, bottom_res, z_mean, z_log_var, top_y, bottom_y):\n",
102
    "        return sdl(top_res, top_y) + (0.1 * kld(z_mean, z_log_var)) + (0.1 * l2l(bottom_res, bottom_y))"
103
   ]
104
  },
105
  {
106
   "cell_type": "code",
107
   "execution_count": 6,
108
   "metadata": {
109
    "code_folding": [
110
     1
111
    ]
112
   },
113
   "outputs": [],
114
   "source": [
115
    "#monkey-patch\n",
116
    "def mp_loss_batch(model:nn.Module, xb:Tensor, yb:Tensor, loss_func:OptLossFunc=None, opt:OptOptimizer=None,\n",
117
    "               cb_handler:Optional[CallbackHandler]=None)->Tuple[Union[Tensor,int,float,str]]:\n",
118
    "    \"Calculate loss and metrics for a batch, call out to callbacks as necessary.\"\n",
119
    "    cb_handler = ifnone(cb_handler, CallbackHandler())\n",
120
    "    if not is_listy(xb): xb = [xb]\n",
121
    "    if not is_listy(yb): yb = [yb]\n",
122
    "    out = model(*xb)\n",
123
    "    out = cb_handler.on_loss_begin(out)\n",
124
    "\n",
125
    "    if not loss_func: return to_detach(out), to_detach(yb[0])\n",
126
    "    loss = loss_func(*out) #modified\n",
127
    "\n",
128
    "    if opt is not None:\n",
129
    "        loss,skip_bwd = cb_handler.on_backward_begin(loss)\n",
130
    "        if not skip_bwd:                     loss.backward()\n",
131
    "        if not cb_handler.on_backward_end(): opt.step()\n",
132
    "        if not cb_handler.on_step_end():     opt.zero_grad()\n",
133
    "\n",
134
    "    return loss.detach().cpu()"
135
   ]
136
  },
137
  {
138
   "cell_type": "code",
139
   "execution_count": 7,
140
   "metadata": {
141
    "code_folding": [
142
     1
143
    ]
144
   },
145
   "outputs": [],
146
   "source": [
147
    "#monkey-patch\n",
148
    "def mp_fit(epochs:int, learn:Learner, callbacks:Optional[CallbackList]=None, metrics:OptMetrics=None)->None:\n",
149
    "    \"Fit the `model` on `data` and learn using `loss_func` and `opt`.\"\n",
150
    "    assert len(learn.data.train_dl) != 0, f\"\"\"Your training dataloader is empty, can't train a model.\n",
151
    "        Use a smaller batch size (batch size={learn.data.train_dl.batch_size} for {len(learn.data.train_dl.dataset)} elements).\"\"\"\n",
152
    "    cb_handler = CallbackHandler(callbacks, metrics)\n",
153
    "    pbar = master_bar(range(epochs))\n",
154
    "    cb_handler.on_train_begin(epochs, pbar=pbar, metrics=metrics)\n",
155
    "\n",
156
    "    exception=False\n",
157
    "    try:\n",
158
    "        for epoch in pbar:\n",
159
    "            learn.model.train()\n",
160
    "            cb_handler.set_dl(learn.data.train_dl)\n",
161
    "            cb_handler.on_epoch_begin()\n",
162
    "            for xb,yb in progress_bar(learn.data.train_dl, parent=pbar):\n",
163
    "                xb, yb = cb_handler.on_batch_begin(xb, yb)\n",
164
    "                loss = loss_batch(learn.model, xb, yb, learn.loss_func, learn.opt, cb_handler) #modified\n",
165
    "                if cb_handler.on_batch_end(loss): break\n",
166
    "\n",
167
    "            if not cb_handler.skip_validate and not learn.data.empty_val:\n",
168
    "                val_loss = validate(learn.model, learn.data.valid_dl, loss_func=learn.loss_func,\n",
169
    "                                       cb_handler=cb_handler, pbar=pbar)\n",
170
    "            else: val_loss=None\n",
171
    "            if cb_handler.on_epoch_end(val_loss): break\n",
172
    "    except Exception as e:\n",
173
    "        exception = e\n",
174
    "        raise\n",
175
    "    finally: cb_handler.on_train_end(exception)\n"
176
   ]
177
  },
178
  {
179
   "cell_type": "code",
180
   "execution_count": 8,
181
   "metadata": {
182
    "code_folding": [
183
     1
184
    ]
185
   },
186
   "outputs": [],
187
   "source": [
188
    " #monkey-patch\n",
189
    "def mp_learner_fit(self, epochs:int, lr:Union[Floats,slice]=defaults.lr,\n",
190
    "                   wd:Floats=None, callbacks:Collection[Callback]=None)->None:\n",
191
    "    \"Fit the model on this learner with `lr` learning rate, `wd` weight decay for `epochs` with `callbacks`.\"\n",
192
    "    lr = self.lr_range(lr)\n",
193
    "    if wd is None: wd = self.wd\n",
194
    "    if not getattr(self, 'opt', False): self.create_opt(lr, wd)\n",
195
    "    else: self.opt.lr,self.opt.wd = lr,wd\n",
196
    "    callbacks = [cb(self) for cb in self.callback_fns + listify(defaults.extra_callback_fns)] + listify(callbacks)\n",
197
    "    fit(epochs, self, metrics=self.metrics, callbacks=self.callbacks+callbacks)"
198
   ]
199
  },
200
  {
201
   "cell_type": "code",
202
   "execution_count": 9,
203
   "metadata": {
204
    "code_folding": [
205
     1
206
    ]
207
   },
208
   "outputs": [],
209
   "source": [
210
    "#monkey-patch\n",
211
    "def mp_validate(model:nn.Module, dl:DataLoader, loss_func:OptLossFunc=None, cb_handler:Optional[CallbackHandler]=None,\n",
212
    "             pbar:Optional[PBar]=None, average=True, n_batch:Optional[int]=None)->Iterator[Tuple[Union[Tensor,int],...]]:\n",
213
    "    \"Calculate `loss_func` of `model` on `dl` in evaluation mode.\"\n",
214
    "    model.eval()\n",
215
    "    with torch.no_grad():\n",
216
    "        val_losses,nums = [],[]\n",
217
    "        if cb_handler: cb_handler.set_dl(dl)\n",
218
    "        for xb,yb in progress_bar(dl, parent=pbar, leave=(pbar is not None)):\n",
219
    "            if cb_handler: xb, yb = cb_handler.on_batch_begin(xb, yb, train=False)\n",
220
    "            val_loss = loss_batch(model, xb, yb, loss_func, cb_handler=cb_handler) #modified\n",
221
    "            val_losses.append(val_loss)\n",
222
    "            if not is_listy(yb): yb = [yb]\n",
223
    "            nums.append(first_el(yb).shape[0])\n",
224
    "            if cb_handler and cb_handler.on_batch_end(val_losses[-1]): break\n",
225
    "            if n_batch and (len(nums)>=n_batch): break\n",
226
    "        nums = np.array(nums, dtype=np.float32)\n",
227
    "        if average: return (to_np(torch.stack(val_losses)) * nums).sum() / nums.sum()\n",
228
    "        else:       return val_losses"
229
   ]
230
  },
231
  {
232
   "cell_type": "code",
233
   "execution_count": 10,
234
   "metadata": {
235
    "code_folding": [
236
     1
237
    ]
238
   },
239
   "outputs": [],
240
   "source": [
241
    "#monkey-patch\n",
242
    "def mp_learner_validate(self, dl=None, callbacks=None, metrics=None):\n",
243
    "    \"Validate on `dl` with potential `callbacks` and `metrics`.\"\n",
244
    "    dl = ifnone(dl, self.data.valid_dl)\n",
245
    "    metrics = ifnone(metrics, self.metrics)\n",
246
    "    cb_handler = CallbackHandler(self.callbacks + ifnone(callbacks, []), metrics)\n",
247
    "    cb_handler.on_train_begin(1, None, metrics); cb_handler.on_epoch_begin()\n",
248
    "    val_metrics = validate(self.model, dl, self.loss_func, cb_handler)\n",
249
    "    cb_handler.on_epoch_end(val_metrics)\n",
250
    "    return cb_handler.state_dict['last_metrics']"
251
   ]
252
  },
253
  {
254
   "cell_type": "code",
255
   "execution_count": 11,
256
   "metadata": {},
257
   "outputs": [],
258
   "source": [
259
    "from fastai.basic_train import loss_batch, fit, validate"
260
   ]
261
  },
262
  {
263
   "cell_type": "code",
264
   "execution_count": 12,
265
   "metadata": {},
266
   "outputs": [],
267
   "source": [
268
    "loss_batch = mp_loss_batch\n",
269
    "fit = mp_fit\n",
270
    "validate = mp_validate\n",
271
    "Learner.fit = mp_learner_fit\n",
272
    "Learner.validate = mp_learner_validate"
273
   ]
274
  },
275
  {
276
   "cell_type": "code",
277
   "execution_count": 13,
278
   "metadata": {},
279
   "outputs": [],
280
   "source": [
281
    "def dice_coefficient(last_output:Tensor, last_target:Tensor):\n",
282
    "    \"Metric based on dice coefficient\"\n",
283
    "    pred, targ = last_output[0], last_target\n",
284
    "    return 2 * (pred * targ).sum() / ((pred**2).sum() + (targ**2).sum())"
285
   ]
286
  },
287
  {
288
   "cell_type": "code",
289
   "execution_count": 14,
290
   "metadata": {},
291
   "outputs": [],
292
   "source": [
293
    "auto_unet_loss = AutoUNetLoss()"
294
   ]
295
  },
296
  {
297
   "cell_type": "code",
298
   "execution_count": 15,
299
   "metadata": {},
300
   "outputs": [],
301
   "source": [
302
    "learner = Learner(data, autounet, loss_func=auto_unet_loss)"
303
   ]
304
  },
305
  {
306
   "cell_type": "code",
307
   "execution_count": 16,
308
   "metadata": {},
309
   "outputs": [],
310
   "source": [
311
    "autounet_cb = AutoUNetCallback(learner)"
312
   ]
313
  },
314
  {
315
   "cell_type": "code",
316
   "execution_count": 17,
317
   "metadata": {},
318
   "outputs": [],
319
   "source": [
320
    "learner.callbacks.append(autounet_cb)"
321
   ]
322
  },
323
  {
324
   "cell_type": "code",
325
   "execution_count": 17,
326
   "metadata": {},
327
   "outputs": [
328
    {
329
     "data": {
330
      "text/html": [
331
       "\n",
332
       "    <div>\n",
333
       "        <style>\n",
334
       "            /* Turns off some styling */\n",
335
       "            progress {\n",
336
       "                /* gets rid of default border in Firefox and Opera. */\n",
337
       "                border: none;\n",
338
       "                /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
339
       "                background-size: auto;\n",
340
       "            }\n",
341
       "            .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
342
       "                background: #F44336;\n",
343
       "            }\n",
344
       "        </style>\n",
345
       "      <progress value='0' class='' max='1', style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
346
       "      0.00% [0/1 00:00<00:00]\n",
347
       "    </div>\n",
348
       "    \n",
349
       "<table border=\"1\" class=\"dataframe\">\n",
350
       "  <thead>\n",
351
       "    <tr style=\"text-align: left;\">\n",
352
       "      <th>epoch</th>\n",
353
       "      <th>train_loss</th>\n",
354
       "      <th>valid_loss</th>\n",
355
       "      <th>time</th>\n",
356
       "    </tr>\n",
357
       "  </thead>\n",
358
       "  <tbody>\n",
359
       "  </tbody>\n",
360
       "</table><p>\n",
361
       "\n",
362
       "    <div>\n",
363
       "        <style>\n",
364
       "            /* Turns off some styling */\n",
365
       "            progress {\n",
366
       "                /* gets rid of default border in Firefox and Opera. */\n",
367
       "                border: none;\n",
368
       "                /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
369
       "                background-size: auto;\n",
370
       "            }\n",
371
       "            .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
372
       "                background: #F44336;\n",
373
       "            }\n",
374
       "        </style>\n",
375
       "      <progress value='58' class='' max='288', style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
376
       "      20.14% [58/288 05:56<23:34 176342.1875]\n",
377
       "    </div>\n",
378
       "    "
379
      ],
380
      "text/plain": [
381
       "<IPython.core.display.HTML object>"
382
      ]
383
     },
384
     "metadata": {},
385
     "output_type": "display_data"
386
    },
387
    {
388
     "name": "stdout",
389
     "output_type": "stream",
390
     "text": [
391
      "LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.\n"
392
     ]
393
    }
394
   ],
395
   "source": [
396
    "learner.lr_find()"
397
   ]
398
  },
399
  {
400
   "cell_type": "code",
401
   "execution_count": 18,
402
   "metadata": {},
403
   "outputs": [
404
    {
405
     "data": {
406
      "image/png": "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\n",
407
      "text/plain": [
408
       "<Figure size 432x288 with 1 Axes>"
409
      ]
410
     },
411
     "metadata": {},
412
     "output_type": "display_data"
413
    }
414
   ],
415
   "source": [
416
    "learner.recorder.plot()"
417
   ]
418
  },
419
  {
420
   "cell_type": "code",
421
   "execution_count": 20,
422
   "metadata": {},
423
   "outputs": [
424
    {
425
     "data": {
426
      "text/plain": [
427
       "PosixPath('/home/ubuntu/MultiCampus/MICCAI_BraTS_2019_Data_Training/models/trained_model.pth')"
428
      ]
429
     },
430
     "execution_count": 20,
431
     "metadata": {},
432
     "output_type": "execute_result"
433
    }
434
   ],
435
   "source": [
436
    "learner.save(\"trained_model\", return_path=True)"
437
   ]
438
  },
439
  {
440
   "cell_type": "code",
441
   "execution_count": 20,
442
   "metadata": {},
443
   "outputs": [],
444
   "source": [
445
    "learner = learner.load(\"trained_model\", device=1)"
446
   ]
447
  },
448
  {
449
   "cell_type": "code",
450
   "execution_count": 20,
451
   "metadata": {},
452
   "outputs": [],
453
   "source": [
454
    "learner.metrics = [dice_coefficient]"
455
   ]
456
  },
457
  {
458
   "cell_type": "code",
459
   "execution_count": 23,
460
   "metadata": {},
461
   "outputs": [
462
    {
463
     "data": {
464
      "text/html": [
465
       "<table border=\"1\" class=\"dataframe\">\n",
466
       "  <thead>\n",
467
       "    <tr style=\"text-align: left;\">\n",
468
       "      <th>epoch</th>\n",
469
       "      <th>train_loss</th>\n",
470
       "      <th>valid_loss</th>\n",
471
       "      <th>dice_coefficient</th>\n",
472
       "      <th>time</th>\n",
473
       "    </tr>\n",
474
       "  </thead>\n",
475
       "  <tbody>\n",
476
       "    <tr>\n",
477
       "      <td>0</td>\n",
478
       "      <td>11968.476562</td>\n",
479
       "      <td>11397.278320</td>\n",
480
       "      <td>0.728514</td>\n",
481
       "      <td>31:11</td>\n",
482
       "    </tr>\n",
483
       "  </tbody>\n",
484
       "</table>"
485
      ],
486
      "text/plain": [
487
       "<IPython.core.display.HTML object>"
488
      ]
489
     },
490
     "metadata": {},
491
     "output_type": "display_data"
492
    }
493
   ],
494
   "source": [
495
    "learner.fit_one_cycle(1, max_lr=3e-04)"
496
   ]
497
  },
498
  {
499
   "cell_type": "code",
500
   "execution_count": 24,
501
   "metadata": {},
502
   "outputs": [
503
    {
504
     "data": {
505
      "text/html": [
506
       "<table border=\"1\" class=\"dataframe\">\n",
507
       "  <thead>\n",
508
       "    <tr style=\"text-align: left;\">\n",
509
       "      <th>epoch</th>\n",
510
       "      <th>train_loss</th>\n",
511
       "      <th>valid_loss</th>\n",
512
       "      <th>dice_coefficient</th>\n",
513
       "      <th>time</th>\n",
514
       "    </tr>\n",
515
       "  </thead>\n",
516
       "  <tbody>\n",
517
       "    <tr>\n",
518
       "      <td>0</td>\n",
519
       "      <td>10191.506836</td>\n",
520
       "      <td>11200.149414</td>\n",
521
       "      <td>0.737531</td>\n",
522
       "      <td>32:57</td>\n",
523
       "    </tr>\n",
524
       "    <tr>\n",
525
       "      <td>1</td>\n",
526
       "      <td>11503.087891</td>\n",
527
       "      <td>11923.188477</td>\n",
528
       "      <td>0.644095</td>\n",
529
       "      <td>32:46</td>\n",
530
       "    </tr>\n",
531
       "    <tr>\n",
532
       "      <td>2</td>\n",
533
       "      <td>11965.605469</td>\n",
534
       "      <td>11864.083984</td>\n",
535
       "      <td>0.658343</td>\n",
536
       "      <td>32:44</td>\n",
537
       "    </tr>\n",
538
       "    <tr>\n",
539
       "      <td>3</td>\n",
540
       "      <td>11030.506836</td>\n",
541
       "      <td>11926.581055</td>\n",
542
       "      <td>0.679012</td>\n",
543
       "      <td>32:11</td>\n",
544
       "    </tr>\n",
545
       "    <tr>\n",
546
       "      <td>4</td>\n",
547
       "      <td>10746.779297</td>\n",
548
       "      <td>11227.884766</td>\n",
549
       "      <td>0.706088</td>\n",
550
       "      <td>32:13</td>\n",
551
       "    </tr>\n",
552
       "    <tr>\n",
553
       "      <td>5</td>\n",
554
       "      <td>10609.997070</td>\n",
555
       "      <td>11073.265625</td>\n",
556
       "      <td>0.709225</td>\n",
557
       "      <td>32:19</td>\n",
558
       "    </tr>\n",
559
       "    <tr>\n",
560
       "      <td>6</td>\n",
561
       "      <td>10128.075195</td>\n",
562
       "      <td>10866.394531</td>\n",
563
       "      <td>0.730715</td>\n",
564
       "      <td>32:28</td>\n",
565
       "    </tr>\n",
566
       "    <tr>\n",
567
       "      <td>7</td>\n",
568
       "      <td>8688.515625</td>\n",
569
       "      <td>10695.497070</td>\n",
570
       "      <td>0.721070</td>\n",
571
       "      <td>32:36</td>\n",
572
       "    </tr>\n",
573
       "    <tr>\n",
574
       "      <td>8</td>\n",
575
       "      <td>9033.506836</td>\n",
576
       "      <td>10564.528320</td>\n",
577
       "      <td>0.755184</td>\n",
578
       "      <td>32:44</td>\n",
579
       "    </tr>\n",
580
       "    <tr>\n",
581
       "      <td>9</td>\n",
582
       "      <td>8694.732422</td>\n",
583
       "      <td>10569.330078</td>\n",
584
       "      <td>0.755437</td>\n",
585
       "      <td>30:29</td>\n",
586
       "    </tr>\n",
587
       "  </tbody>\n",
588
       "</table>"
589
      ],
590
      "text/plain": [
591
       "<IPython.core.display.HTML object>"
592
      ]
593
     },
594
     "metadata": {},
595
     "output_type": "display_data"
596
    }
597
   ],
598
   "source": [
599
    "learner.fit_one_cycle(10, max_lr=3e-04)"
600
   ]
601
  },
602
  {
603
   "cell_type": "code",
604
   "execution_count": 26,
605
   "metadata": {},
606
   "outputs": [
607
    {
608
     "data": {
609
      "text/plain": [
610
       "PosixPath('/home/ubuntu/MultiCampus/MICCAI_BraTS_2019_Data_Training/models/trained_model_1cycle.pth')"
611
      ]
612
     },
613
     "execution_count": 26,
614
     "metadata": {},
615
     "output_type": "execute_result"
616
    }
617
   ],
618
   "source": [
619
    "learner.save(\"trained_model_1cycle\", return_path=True)"
620
   ]
621
  },
622
  {
623
   "cell_type": "code",
624
   "execution_count": 18,
625
   "metadata": {},
626
   "outputs": [],
627
   "source": [
628
    "learner = learner.load(\"trained_model_1cycle\", device=1)"
629
   ]
630
  },
631
  {
632
   "cell_type": "code",
633
   "execution_count": null,
634
   "metadata": {},
635
   "outputs": [
636
    {
637
     "data": {
638
      "text/html": [
639
       "\n",
640
       "    <div>\n",
641
       "        <style>\n",
642
       "            /* Turns off some styling */\n",
643
       "            progress {\n",
644
       "                /* gets rid of default border in Firefox and Opera. */\n",
645
       "                border: none;\n",
646
       "                /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
647
       "                background-size: auto;\n",
648
       "            }\n",
649
       "            .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
650
       "                background: #F44336;\n",
651
       "            }\n",
652
       "        </style>\n",
653
       "      <progress value='8' class='' max='10', style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
654
       "      80.00% [8/10 4:10:44<1:02:41]\n",
655
       "    </div>\n",
656
       "    \n",
657
       "<table border=\"1\" class=\"dataframe\">\n",
658
       "  <thead>\n",
659
       "    <tr style=\"text-align: left;\">\n",
660
       "      <th>epoch</th>\n",
661
       "      <th>train_loss</th>\n",
662
       "      <th>valid_loss</th>\n",
663
       "      <th>dice_coefficient</th>\n",
664
       "      <th>time</th>\n",
665
       "    </tr>\n",
666
       "  </thead>\n",
667
       "  <tbody>\n",
668
       "    <tr>\n",
669
       "      <td>0</td>\n",
670
       "      <td>10392.399414</td>\n",
671
       "      <td>9580.957031</td>\n",
672
       "      <td>0.736880</td>\n",
673
       "      <td>31:50</td>\n",
674
       "    </tr>\n",
675
       "    <tr>\n",
676
       "      <td>1</td>\n",
677
       "      <td>10042.610352</td>\n",
678
       "      <td>10256.254883</td>\n",
679
       "      <td>0.701320</td>\n",
680
       "      <td>30:34</td>\n",
681
       "    </tr>\n",
682
       "    <tr>\n",
683
       "      <td>2</td>\n",
684
       "      <td>10119.898438</td>\n",
685
       "      <td>10275.036133</td>\n",
686
       "      <td>0.689501</td>\n",
687
       "      <td>31:14</td>\n",
688
       "    </tr>\n",
689
       "    <tr>\n",
690
       "      <td>3</td>\n",
691
       "      <td>10711.199219</td>\n",
692
       "      <td>10155.269531</td>\n",
693
       "      <td>0.584035</td>\n",
694
       "      <td>31:59</td>\n",
695
       "    </tr>\n",
696
       "    <tr>\n",
697
       "      <td>4</td>\n",
698
       "      <td>9853.235352</td>\n",
699
       "      <td>10081.066406</td>\n",
700
       "      <td>0.673109</td>\n",
701
       "      <td>31:24</td>\n",
702
       "    </tr>\n",
703
       "    <tr>\n",
704
       "      <td>5</td>\n",
705
       "      <td>9889.505859</td>\n",
706
       "      <td>9921.931641</td>\n",
707
       "      <td>0.688964</td>\n",
708
       "      <td>31:13</td>\n",
709
       "    </tr>\n",
710
       "    <tr>\n",
711
       "      <td>6</td>\n",
712
       "      <td>8726.832031</td>\n",
713
       "      <td>9781.743164</td>\n",
714
       "      <td>0.708290</td>\n",
715
       "      <td>31:18</td>\n",
716
       "    </tr>\n",
717
       "    <tr>\n",
718
       "      <td>7</td>\n",
719
       "      <td>8652.989258</td>\n",
720
       "      <td>9700.190430</td>\n",
721
       "      <td>0.732054</td>\n",
722
       "      <td>31:08</td>\n",
723
       "    </tr>\n",
724
       "  </tbody>\n",
725
       "</table><p>\n",
726
       "\n",
727
       "    <div>\n",
728
       "        <style>\n",
729
       "            /* Turns off some styling */\n",
730
       "            progress {\n",
731
       "                /* gets rid of default border in Firefox and Opera. */\n",
732
       "                border: none;\n",
733
       "                /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
734
       "                background-size: auto;\n",
735
       "            }\n",
736
       "            .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
737
       "                background: #F44336;\n",
738
       "            }\n",
739
       "        </style>\n",
740
       "      <progress value='220' class='' max='288', style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
741
       "      76.39% [220/288 22:29<06:57 8392.4023]\n",
742
       "    </div>\n",
743
       "    "
744
      ],
745
      "text/plain": [
746
       "<IPython.core.display.HTML object>"
747
      ]
748
     },
749
     "metadata": {},
750
     "output_type": "display_data"
751
    }
752
   ],
753
   "source": [
754
    "learner.fit_one_cycle(10, max_lr=3e-04)"
755
   ]
756
  }
757
 ],
758
 "metadata": {
759
  "kernelspec": {
760
   "display_name": "Python 3",
761
   "language": "python",
762
   "name": "python3"
763
  },
764
  "language_info": {
765
   "codemirror_mode": {
766
    "name": "ipython",
767
    "version": 3
768
   },
769
   "file_extension": ".py",
770
   "mimetype": "text/x-python",
771
   "name": "python",
772
   "nbconvert_exporter": "python",
773
   "pygments_lexer": "ipython3",
774
   "version": "3.6.5"
775
  }
776
 },
777
 "nbformat": 4,
778
 "nbformat_minor": 4
779
}