Extract boxes with PyTorch


In [1]:
%load_ext autoreload
%autoreload 2

import os, glob, json, tqdm, pandas, pickle
import matplotlib.pyplot as plt
%pylab inline

import torch
from torch import nn
from torch.autograd import Variable
from torch.nn import functional as F
from torch.optim import Adam
from torch.utils.data import Dataset, DataLoader

from imgaug import augmenters as iaa
from imgaug import imgaug as ia
from PIL import Image

from IPython.display import display

from prepare_images_utils import *
from latex_dataset import *


Populating the interactive namespace from numpy and matplotlib

Prepare data source


In [2]:
SRC_DIR = './generated/src/'

In [3]:
all_image_ids = [os.path.basename(fname)[:-9]
                 for fname in glob.glob(os.path.join(SRC_DIR, '*_out.json'))]
random.shuffle(all_image_ids)

TOTAL_SAMPLES = len(all_image_ids)
TRAIN_SAMPLES = int(TOTAL_SAMPLES * 0.8)
VAL_SAMPLES = TOTAL_SAMPLES - TRAIN_SAMPLES
train_image_ids = all_image_ids[:TRAIN_SAMPLES]
val_image_ids = all_image_ids[TRAIN_SAMPLES:]

In [4]:
def load_image_with_boxes(img_id):
    img = load_image_opaque(os.path.join(SRC_DIR, img_id + '_in.png'))
    with open(os.path.join(SRC_DIR, img_id + '_out.json'), 'r') as f:
        boxes = json.load(f)
    return img, boxes


def prepare_img_boxes_for_nn(img, boxes, shape=(600, 600)):
    cats, just_boxes = zip(*boxes)
    cats = numpy.array(cats)
    just_boxes = numpy.array(just_boxes) * POINTS_TO_PIXELS_FACTOR
    just_boxes = just_boxes[:, [1, 0, 3, 2]] # x1, y1, x2, y2
    cropbox = numpy.array((just_boxes[:, 0].min(),
                           just_boxes[:, 1].min(),
                           just_boxes[:, 2].max(),
                           just_boxes[:, 3].max())).astype('int')

    res_in_img = Image.new('L', shape, 255)
    res_in_img.paste(img.crop(cropbox))

    just_boxes -= cropbox[[0, 1, 0, 1]]
    just_boxes = numpy.clip(just_boxes,
                            (0, 0, 0, 0),
                            (shape[0], shape[1], shape[0], shape[1]))
    boxes_area = (just_boxes[:, 2] - just_boxes[:, 0]) * (just_boxes[:, 3] - just_boxes[:, 1])
    good_boxes = numpy.where(boxes_area > 0)[0]
    return (numpy.array(res_in_img).astype('float32') / 255,
            cats[good_boxes],
            just_boxes[good_boxes])


TOTAL_CLASSES = 5
def make_mask_for_nn(size, box_cats, boxes_on_image):
    result = numpy.zeros((TOTAL_CLASSES, ) + size, dtype='float32')
    for cat, bbox in zip(box_cats, boxes_on_image.bounding_boxes):
        result[cat, int(bbox.y1):int(bbox.y2+1), int(bbox.x1):int(bbox.x2+1)] = 1
    return result


def calc_loss_weights(mask, edge_add_weight=0.2, laplacian_ksize=9, edge_th=1.1):
    result = numpy.ones_like(mask)
    for sample_i in range(mask.shape[0]):
        for channel_i in range(mask.shape[1]):
            edges = numpy.absolute(cv2.Laplacian(mask[sample_i, channel_i],
                                                 cv2.CV_32F,
                                                 ksize=laplacian_ksize))
            edges = numpy.where(edges > edge_th, 1, 0)
            if edges.max() > 0:
                result[sample_i, channel_i] += edge_add_weight * edges
    return result


