Loading

Mask Prediction

Solution for submission 174985

A detailed solution for submission 174985 submitted for challenge Mask Prediction

jakub_bartczuk
In [91]:
%%capture
!pip install aicrowd-cli

%load_ext aicrowd.magic
In [ ]:
!python main_train.py --model_type fasterrcnn --config_path fasterrcnn.yaml
FasterRCNNConfig(
  datasets: <deepsense_vision.models.data_config.DataConfig object at 0x7f2859a42790>,
  name: 'Faster R-CNN',
  num_input_channels: 3,
  normalization_shift: [-0.485, -0.456, -0.406],
  normalization_scale: [4.367, 4.364, 4.444],
  anchor_sizes: [[32], [64], [128], [256], [512]],
  aspect_ratios: [[0.5, 1.0, 2.0], [0.5, 1.0, 2.0], [0.5, 1.0, 2.0], [0.5, 1.0, 2.0], [0.5, 1.0, 2.0]],
  classnames: ['N95', 'surgical', 'cloth', 'KN95'],
  pretrained_weights_COCO: True,
  pretrained_checkpoint_filepath: None,
  pretrained_weights_filepath: None,
  experiment_dirpath: 'experiments/20220221_230917_676936_faster_rcnn_training_1_epochs',
  num_train_iters: 1500,
  verbose_freq_iters: 100,
  train_batch_size: 4,
  train_transformations: ['resize(512,512)'],
  init_lr: 0.0001,
  lr_step_size: 1500,
  lr_gamma: 0.5,
  num_train_dataloader_workers: 0,
  class_balanced_sampling: False,
  multi_gpu: False,
  device: 'cuda',
  valid_freq_iters: 1000,
  valid_batch_size: 8,
  valid_transformations: ['resize(512,512)'],
  num_valid_dataloader_workers: 0,
  maximized_global_metric_name: 'f1',
  metric_iou_threshold: 0.5,
  metric_class_proba_thresholds: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
  neptune_experiment_name: 'Faster R-CNN training',
  neptune_project_name: None,
  neptune_send_classwise_metrics: False,
  inference_preprocessing_longer_axis_size: 1200,
  inference_preprocessing_padding_min_image_height: None,
  inference_preprocessing_padding_min_image_width: None,
  inference_class_proba_thresholds: [],
  inference_nms_overlap_threshold: 0.5,
  inference_box_proba_threshold: 0.5,
  inference_sliding_window: False,
  inference_sliding_window_height: 1024,
  inference_sliding_window_width: 1024,
  inference_sliding_window_min_height_overlap: 0,
  inference_sliding_window_min_width_overlap: 0,
  inference_sliding_window_batch_size: 8,
)
Creating experiment dirpath experiments/20220221_230917_676936_faster_rcnn_training_1_epochs...
Experiment dirpath experiments/20220221_230917_676936_faster_rcnn_training_1_epochs created successfully!
DeepsenseDataset: loading annotations...
DeepsenseDataset: 5600 annotations (5600 namedboxes + 0 namedmasks + 0 namedkeypoints) for 5600 metapoints loaded successfully!
DeepsenseDataset: loading annotations...
DeepsenseDataset: 2400 annotations (2400 namedboxes + 0 namedmasks + 0 namedkeypoints) for 2400 metapoints loaded successfully!
Initializing FasterRCNN from pretrained COCO weights...
load_state_dict_greedily: len(source_state_dict) = 295
load_state_dict_greedily: len(target_state_dict) = 295
load_state_dict_greedily: Source tensor reshaped from [91, 1024] to [5, 1024] for 'roi_heads.box_predictor.cls_score.weight' successfully!
load_state_dict_greedily: Source tensor reshaped from [91] to [5] for 'roi_heads.box_predictor.cls_score.bias' successfully!
load_state_dict_greedily: Source tensor reshaped from [364, 1024] to [20, 1024] for 'roi_heads.box_predictor.bbox_pred.weight' successfully!
load_state_dict_greedily: Source tensor reshaped from [364] to [20] for 'roi_heads.box_predictor.bbox_pred.bias' successfully!
load_state_dict_greedily: Initialized 295/295 tensors from source_state_dict successfully!
FasterRCNN initialized from pretrained COCO weights successfully!
Train FasterRCNNDataloader created for DeepsenseDataset successfully!
Valid FasterRCNNDataloader created for DeepsenseDataset successfully!
Training: :   0%|                                      | 0/1500 [00:00<?, ?it/s]/home/kuba/.local/lib/python3.8/site-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at  /pytorch/c10/core/TensorImpl.h:1156.)
  return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