def prepare_batch(batch_image_ids, augmenter):
    images, box_cats, boxes = zip(*[prepare_img_boxes_for_nn(*load_image_with_boxes(img_id))
                                    for img_id in batch_image_ids])

    det = augmenter.to_deterministic() if not augmenter.deterministic else augseq

    images_aug = det.augment_images(images)

    boxes = [ia.BoundingBoxesOnImage([ia.BoundingBox(*box)
                                      for box in img_boxes],
                                     img.shape)
             for img, img_boxes in zip(images, boxes)]
    boxes_aug = det.augment_bounding_boxes(boxes)

    mask = numpy.array([make_mask_for_nn(img.shape, img_box_cats, img_boxes)
                        for img, img_box_cats, img_boxes
                        in zip(images_aug, box_cats, boxes_aug)])

    boxes_aug_lists_with_cats = []
    for img_boxes, img_box_cats in zip(boxes_aug, box_cats):
        img_boxes_with_cats = collections.defaultdict(list)
        for b, c in zip(img_boxes.bounding_boxes, img_box_cats):
            img_boxes_with_cats[c].append((b.x1, b.y1, b.x2, b.y2))
        boxes_aug_lists_with_cats.append(img_boxes_with_cats)

    return (batch_image_ids,
            numpy.expand_dims(numpy.array(images_aug), 1),
            mask,
            calc_loss_weights(mask),
            boxes_aug_lists_with_cats)


def data_gen(image_ids, augmenter, batch_size=32):
    while True:
        yield prepare_batch(numpy.random.choice(image_ids, size=batch_size),
                            augmenter)


class SegmDataset(Dataset):
    def __init__(self, all_image_ids, augmenter):
        self.all_image_ids = all_image_ids
        self.augmenter = augmenter

    def __len__(self):
        return len(self.all_image_ids)

    def __getitem__(self, i):
        (batch_image_ids,
         in_img,
         mask,
         loss_weights,
         boxes_aug) = prepare_batch([self.all_image_ids[i]],
                                    self.augmenter)
        boxes_aug_str = pickle.dumps(boxes_aug[0])
        return (batch_image_ids,
                in_img[0],
                mask[0],
                loss_weights[0],
                boxes_aug_str)

In [5]:
imgaug_pipeline = iaa.Sequential([
#     iaa.Fliplr(0.5), # horizontally flip 50% of the images
#     iaa.GaussianBlur(sigma=(0, 3.0)) # blur images with a sigma of 0 to 3.0
])

Compare data generators


In [6]:
# train_gen_mt = DataLoader(SegmDataset(train_image_ids, imgaug_pipeline),
#                           batch_size=8,
#                           shuffle=True,
#                           num_workers=4)
# train_gen_mt_iter = iter(train_gen_mt)
# _ = next(train_gen_mt_iter)

In [7]:
# %%prun
# for _ in range(10):
#     next(train_gen_mt_iter)

In [8]:
# train_gen_st = data_gen(train_image_ids, imgaug_pipeline, batch_size=8)
# train_gen_st_iter = iter(train_gen_st)
# _ = next(train_gen_st_iter)

In [9]:
# %%prun
# for _ in range(10):
#     next(train_gen_st_iter)

Define a network


In [10]:
class ConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, dilations=[1], bn=True):
        super(ConvBlock, self).__init__()
        self.bn = nn.BatchNorm2d(in_channels)
        self.convs = nn.ModuleList([nn.Conv2d(in_channels,
                                              out_channels,
                                              kernel_size,
                                              padding=dil,
                                              dilation=dil)
                                    for dil in dilations])

    def forward(self, x):
        x = self.bn(x)
        return F.relu(torch.cat([conv(x) for conv in self.convs], dim=1))


class UNet(nn.Module):
    def __init__(self, out_channels=TOTAL_CLASSES, first_conv_channels=4, depth=2, out_layers=1, conv_kernel=(3, 3),
                 enc_dilations=[1], dec_dilations=[1]):
        super(UNet, self).__init__()
        enc_channels = [1] + [first_conv_channels * (2**step) for step in range(depth)]
        enc_in_channels = [1] + [n * len(enc_dilations) for n in enc_channels[1:]]
        self.encoder = nn.ModuleList([ConvBlock(enc_in_channels[i],
                                                enc_channels[i+1],
                                                conv_kernel,
                                                dilations=enc_dilations)
                                      for i in range(depth)])
        bottleneck_channels = enc_channels[-1] * 2
        self.bottleneck = ConvBlock(enc_channels[-1],
                                    bottleneck_channels,
                                    conv_kernel,
                                    dilations=enc_dilations)
        dec_channels = [bottleneck_channels] + enc_channels[:0:-1]
        self.dec_conv = nn.ModuleList([ConvBlock(dec_channels[i],
                                                 dec_channels[i+1],
                                                 conv_kernel,
                                                 dilations=dec_dilations)
                                      for i in range(depth)])
        self.dec_deconv = nn.ModuleList([nn.ConvTranspose2d(dec_channels[i],
                                                            dec_channels[i+1],
                                                            (2, 2),
                                                            stride=2)
                                         for i in range(depth)])
        self.out_layers = nn.ModuleList([ConvBlock(dec_channels[-1],
                                                   dec_channels[-1],
                                                   conv_kernel,
                                                   dilations=dec_dilations)])
        self.out_conv = nn.Conv2d(dec_channels[-1],
                                  out_channels,
                                  (1, 1))

    def forward(self, x):
        enc_conv_outs = []
        enc_pool_outs = [x]
        for enc_conv in self.encoder:
            cur_conv_out = enc_conv(enc_pool_outs[-1])
            enc_conv_outs.append(cur_conv_out)
            cur_pool_out = F.max_pool2d(cur_conv_out, (2, 2))
            enc_pool_outs.append(cur_pool_out)

        cur_out = self.bottleneck(enc_pool_outs[-1])

        for dec_step, (dec_conv, dec_deconv) in enumerate(zip(self.dec_conv, self.dec_deconv)):
            up = dec_deconv(cur_out)
            cur_out = torch.cat([up, enc_conv_outs[-dec_step-1]], dim=1)
            cur_out = dec_conv(cur_out)

        for out_layer in self.out_layers:
            cur_out = F.relu(out_layer(cur_out))

        return F.sigmoid(self.out_conv(cur_out))

Define losses and metrics

Discrete


In [11]:
def get_all_boxes(mask, min_area=100, min_size=(10, 10), threshold=0.5):
# def get_all_boxes(mask, min_area=0, min_size=(0, 0), threshold=0.5):
    result = []
    contours = cv2.findContours((mask > threshold).astype('uint8'),
                                cv2.RETR_LIST,
                                cv2.CHAIN_APPROX_SIMPLE)[1]
    for cnt in contours:
        if cv2.contourArea(cnt) < min_area:
            continue
        x, y, w, h = cv2.boundingRect(cnt)
        if h < min_size[0] or w < min_size[1]:
            continue
        result.append((y, x, y+h, x+w))
    result.sort()
    return result


def filter_by_intersection(big_box, boxes_to_filter, threshold=0.8):
    return [b for b in boxes_to_filter
            if box_inter_area(big_box, b) / box_area(b) >= threshold]


def get_biggest_box(boxes):
    return boxes[numpy.argmax(list(map(box_area, boxes)))]


def get_boxes_by_channel(pred):
    pred_boxes = [[]]
    pred_boxes.append(get_all_boxes(pred[1]))
    pred_body = get_biggest_box(pred_boxes[1])
    for ch in range(2, TOTAL_CLASSES):
        pred_boxes.append(filter_by_intersection(pred_body, get_all_boxes(pred[ch])))
    return pred_boxes


def find_closest_box(box, others, min_dice=0.8):
    ba = box_area(box)
    best_dice = 0
    best_idx = None
    for i, other in enumerate(others):
        dice = 2 * box_inter_area(box, other) / (ba + box_area(other))
        if dice > best_dice:
            best_idx = i
            best_dice = dice
    return best_idx