train_loss_values(iteration=100): mean_loss_objectness=0.000806, mean_loss_rpn_box_reg=0.001160, mean_loss_classifier=0.030577, mean_loss_box_reg=0.026976, mean_total_loss=0.059519
Training: :   8%|██                          | 113/1500 [00:25<05:17,  4.37it/s]
In [ ]:

!rm -rf data !mkdir data %aicrowd ds dl -c mask-prediction -o data

!unzip data/train.zip -d data/train > /dev/null !unzip data/val.zip -d data/val > /dev/null !unzip data/test.zip -d data/test > /dev/null

yolov3.yaml

datasets: train: metadata_path: train_metadata.json dataset_format: deepsense valid: metadata_path: val_metadata.json dataset_format: deepsense classnames:

  • N95
  • surgical
  • cloth
  • KN95 input_height: 256 input_width: 256 experiment_dirpath: experiments/yolov3_training num_train_iters: 2000 valid_freq_iters: 200 verbose_freq_iters: 100 lr_step_size: 200 timestamped: True train_transformations: ["resize(256,256)"] valid_transformations: ["resize(256,256)"]
In [64]:
#Reading the file
import pandas as pd
import numpy as np
import os
from pathlib import Path

# Image Reading & Preprocessing
from PIL import Image, ImageDraw
import cv2
import matplotlib.pyplot as plt
import numpy as np

# Misc.
from tqdm.notebook import tqdm
from sklearn.ensemble import RandomForestClassifier
In [65]:
train_images = 'data/train'
val_images = 'data/val'
test_images = 'data/test'
In [66]:
train_df = pd.read_csv("data/train.csv")
val_df = pd.read_csv("data/val.csv")
In [67]:
train_df.head()
Out[67]:
ImageID bbox masktype
0 k8o0f [73, 197, 293, 400] N95
1 7a0l9 [47, 364, 300, 512] surgical
2 wfp7p [203, 221, 380, 403] N95
3 7qaw6 [87, 210, 322, 385] surgical
4 i4kqj [227, 283, 479, 475] surgical
In [68]:
from ast import literal_eval
In [69]:
def create_bboxes(row):
    bbox_coords = literal_eval(row['bbox'])
    bbox = {"xmin": bbox_coords[0], "ymin": bbox_coords[1], "xmax": bbox_coords[2], "ymax": bbox_coords[3]}
    bbox['classname'] = row['masktype']
    bbox['probability'] = None
    return bbox
In [70]:
def create_item_metadata(image_path, row):
    item_metadata = {
        'image_path': str(Path(image_path) / (row['ImageID'] + ".jpg")),
        'namedboxes': [create_bboxes(row)],
        'namedmasks': [],
        'namedkeypoints': [],
        'image_classnames': []
    }
    return item_metadata
In [71]:
def create_dsvision_metadata(image_path, metadata_df):
    items = []
    for idx, row in metadata_df.iterrows():
        item_metadata = create_item_metadata(image_path, row) 
        items.append(item_metadata)
    return items
In [72]:
train_dsvision_metadata = create_dsvision_metadata(train_images, train_df)
val_dsvision_metadata = create_dsvision_metadata(val_images, val_df)
In [73]:
import json
In [74]:
json.dump(train_dsvision_metadata, open("train_metadata.json", "w"))
json.dump(val_dsvision_metadata, open("val_metadata.json", "w"))
In [75]:
for i in train_df['masktype'].unique():
    print("  - "+ i)
  - N95
  - surgical
  - cloth
  - KN95
In [76]:
import deepsense_vision
In [77]:
from deepsense_vision.datasets.deepsense_dataset import DeepsenseDataset
from deepsense_vision.io import load_json
from deepsense_vision.models.fasterrcnn.fasterrcnn_model import FasterRCNNModel
from deepsense_vision.models.yolov3.yolov3_model import YOLOv3Model 
from deepsense_vision.models.patchnet.patchnet_model import PatchNetModel
In [78]:
model = FasterRCNNModel()
In [79]:
!ls experiments/
20220205_223246_382917_yolov3_training
20220205_223330_776621_yolov3_training
20220205_223339_241858_yolov3_training
20220205_223533_778631_yolov3_training
20220205_223741_918155_faster_rcnn_training
20220205_224450_772442_faster_rcnn_training
20220210_095034_495233_faster_rcnn_training_1000
20220210_100434_304281_faster_rcnn_training_1000
20220210_100929_544292_faster_rcnn_training_1000
20220210_102822_739059_faster_rcnn_training_1000
20220210_123813_391604_faster_rcnn_training_1000
20220210_124238_344077_faster_rcnn_training_1000
20220210_131831_950098_faster_rcnn_training_1000
20220210_131900_003460_faster_rcnn_training_1000
20220210_132502_345197_faster_rcnn_training_1000
20220220_125123_037227_faster_rcnn_training_1000
20220220_132202_290708_faster_rcnn_training_3000
20220220_132405_347105_faster_rcnn_training_3000
20220221_170343_760904_faster_rcnn_training_3000
20220221_170440_413860_faster_rcnn_training_6000
20220221_170902_483068_faster_rcnn_training_6000
20220221_172141_860248_faster_rcnn_training_5_epochs
20220221_180208_943154_faster_rcnn_training_5_epochs
In [80]:
import pathlib


def load_results_from_config_path(experiment_path):
    results_path = pathlib.Path(experiment_path) / "checkpoint" / "valid_metrics.json"
    if os.path.exists(results_path):
        return json.load(open(str(results_path), "r"))['global']
    else:
        return None
In [81]:
!ls 20220210_124238_344077_faster_rcnn_training_1000/
ls: cannot access '20220210_124238_344077_faster_rcnn_training_1000/': No such file or directory
In [82]:
load_results_from_config_path("experiments/20220210_124238_344077_faster_rcnn_training_1000")
Out[82]:
{'num_true_positives': 2393,
 'num_false_positives': 4,
 'num_false_negatives': 7,
 'precision': 0.9983312473925741,
 'recall': 0.9970833333333333,
 'f1': 0.9977069001459244,
 'mAP': 0.9248538594789876,
 'mAP@.50': 0.9925660609507732,
 'mAP@.75': 0.9925660609507732}