def classify_boxes(pred_boxes, gold_boxes, strictness=0.8):
    true_positive = []
    false_positive = []

    found_gold = set()
    for i, box in enumerate(pred_boxes):
        closest_gold_i = find_closest_box(box, gold_boxes, min_dice=strictness)
        if not closest_gold_i is None:
            true_positive.append(i)
            found_gold.add(closest_gold_i)
        else:
            false_positive.append(i)

    false_negative = set(range(len(gold_boxes))) - found_gold
    return (true_positive, false_positive, false_negative)


def calc_precision(tp, fp, fn):
    denom = float(tp + fp)
    return (tp / denom) if denom > 1e-4 else 0


def calc_recall(tp, fp, fn):
    denom = float(tp + fn)
    return (tp / denom) if denom > 1e-4 else 0


def box_match_single_image(pred, gold_boxes, metric, strictness=0.8):
    pred_boxes = get_boxes_by_channel(pred)
    result = []
    for ch in range(pred.shape[0]):
        tp, fp, fn = classify_boxes(pred_boxes[ch],
                                    gold_boxes.get(ch, []),
                                    strictness=strictness)
        tp, fp, fn = len(tp), len(fp), len(fn)
        result.append(metric(tp, fp, fn))
    return result

def box_match_batch(pred, gold_boxes, metric, strictness=0.8):
    if not isinstance(pred, numpy.ndarray):
        pred = pred.data.cpu().numpy()
    image_metrics = [box_match_single_image(pred[i],
                                            gold_boxes[i],
                                            metric,
                                            strictness=strictness)
                     for i in range(pred.shape[0])]
    return numpy.array(image_metrics).mean(0)


def box_match_precision(pred, target, gold_boxes, strictness=0.8):
    return box_match_batch(pred, gold_boxes, calc_precision, strictness=strictness)


def box_match_recall(pred, target, gold_boxes, strictness=0.8):
    return box_match_batch(pred, gold_boxes, calc_recall, strictness=strictness)

# box_match_precision(numpy.tile(numpy.array([[[[1, 1, 1, 1], [1, 1, 1, 1]]]]), (1, 5, 1, 1)),
#                     None,
#                     [{2 : [[0, 0, 2, 4]]}])

Fuzzy

$Dice(p, t, w) = 1 - \frac{ p \cdot t + 1 }{ p + t + 1 }$

$WDice(p, t, w) = 1 - \frac{ p \cdot t \cdot w^{-1} + 1 }{ p + t + p \cdot (1 - t) \cdot w + 1 }$


In [12]:
DICE_SMOOTH = 1.0
def dice_coef(pred, target, gold_boxes):
    intersection = pred * target
    union = pred + target
    return ((2. * intersection.sum(3).sum(2).sum(0) + DICE_SMOOTH) /
            (union.sum(3).sum(2).sum(0) + DICE_SMOOTH))


def px_precision(pred, target, threshold=0.5):
    pred = pred >= threshold
    target = target >= threshold
    tp = (pred * target).float().sum(3).sum(2).sum(0)
    fp = ((target - pred) < 0).float().sum(3).sum(2).sum(0)
    denum = tp + fp
    return tp / (denum + (denum == 0).float())


def px_recall(pred, target, threshold=0.5):
    pred = pred >= threshold
    target = target >= threshold
    tp = (pred * target).float().sum(3).sum(2).sum(0)
    fn = ((pred - target) < 0).float().sum(3).sum(2).sum(0)
    denum = tp + fn
    return tp / (denum + (denum == 0).float())


def make_single_channel(f, channel):
    def _impl(pred, target):
        return f(pred[:, channel:channel+1], target[:, channel:channel+1])
    return _impl


def make_cpu(f):
    def _impl(pred, target):
        return f(pred.cpu(), target.cpu())
    return _impl


METRICS_DIMENSIONS_MEANING = (None, 'area', 'cell', 'rows', 'cols')
METRICS = {'d' : (dice_coef, METRICS_DIMENSIONS_MEANING),
#            'bp' : (box_match_precision, METRICS_DIMENSIONS_MEANING),
#            'br' : (box_match_recall, METRICS_DIMENSIONS_MEANING),
#            'p' : px_precision,
#            'r' : px_recall
           }