In [83]:
import glob
In [84]:
experiment_results_jsons = {
    config_path: load_results_from_config_path(config_path)
    for config_path in glob.glob("experiments/*")
}
In [85]:
experiment_results_jsons
Out[85]:
{'experiments/20220210_132502_345197_faster_rcnn_training_1000': {'num_true_positives': 2390,
  'num_false_positives': 2,
  'num_false_negatives': 10,
  'precision': 0.9991638795986622,
  'recall': 0.9958333333333333,
  'f1': 0.9974958263772955,
  'mAP': 0.9280093848690896,
  'mAP@.50': 0.9925474773134191,
  'mAP@.75': 0.9925474773134191},
 'experiments/20220210_095034_495233_faster_rcnn_training_1000': {'num_true_positives': 2388,
  'num_false_positives': 6,
  'num_false_negatives': 12,
  'precision': 0.9974937343358395,
  'recall': 0.995,
  'f1': 0.9962453066332916,
  'mAP': 0.872780488748457,
  'mAP@.50': 0.9900864663452082,
  'mAP@.75': 0.9900864663452082},
 'experiments/20220205_223533_778631_yolov3_training': {'num_true_positives': 2270,
  'num_false_positives': 227,
  'num_false_negatives': 130,
  'precision': 0.9090909090909091,
  'recall': 0.9458333333333333,
  'f1': 0.9270982234020828,
  'mAP': 0.5916627182501502,
  'mAP@.50': 0.9338058821017383,
  'mAP@.75': 0.6805214393140011},
 'experiments/20220210_124238_344077_faster_rcnn_training_1000': {'num_true_positives': 2393,
  'num_false_positives': 4,
  'num_false_negatives': 7,
  'precision': 0.9983312473925741,
  'recall': 0.9970833333333333,
  'f1': 0.9977069001459244,
  'mAP': 0.9248538594789876,
  'mAP@.50': 0.9925660609507732,
  'mAP@.75': 0.9925660609507732},
 'experiments/20220210_131900_003460_faster_rcnn_training_1000': None,
 'experiments/20220221_170902_483068_faster_rcnn_training_6000': {'num_true_positives': 2393,
  'num_false_positives': 2,
  'num_false_negatives': 7,
  'precision': 0.9991649269311065,
  'recall': 0.9970833333333333,
  'f1': 0.9981230448383733,
  'mAP': 0.9644892288986135,
  'mAP@.50': 0.9925703958851424,
  'mAP@.75': 0.9925703958851424},
 'experiments/20220205_223330_776621_yolov3_training': None,
 'experiments/20220220_125123_037227_faster_rcnn_training_1000': {'num_true_positives': 2392,
  'num_false_positives': 2,
  'num_false_negatives': 8,
  'precision': 0.9991645781119465,
  'recall': 0.9966666666666667,
  'f1': 0.9979140592407175,
  'mAP': 0.9617677728847683,
  'mAP@.50': 0.9900990099009901,
  'mAP@.75': 0.9900990099009901},
 'experiments/20220220_132202_290708_faster_rcnn_training_3000': None,
 'experiments/20220220_132405_347105_faster_rcnn_training_3000': {'num_true_positives': 2394,
  'num_false_positives': 5,
  'num_false_negatives': 6,
  'precision': 0.9979157982492706,
  'recall': 0.9975,
  'f1': 0.9977078558032925,
  'mAP': 0.8796662978591018,
  'mAP@.50': 0.9925550694604344,
  'mAP@.75': 0.9921259109578942},
 'experiments/20220210_102822_739059_faster_rcnn_training_1000': {'num_true_positives': 2392,
  'num_false_positives': 5,
  'num_false_negatives': 8,
  'precision': 0.9979140592407175,
  'recall': 0.9966666666666667,
  'f1': 0.997289972899729,
  'mAP': 0.9145797292044506,
  'mAP@.50': 0.9925588832175143,
  'mAP@.75': 0.9925588832175143},
 'experiments/20220210_100929_544292_faster_rcnn_training_1000': {'num_true_positives': 2391,
  'num_false_positives': 2,
  'num_false_negatives': 9,
  'precision': 0.9991642290012537,
  'recall': 0.99625,
  'f1': 0.9977049864385562,
  'mAP': 0.9363608528925254,
  'mAP@.50': 0.9900990099009901,
  'mAP@.75': 0.9900820950213458},
 'experiments/20220205_223741_918155_faster_rcnn_training': {'num_true_positives': 2380,
  'num_false_positives': 9,
  'num_false_negatives': 20,
  'precision': 0.996232733361239,
  'recall': 0.9916666666666667,
  'f1': 0.9939444560451034,
  'mAP': 0.9162001458772803,
  'mAP@.50': 0.99002343755731,
  'mAP@.75': 0.9899898748790084},
 'experiments/20220221_172141_860248_faster_rcnn_training_5_epochs': {'num_true_positives': 2394,
  'num_false_positives': 3,
  'num_false_negatives': 6,
  'precision': 0.9987484355444305,
  'recall': 0.9975,
  'f1': 0.9981238273921201,
  'mAP': 0.9230619793275505,
  'mAP@.50': 0.9925474773134191,
  'mAP@.75': 0.9784664292591042},
 'experiments/20220210_131831_950098_faster_rcnn_training_1000': None,
 'experiments/20220221_180208_943154_faster_rcnn_training_5_epochs': {'num_true_positives': 2395,
  'num_false_positives': 2,
  'num_false_negatives': 5,
  'precision': 0.999165623696287,
  'recall': 0.9979166666666667,
  'f1': 0.9985407546383157,
  'mAP': 0.9049175808505268,
  'mAP@.50': 0.9949822656289398,
  'mAP@.75': 0.968016391540086},
 'experiments/20220205_223246_382917_yolov3_training': None,
 'experiments/20220221_170440_413860_faster_rcnn_training_6000': {'num_true_positives': 2391,
  'num_false_positives': 4,
  'num_false_negatives': 9,
  'precision': 0.998329853862213,
  'recall': 0.99625,
  'f1': 0.997288842544317,
  'mAP': 0.8400651423265474,
  'mAP@.50': 0.9900990099009901,
  'mAP@.75': 0.9900362146109236},
 'experiments/20220205_223339_241858_yolov3_training': None,
 'experiments/20220205_224450_772442_faster_rcnn_training': {'num_true_positives': 2388,
  'num_false_positives': 9,
  'num_false_negatives': 12,
  'precision': 0.9962453066332916,
  'recall': 0.995,
  'f1': 0.9956222639149468,
  'mAP': 0.9831449733226844,
  'mAP@.50': 0.9900990099009901,
  'mAP@.75': 0.9900990099009901},
 'experiments/20220210_100434_304281_faster_rcnn_training_1000': None,
 'experiments/20220221_170343_760904_faster_rcnn_training_3000': None,
 'experiments/20220210_123813_391604_faster_rcnn_training_1000': {'num_true_positives': 2375,
  'num_false_positives': 41,
  'num_false_negatives': 25,
  'precision': 0.9830298013245033,
  'recall': 0.9895833333333334,
  'f1': 0.9862956810631229,
  'mAP': 0.8646274964094278,
  'mAP@.50': 0.9923131491675302,
  'mAP@.75': 0.9923088593104682}}
In [86]:
experiment_results = [
    {"experiment": path, **{k: v for (k,v) in results.items() if "mAP" in k}}
    for (path, results) in experiment_results_jsons.items()
    if not results is None
]
In [87]:
experiments_df = pd.DataFrame.from_records(experiment_results).sort_values("mAP", ascending=False)
In [88]:
experiments_df.index = experiments_df['experiment']
In [89]:
experiments_df.sort_values("mAP", ascending=False)
Out[89]:
experiment mAP mAP@.50 mAP@.75
experiment
experiments/20220205_224450_772442_faster_rcnn_training experiments/20220205_224450_772442_faster_rcnn... 0.983145 0.990099 0.990099
experiments/20220221_170902_483068_faster_rcnn_training_6000 experiments/20220221_170902_483068_faster_rcnn... 0.964489 0.992570 0.992570
experiments/20220220_125123_037227_faster_rcnn_training_1000 experiments/20220220_125123_037227_faster_rcnn... 0.961768 0.990099 0.990099
experiments/20220210_100929_544292_faster_rcnn_training_1000 experiments/20220210_100929_544292_faster_rcnn... 0.936361 0.990099 0.990082
experiments/20220210_132502_345197_faster_rcnn_training_1000 experiments/20220210_132502_345197_faster_rcnn... 0.928009 0.992547 0.992547
experiments/20220210_124238_344077_faster_rcnn_training_1000 experiments/20220210_124238_344077_faster_rcnn... 0.924854 0.992566 0.992566
experiments/20220221_172141_860248_faster_rcnn_training_5_epochs experiments/20220221_172141_860248_faster_rcnn... 0.923062 0.992547 0.978466
experiments/20220205_223741_918155_faster_rcnn_training experiments/20220205_223741_918155_faster_rcnn... 0.916200 0.990023 0.989990
experiments/20220210_102822_739059_faster_rcnn_training_1000 experiments/20220210_102822_739059_faster_rcnn... 0.914580 0.992559 0.992559
experiments/20220221_180208_943154_faster_rcnn_training_5_epochs experiments/20220221_180208_943154_faster_rcnn... 0.904918 0.994982 0.968016
experiments/20220220_132405_347105_faster_rcnn_training_3000 experiments/20220220_132405_347105_faster_rcnn... 0.879666 0.992555 0.992126
experiments/20220210_095034_495233_faster_rcnn_training_1000 experiments/20220210_095034_495233_faster_rcnn... 0.872780 0.990086 0.990086
experiments/20220210_123813_391604_faster_rcnn_training_1000 experiments/20220210_123813_391604_faster_rcnn... 0.864627 0.992313 0.992309
experiments/20220221_170440_413860_faster_rcnn_training_6000 experiments/20220221_170440_413860_faster_rcnn... 0.840065 0.990099 0.990036
experiments/20220205_223533_778631_yolov3_training experiments/20220205_223533_778631_yolov3_trai... 0.591663 0.933806 0.680521
In [28]:
#pathlib.Path("experiments/20220210_100929_544292_faster_rcnn_training_1000")
best_model_dir =  pathlib.Path(experiments_df['mAP'].idxmax())
best_model_path = best_model_dir / "checkpoint" / "fasterrcnn.pt"
In [29]:
model.load_checkpoint(str(best_model_path))
Loading from experiments/20220205_224450_772442_faster_rcnn_training/checkpoint/fasterrcnn.pt...
FasterRCNN loaded from experiments/20220205_224450_772442_faster_rcnn_training/checkpoint/fasterrcnn.pt successfully!
In [30]:
model.to_gpu()
In [31]:
from pathlib import Path
In [ ]:
test_image_paths =  list(map(str, Path("data/test/").glob("*")))
In [ ]:
import skimage.io
import skimage.transform
In [ ]:
test_image_paths[0]
In [ ]:
test_img = skimage.io.imread(test_image_paths[0])
In [ ]:
test_img.shape
In [ ]:
plt.imshow(test_img)
In [ ]:
model.config.inference_preprocessing_longer_axis_size =  512 
model.config.inference_preprocessing_padding_min_image_height = 512 
model.config.inference_preprocessing_padding_min_image_width =  512 
model.config.inference_preprocessing_longer_axis_size = 512 
model.config.inference_sliding_window_height = 512 
model.config.inference_sliding_window_width = 512
In [ ]:
test_img.shape
In [ ]:
test_img.transpose(-1, 0, 1).shape
In [ ]:
pred = model.predict_from_array(test_img)
In [ ]:
pred = model.predict_from_filepath(test_image_paths[1])
In [ ]:
pred.visualize()
In [ ]:
import tqdm
import numpy as np
In [ ]:
def convert_box_coords_to_int(box):
    for key in ['xmin', 'xmax', 'ymin', 'ymax']:
        box[key] = int(np.round(box[key]))