# for channel in range(1, TOTAL_CLASSES):
#     METRICS['d{}'.format(channel)] = make_single_channel(make_cpu(dice_coef), channel)
#     METRICS['pp{}'.format(channel)] = make_single_channel(px_precision, channel)
#     METRICS['pr{}'.format(channel)] = make_single_channel(px_recall, channel)

Losses


In [13]:
def dice_loss(pred, target, weights):
    intersection = pred * target
    union = pred + target
    return 1 - ((2. * intersection.sum() + DICE_SMOOTH) /
                (union.sum() + DICE_SMOOTH))


def weighted_dice_loss(pred, target, weights):
    # the idea is to lower actual intersection in important areas
    inv_weights = 1 / weights
    intersection = pred * inv_weights * target
    
    # the idea is to increase actual predicted values
    # where they have to be zero
    inv_target = 1 - target
    inv_intersection = pred * inv_target * weights
    union = pred + target + inv_intersection

    return 1 - ((2. * intersection.sum() + DICE_SMOOTH) /
                (union.sum() + DICE_SMOOTH))


def dice_bce_loss(pred, target, weights):
    return dice_loss(pred, target, weights) + F.binary_cross_entropy(pred, target, weights)

Train


In [14]:
def mcuda(x, cuda):
    return x.cuda() if cuda else x


def npten(arr, cuda):
    return mcuda(torch.from_numpy(arr), cuda)


def npvar(arr, cuda):
    if not torch.is_tensor(arr):
        arr = torch.from_numpy(arr)
    return mcuda(Variable(arr), cuda)


def run_network(network, generator, num_batches, criterion=dice_bce_loss, optimizer=None, cuda=True):
    metrics = []
    gen_iter = iter(generator)
    for _ in tqdm.tqdm(range(num_batches)):
        image_ids, images, mask, loss_weights, boxes = next(gen_iter)
        images_var = npvar(images, cuda)
        mask_var = npvar(mask, cuda)
        loss_weights_var = npvar(loss_weights, cuda)
        boxes = [pickle.loads(b) for b in boxes]

        cur_out = network(images_var)

        loss = criterion(cur_out, mask_var, loss_weights_var)

        if optimizer:
            optimizer.zero_grad()
            loss.backward()
            nn.utils.clip_grad_norm(network.parameters(), 10)
            optimizer.step()

        cur_metrics = { 'loss' : loss.data[0] }
        for name, (func, elem_names) in METRICS.items():
            metric_value = func(cur_out, mask_var, boxes)
            if not isinstance(metric_value, (list, numpy.ndarray)):
                metric_value = metric_value.cpu().data.numpy()
            cur_metrics.update(('\n'.join((name, n)), v) for n, v in zip(elem_names, metric_value) if n)
        metrics.append(cur_metrics)
    return metrics

Run


In [15]:
train_gen = None
val_gen = None