In [ ]:
raw_predictions = [
    [box.to_dict() for box in model.predict_from_filepath(str(p)).namedboxes]
    for p in tqdm.tqdm_notebook(test_image_paths)
]
In [ ]:
for pred in raw_predictions:
    for b in pred:
        convert_box_coords_to_int(b)
In [ ]:
raw_predictions[0]
In [ ]:
predictions = [b[0]  if len(b) > 0 else raw_predictions[0][0] for b in raw_predictions]
In [ ]:
def box_to_str(box):
    return "[{}, {}, {}, {}]".format(box['xmin'], box['ymin'], box['xmax'], box['ymax'])
In [ ]:
str_predictions = [box_to_str(b) for b in predictions]
cls_predictions = [b['classname'] for b in predictions]
In [ ]:
idxs = [os.path.splitext(os.path.basename(p))[0] for p in test_image_paths]
In [ ]:
preds_df = pd.DataFrame.from_records(zip(idxs, str_predictions, cls_predictions))
In [ ]:
preds_df.columns = ['ImageID', 'bbox', 'masktype']
In [ ]:
preds_df.to_csv('submission.csv', index=False)
In [ ]:
!cp Masks_DS_Vision.ipynb notebook.ipynb
!zip -r submission.zip notebook.ipynb submission.csv
In [ ]:
!zip -r submission.zip submission/
In [ ]:
#%aicrowd login
In [ ]:
!aicrowd submission create -c mask-prediction -f submission.zip
In [ ]:


Comments

You must login before you can post a comment.

Execute