EPOCHS_NUM = 60
BATCH_SIZE = 16
PART_PER_EPOCH = 0.5
BATCHES_PER_EPOCH_TRAIN = int(len(train_image_ids) * PART_PER_EPOCH / BATCH_SIZE)
BATCHES_PER_EPOCH_VAL = int(len(val_image_ids) * PART_PER_EPOCH // BATCH_SIZE)

# train_gen = data_gen(train_image_ids, imgaug_pipeline, batch_size=BATCH_SIZE)
# val_gen = data_gen(val_image_ids, imgaug_pipeline, batch_size=BATCH_SIZE)


net = UNet(first_conv_channels=8,
           depth=3,
           enc_dilations=[1]).cuda()
# LOSS = dice_bce_loss
# LOSS = dice_loss
LOSS = weighted_dice_loss
print('total parameters', sum(numpy.product(p.size()) for p in net.parameters()))

train_metrics = []
val_metrics = []
for epoch in range(EPOCHS_NUM):
    try:
        train_gen = DataLoader(SegmDataset(train_image_ids, imgaug_pipeline),
                               batch_size=BATCH_SIZE,
                               shuffle=True,
                               num_workers=4)
        val_gen = DataLoader(SegmDataset(val_image_ids, imgaug_pipeline),
                             batch_size=BATCH_SIZE,
                             shuffle=True,
                             num_workers=2)
        print('epoch', epoch)

        lr_factor = 0.5 ** (epoch // 20)
        lr = 1e-3 * lr_factor
        print('lr', lr)
        optimizer = Adam(net.parameters(), lr=lr)

        net.train()
        cur_train_metrics = run_network(net, train_gen, BATCHES_PER_EPOCH_TRAIN,
                                        criterion=LOSS,
                                        optimizer=optimizer)
        train_metrics.extend(cur_train_metrics)
        display(pandas.DataFrame(cur_train_metrics).describe().loc[['mean', 'std']])

        net.eval()
        cur_val_metrics = run_network(net, val_gen, BATCHES_PER_EPOCH_VAL,
                                      criterion=LOSS)
        val_metrics.extend(cur_val_metrics)
        display(pandas.DataFrame(cur_val_metrics).describe().loc[['mean', 'std']])
    finally:
        if train_gen:
            del train_gen
        if val_gen:
            del val_gen


total parameters 60423
epoch 0
lr 0.001
100%|██████████| 75/75 [00:42<00:00,  1.76it/s]
d area d cell d cols d rows loss
mean 0.377635 0.151276 0.367543 0.146761 0.865857
std 0.081692 0.028460 0.095364 0.052462 0.038225
100%|██████████| 18/18 [00:12<00:00,  1.44it/s]
d area d cell d cols d rows loss
mean 0.506821 0.200598 0.538252 0.261781 0.793365
std 0.031868 0.012992 0.030592 0.019088 0.016962
epoch 1
lr 0.001
100%|██████████| 75/75 [00:44<00:00,  1.67it/s]
d area d cell d cols d rows loss
mean 0.702750 0.307249 0.749642 0.378293 0.648785
std 0.127376 0.079954 0.114463 0.084669 0.102993
100%|██████████| 18/18 [00:13<00:00,  1.31it/s]
d area d cell d cols d rows loss
mean 0.902227 0.437700 0.889189 0.536584 0.464065
std 0.010868 0.018483 0.011694 0.018910 0.013472
epoch 2
lr 0.001
100%|██████████| 75/75 [00:46<00:00,  1.60it/s]
d area d cell d cols d rows loss
mean 0.944422 0.500854 0.900044 0.646998 0.357422
std 0.017636 0.030582 0.010999 0.048276 0.053050
100%|██████████| 18/18 [00:13<00:00,  1.38it/s]
d area d cell d cols d rows loss
mean 0.944087 0.537337 0.890840 0.673273 0.293871
std 0.010262 0.011046 0.009835 0.011767 0.007480
epoch 3
lr 0.001
100%|██████████| 75/75 [00:48<00:00,  1.56it/s]
d area d cell d cols d rows loss
mean 0.966722 0.697317 0.909088 0.668369 0.230084
std 0.008996 0.090282 0.010636 0.017997 0.032759
100%|██████████| 18/18 [00:12<00:00,  1.41it/s]
d area d cell d cols d rows loss
mean 0.295192 0.576386 0.265540 0.384663 0.822027
std 0.036010 0.024905 0.034669 0.023222 0.024292
epoch 4
lr 0.001
  7%|▋         | 5/75 [00:04<01:05,  1.06it/s]Process Process-20:
Process Process-17:
Process Process-6:
Process Process-22:
Process Process-2:
Process Process-18:
Process Process-21:
Process Process-4:
Process Process-1:
Process Process-16:
Process Process-23:
Process Process-5:
Process Process-7:
Process Process-11:
Process Process-8:
Process Process-14:
Process Process-10:
Process Process-15:
Process Process-12:
Process Process-9:
Process Process-13:
Process Process-3:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 44, in _worker_loop
    data_queue.put((idx, samples))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 397, in _send_bytes
    self._send(header)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 354, in put
    with self._wlock:
KeyboardInterrupt
KeyboardInterrupt
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
KeyboardInterrupt
KeyboardInterrupt
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 398, in _send_bytes
    self._send(buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 397, in _send_bytes
    self._send(header)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
KeyboardInterrupt
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 355, in put
    self._writer.send_bytes(obj)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 398, in _send_bytes
    self._send(buf)
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 398, in _send_bytes
    self._send(buf)
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 397, in _send_bytes
    self._send(header)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
KeyboardInterrupt
KeyboardInterrupt
KeyboardInterrupt
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 398, in _send_bytes
    self._send(buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
    self._send_bytes(m[offset:offset + size])
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 398, in _send_bytes
    self._send(buf)
KeyboardInterrupt
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 368, in _send
    n = write(self._handle, buf)
KeyboardInterrupt
ERROR:root:Internal Python error in the inspect module.
Below is the traceback from this internal error.

Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2910, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-15-04393183b9d4>", line 44, in <module>
    optimizer=optimizer)
  File "<ipython-input-14-a11e8ef91bf5>", line 19, in run_network
    image_ids, images, mask, loss_weights, boxes = next(gen_iter)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 195, in __next__
    idx, batch = self.data_queue.get()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/queues.py", line 343, in get
    res = self._reader.recv_bytes()
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 216, in recv_bytes
    buf = self._recv_bytes(maxlength)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 407, in _recv_bytes
    buf = self._recv(4)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/multiprocessing/connection.py", line 379, in _recv
    chunk = read(handle, remaining)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 1828, in showtraceback
    stb = value._render_traceback_()
AttributeError: 'KeyboardInterrupt' object has no attribute '_render_traceback_'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/IPython/core/ultratb.py", line 1090, in get_records
    return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/IPython/core/ultratb.py", line 311, in wrapped
    return f(*args, **kwargs)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/site-packages/IPython/core/ultratb.py", line 345, in _fixed_getinnerframes
    records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 1454, in getinnerframes
    frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 1411, in getframeinfo
    filename = getsourcefile(frame) or getfile(frame)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 666, in getsourcefile
    if getattr(getmodule(object, filename), '__loader__', None) is not None:
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 709, in getmodule
    f = getabsfile(module)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 678, in getabsfile
    _filename = getsourcefile(object) or getfile(object)
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/inspect.py", line 663, in getsourcefile
    if os.path.exists(filename):
  File "/root/.pyenv/versions/3.6.0/lib/python3.6/genericpath.py", line 19, in exists
    os.stat(path)
KeyboardInterrupt
---------------------------------------------------------------------------

Plot metrics


In [ ]:
train_metrics = pandas.DataFrame(train_metrics)
val_metrics = pandas.DataFrame(val_metrics)

In [ ]:
pandas.rolling_mean(train_metrics, 100).plot(figsize=(13, 8))

In [ ]:
pandas.rolling_mean(val_metrics, 100).plot(figsize=(13, 8))

Predict and visualize


In [ ]:
# torch.save(net, 'models/torch1')

In [ ]:
test_net = torch.load('models/torch1').cpu()

In [ ]:
# test_net = net.cpu()

In [ ]:
test_batch = prepare_batch(val_image_ids[:10], imgaug_pipeline)
test_pred = test_net(npvar(test_batch[1], False))
test_pred_np = test_pred.cpu().data.numpy()

In [ ]:
arr_to_img((test_batch[3][3][2] / test_batch[3][3][2].max()) + test_batch[2][3][2])

In [ ]:
arr_to_img(test_batch[1][6][0])

In [ ]:
arr_to_img(test_pred_np[6][4])

In [ ]:
arr_to_img((test_pred_np[6][1] > 0.5).astype('uint8'))