{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Ensemble v1\n\nEnsemble of Pytorch (0.441) and Keras (0.438) models.\n\n- v1: Siamese CV4-S4-384-512x512x4: 0.728/0.755/0.751/0.752, CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, NoTTA, LB=0.416 / EfficientNet B5-224x224x5 LB=0.402, ENSEMBLE_TOP_N_PER_CELL=4, LB=0.429\n- v2: Siamese CV4-S4-384-512x512x4: 0.728/0.755/0.751/0.752, CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, NoTTA, LB=0.416 / EfficientNet B5-224x224x5 LB=0.402, ENSEMBLE_TOP_N_PER_CELL=8, LB=0.437\n- v3: Siamese CV4-S4-384-512x512x4: 0.728/0.755/0.751/0.752, CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=8, NoTTA, LB=0.420 / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=8, LB=0.447\n- v4: Siamese CV4-S4-384-512x512x4: 0.728/0.755/0.751/0.752, CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=16, NoTTA, LB=0.420 / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=16, ENSEMBLE_THR=0.01, LB=0.449\n- v5: Siamese CV4-S4-384-512x512x4: 0.728/0.755/0.751/0.752, CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.420 / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=0.450\n- v6: Siamese CV4-S2-512-512x512x4/S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.420 / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=\n- v7: Siamese CV4-S2-512-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.420 / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=\n- v8: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-CV5 LB=0.420, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=0.455\n- v9: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-EXT-CV1 LB=0.432, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=0.473\n\n# Per cell generic prediction optimized (GPU)\n\n- v10: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-EXT-CV5 LB=0.444, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=\n- v11: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.444, CL-LB=0.443, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, LB=OOM\n- v12: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.444, CL-LB=0.443, ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=2 (both PT of TF), LB=OOM\n- v13: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.441 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, DELTA=0), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=8 (both PT of TF), LB=0.493\n- v14: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.443 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, DELTA=0, sub-batches added), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=8 (both PT of TF), LB=0.496\n- v15: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.443 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470, DELTA=0, sub-batches added), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4 (both PT of TF), LB=0.50\n- v16: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.443 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470 / EfficientNet B0-224x224x5-CV5 (EXT-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, 0.45/0.45/0.10, LB=0.501\n- v17: Siamese CV4-S4-384-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.443 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470 / EfficientNet B0-224x224x5-CV5 (EXT-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, 0.40/0.50/0.10, LB=0.499\n- v18: Siamese SEResNeXt50-CV4-S1x3-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.457 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, 0.50/0.50, LB=0.517\n- v19: Siamese SEResNeXt50-CV4-S1x3-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.457 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470)/  EfficientNet B0-224x224x5-CV5 (EXT-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, 0.45/0.45/0.10, LB=0.515\n- v20: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=18, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, 0.50/0.50, LB=0.520\n\n# Fixes in NEGATIVE class\n\n- v21: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check removed, 0.50/0.50, LB=**0.533**\n- v22: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=19, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check removed, 0.50/0.50, LB=0.533-\n- v23: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check removed, fix total_class_cam_qt zero issue, 0.50/0.50, LB=0.533\n- v24: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=0.5, fix total_class_cam_qt zero issue, 0.50/0.50, LB=0.533\n- v25: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=0.9, 0.50/0.50, LB=0.533\n- v26: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.005, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=0.99, 0.50/0.50, LB=0.533\n- v27: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.533\n- v28: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=0.8, 0.50/0.50, LB=\n- v29: Siamese SEResNeXt50-CV4-S1x4-EXT-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.461 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) / EfficientNet B0, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.475/0.475/0.05, LB=0.533\n- v30: Siamese SEResNeXt50-CV4-S1x1-89k-epoch31/S1x3-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.474 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.534\n- v31: Siamese SEResNeXt50-CV4-S1x1-89k-epoch43/S1x3-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.474? (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.533\n- v32: Siamese SEResNeXt50-CV4-S1x1-89k/S1x3-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.474? (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.534\n- v33: Siamese SEResNeXt50-CV4-S1x2-89k-epoch36/S1x2-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.494 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.541\n- v34: Siamese SEResNeXt50-CV4-S1x2-89k-epoch39/S1x2-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.494? (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.542\n- v35: Siamese SEResNeXt50-CV4-S1x2-89k/S1x2-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.494? (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.545\n- v36: Siamese SEResNeXt50-CV4-S1x3-89k(fold3-epoch35)/S1x1-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.494? (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.50/0.50, LB=0.550\n- v37: Siamese SEResNeXt50-CV4-S1x3-89k(fold3-epoch35)/S1x1-24k-512x512x4: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.55/0.45, LB=0.553\n- v38: Siamese SEResNeXt50-CV4-S1x4-89k(fold3-epoch35): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.55/0.45, LB=0.554\n- v39: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.60/0.40, LB=0.561\n- v40: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.564\n\n# Class 11 only\n\n- v41: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.017\n\n# Class 15 only\n\n- v42: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.027\n\n# Class 18 only\n\n- v43: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# More models\n\n- v44: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470) / EfficientNetB0-6ch (LB=0.471), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.30/0.05, LB=0.563\n- v45: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470) / EfficientNetB0-6ch (LB=0.471), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.25/0.05, LB=0.564\n- v46: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.565\n- v47: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.75/0.25, LB=0.564\n- v48: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3-6ch, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.25/0.05, LB=0.565\n- v49: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s3-epoch16, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.562\n- v50: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s3-epoch16, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.01, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.562\n\n- v51: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.514 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3-6ch LB=0.476, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.25/0.05, LB=0.565\n\n- v52: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.514 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3-6ch LB=0.476, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.15/0.15, LB=OOM?\n\n- v53: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.514 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3-6ch LB=0.476, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.05/0.25, LB=OOM?\n\n- v54: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.514 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3-6ch LB=0.476, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.15/0.15, SUB_BATCH_SIZE=2 LB=0.564\n\n\n# Class 0 only\n\n- v55: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.043\n\n# Class 16 only\n\n- v56: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.027\n\n\n# (300,300,6) model\n\n- v57: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.514 (full + per cell) / EfficientNet B5-224x224x5-CV5-5ch (EXT-LB=0.475, CL-LB=0.470)/EfficientNetB3x300x300-6ch, ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=2, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.15/0.15, SUB_BATCH_SIZE=2 LB=0.565\n\n\n# Class 13 only\n\n- v58: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.026\n\n# Class 1 only\n\n- v59: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.039\n\n\n# Class 2 only\n\n- v60: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.041\n\n\n# Ensemble with specific class weights\n\n- v61: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, Class 11 from SEResNeXt50 only, LB=0.565-\n\n\n# Class 3 only\n\n- v62: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# Class 4 only\n\n- v63: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n\n# Class 5 only\n\n- v63: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=0.024\n\n\n# Class 6 only\n\n- v64: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n\n# Class 7 only\n\n- v65: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n\n# Class 8 only\n\n- v66: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n\n# Class 9 only\n\n- v67: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# Class 10 only\n\n- v68: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# Class 11 new ensemble\n\n- v68: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022), LB=**0.573**\n\n# New backbone ensemble\n\n- v69: Siamese SEResNeXt50-CV4-S3x1-S1x3-89k/CPResNeXt50-CV4-S1x1 (fold1CSP=epoch21, fold3=epoch35, fold4=epoch47): 0.729/0.823/0.789/798: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.558\n\n- v70: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), Class 4 (0.30/0.70) LB=0.573+\n\n# Class 12 only\n\n- v71: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# Class 14 only\n\n- v72: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# Class 17 only\n\n- v72: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.65/0.35, LB=\n\n# More backbones:\n\n- v73: Siamese SEResNeXt50-CV4-S3x1-S1x3-89k/SEResNeXt101-CV4-S1x1 (fold1=0.1984, fold3=epoch35, fold4=epoch47): 0.78/0.823/0.789/798: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.568\n\n- v74: Siamese SEResNeXt50-CV4-S3x1-S1x3-89k/CSPResNeXt50/SEResNeXt101-CV4-S1x1 (fold1=0.1984, fold3=epoch35, fold4=epoch47): 0.78/0.823/0.789/798: CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, LB=0.567\n\n- v75: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), Class 4 new 360x360 model (0.50/0.50) LB=OOM\n\n- v76: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), Class 4 new 224x224 model (0.50/0.50) LB=0.573++\n\n- v77: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5) + Class4 (0.3/0.7) / Class 4 new 224x224 model (0.50/0.50) LB=0.573+++\n\n- v78: Siamese SEResNeXt50-CV4-x4/SEResNeXt101-CV4-x3-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), LB=0.570\n\n- v79: Siamese SEResNeXt50-CV4-x4/SEResNeXt101-CV4-x3-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.75/0.25, + Class11 (LB=0.022, 0.5/0.5), LB=0.570\n\n- v80: Siamese SEResNeXt50-CV4-x4/SEResNeXt101-CV4-x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), LB=0.569\n\n- v81: SEResNeXt101-CV4-x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47): CLASS_PRED_THR=0.01 / CAM_PRED_QUANTILE=0.99 / SCORE_TH=0.02, TOP_N_PER_IMAGE=18, NoTTA, LB=0.511 (full + per cell) / EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, 0.70/0.30, + Class11 (LB=0.022, 0.5/0.5), LB=0.564\n\n\n# Class 0 only: EfficientNetB5 models only\n\n- v82: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.040\n\n# Class 1 only: EfficientNetB5 models only\n\n- v83: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.036\n\n# Class 18 only: EfficientNetB5 models only\n\n- v84: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.022\n\n# Class 2 only: EfficientNetB5 models only\n\n- v85: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.039\n\n# Class 3 only: EfficientNetB5 models only\n\n- v86: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.020\n\n# Class 4 only: EfficientNetB5 models only\n\n- v87: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.011\n\n# Class 5 only: EfficientNetB5 models only\n\n- v88: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.022\n\n# Green channel model added\n\n- v89: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) + EfficientNet B3-224x224x (green) 0.65/0.25/0.10, LB=**0.577**\n- v90: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) + EfficientNet B3-224x224x (green) 0.60/0.25/0.15, LB=0.576\n- v91: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) + EfficientNet B3-224x224x (green) + EfficientNet B5-224x224x6-CV5 (LB=0.474) 0.65/0.20/0.10/0.05, LB=OOM\n- v91: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) + EfficientNet B5-224x224x6-CV5 (LB=0.474) 0.65/0.25/0.10, LB=0.573\n\n# Class 6 only: EfficientNetB5 models only\n\n- v92: EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470), ENSEMBLE_TOP_N_PER_CELL=19, ENSEMBLE_THR=0.001, SUB_BATCH_SIZE=4, NEGATIVE check improved NEGATIVE_CLASS_ONLY_MIN_THR=1.0, LB=0.020\n\n# More models\n\n- v93: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B5-224x224x5-CV5 (EXT-LB=0.475, CL-LB=0.470) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.15/0.10/0.10, LB=OOM\n- v94: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497)/0.50 (ZFTurbo 0.012) LB=**0.579**\n- v95: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497)/0.50 (ZFTurbo 0.012), Class4 model 0.50(Ensemble)/0.50(ZFTurbo 0.012) LB=0.579+\n- v96: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=**0.581**\n- v97: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), Class4 0.45/0.45/0.10 LB=0.582\n\n# Class 11 only from 0.581\n\n- v98: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.496) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.026\n\n# More models (MSE)\n\n- v99: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.505) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.584\n\n- v100: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.514) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.583\n\n- v101: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.514) 0.55/0.35/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.583\n\n- v102: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-360x360x6(LB=0.513) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.578\n\n- v103: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/CSPResNeXt50-CV4-S1x3-89k + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.505) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.580\n\n- v104: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/CSPResNeXt50-CV4-S1x4-89k + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.505) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=\n\n- v105: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/CSPResNeXt50-CV4-S1x4-89k/SEResNeXt101-CV4-S1x4-89k + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.505) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.577\n\n- v106: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt101-CV4-S1x4-89k + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.505) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.581\n\n- v107: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.584+\n\n- v108: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.518) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.583\n\n- v109: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x6(LB=0.528) + DenseNet121-224x224x6(LB=0.463) + EfficientNet B3-224x224x3(green) 0.65/0.20/0.05/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.582\n\n- v110: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.521) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.583\n\n- v111: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.514) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=\n\n- v112: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + H/V TTA + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.584+\n\n- v113: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + H/V TTA + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.519) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (ZFTurbo 0.012), LB=0.582\n\n- v114: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.50(ZFTurbo 0.497 + MPWARE 0.514)/0.50 (300x300-ZFTurbo 0.019), LB=0.585\n\n- v115: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.60 (300x300-ZFTurbo 0.019), LB=0.585\n\n- v116: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.60 (300x300-ZFTurbo 0.019), Class4(0.60/0.40), LB=0.585+\n\n- v117: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s4-epoch2, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.60 (300x300-ZFTurbo 0.019), LB=0.582\n\n- v118: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=\n\n- v119: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=**0.586**\n\n- v120: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.60(300x300-ZFTurbo 0.019), NEGATIVE mix exclusion added (headx2), LB=0.575\n\n- v121: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x3(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019) NEGATIVE mix exclusion added (tailx2), LB=0.586\n\n- v122: Siamese SEResNeXt50-CV4-S2x1-S3x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47) + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=**0.588**\n\n- v123: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=**0.589**\n\n- v124: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k/SEResNeXt50-CV4-S5x2-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.586\n\n- v125: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.70/0.225/0.075, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.587\n\n- v126: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class0 (0.60/0.40), LB=0.588\n\n- v127: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k/SEResNeXt50-CV4-S5x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.587\n\n- v128: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class1 (0.60/0.40), LB=0.588\n\n- v129: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green) + EfficientNet B3-224x224x6(LB=0.528) 0.65/0.25/0.10, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class2 (0.60/0.40), LB=0.588\n\n- v130: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=**0.590**\n\n- v131: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green/blue,LB=0.482) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.589\n\n- v132: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green, LB=0.460) + EfficientNet B3-224x224x6(green/blue,LB=0.482)+ EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.590-\n\n- v133: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class6 (0.70/0.30), LB=0.589\n\n- v134: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), LB=**0.591**\n\n- v135: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k/SEResNeXt50-512-CV4-S1x2-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), LB=0.587\n\n- v136: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-512-CV4-S1x2-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), LB=\n\n- v137: Siamese SEResNeXt101-CV4-S1x4/SEResNeXt50-CV4-S1x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), LB=\n\n- v138: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S1x4-89k/SEResNeXt101-CV4-S1x4 + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), LB=\n\n- v139: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.60/0.40), LB=0.591-\n\n- v140: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), Class9 (0.70/0.30), LB=\n\n- v141: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k/SEResNeXt50-512-CV4-S1x3-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30), LB=\n\n# Dieter's models added\n\n- v142: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 removed => Final 0.90x(MPWARE+ZFTurbo, LB=0.590)/0.10x(Dieter 2 models LB=0.48), LB=0.593\n\n- v143: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 removed => Final 0.90x(MPWARE+ZFTurbo, LB=0.590)/0.10x(Dieter 4 models LB=0.529), LB=0.593\n\n- v144: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 removed => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=**0.596**\n\n- v145: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 removed => Final 0.80x(MPWARE+ZFTurbo, LB=0.590)/0.10x(Dieter 5 models LB=0.529/0.524), LB=0.595\n\n- v146: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/030) => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=TimeOut\n\n- v147: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S6x3-98k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/030) disabled => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=0.592\n\n- v148: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k/SEResNeXt50-CV4-S6x3-98k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/030) disabled => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=TimeOut\n\n- v149: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x4-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30) => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 3 models LB=0.529/0.524, model_ch54 removed), LB=\n\n- v150: Siamese SEResNeXt50-CV4-S2x1-S1x4-89k(fold1s2-epoch18, fold3-epoch35, fold4-epoch47)/SEResNeXt50-CV4-S4x6-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30) disabled => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=\n\n- v151: Siamese SEResNeXt50-CV4-L10.25-S4x4-89k/SEResNeXt50-CV4-S4x6-89k + EfficientNet B3-224x224x6(green,LB=0.460) + EfficientNet B3-224x224x6(LB=0.528) 0.60/0.275/0.125, Class11 model 0.40(ZFTurbo 0.497 + MPWARE 0.514)/0.30(300x300-ZFTurbo 0.019)/0.30(224x224G-ZFTurbo 0.019), Class7 (0.70/0.30) disabled => Final 0.85x(MPWARE+ZFTurbo, LB=0.590)/0.15x(Dieter 4 models LB=0.529/0.524), LB=","metadata":{}},{"cell_type":"code","source":"# !pip install pycocotools\n# !pip install git+https://github.com/CellProfiling/HPA-Cell-Segmentation.git # This one install pytorch_zoo","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q ../input/hpa-segmentation/pycocotools-2.0.2-cp37-cp37m-linux_x86_64.whl --no-index\n!pip install -q ../input/hpa-segmentation/pytorch_zoo-master/pytorch_zoo-master --no-index\n!pip install -q ../input/hpa-segmentation/HPA-Cell-Segmentation-master/HPA-Cell-Segmentation-master --no-index\n!pip install -q ../input/segmentation-models-013/timm-0.4.5-py3-none-any.whl --no-index\n# !pip install ../input/keras-applications108/ ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os, sys, random, gc, math\nimport numpy as np\nimport pandas as pd\nimport operator\nfrom tqdm.notebook import tqdm\nimport h5py\nimport cv2\nimport torch\nimport torch.nn as nn\nfrom sklearn.preprocessing import LabelEncoder\nfrom torch.utils.data import Dataset, DataLoader\nimport albumentations as A\nimport torch.nn.functional as F\nimport functools\nfrom collections import OrderedDict, defaultdict\nimport timm\nfrom PIL import Image\nimport skimage.io\nimport skimage.transform\nimport warnings\n#warnings.filterwarnings('ignore')\npd.set_option('display.max_colwidth', 200)\npd.set_option('display.max_columns', 500)\npd.set_option('display.max_rows', 4000)\nimport matplotlib.pyplot as plt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nimport typing as t\nimport zlib\n\n# Vanilla HPA\nimport hpacellseg\nimport hpacellseg.cellsegmentator as cellsegmentator\nfrom hpacellseg.utils import label_cell, label_nuclei\n\n# Custom implementation\nimport scipy.ndimage as ndi\nfrom skimage.morphology import (closing, disk, remove_small_holes, remove_small_objects)\nfrom skimage import filters, measure, segmentation\nfrom skimage import transform, util","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.layers import Dropout\nfrom tensorflow.keras.backend import shape\nfrom tensorflow.keras.models import load_model\nimport tensorflow as tf\n# from keras_applications.imagenet_utils import preprocess_input as _preprocess_input","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Python        : ' + sys.version.split('\\n')[0])\nprint('Numpy         : ' + np.__version__)\nprint('Pandas        : ' + pd.__version__)\nprint('PyTorch       : ' + torch.__version__)\nprint('Albumentations: ' + A.__version__)\nprint('Timm          : ' + timm.__version__)\nprint('HPA CellSeg   : ' + hpacellseg.__version__)\nprint('Tensorflow    : ' + tf.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(s):\n    random.seed(s)\n    os.environ['PYTHONHASHSEED'] = str(s)\n    np.random.seed(s)\n    # Torch\n    torch.manual_seed(s)\n    torch.cuda.manual_seed(s)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed_all(s)\n\nseed = 2020\nseed_everything(seed)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"HOME =  \"./\"\nDATA_HOME = \"../input/hpa-single-cell-image-classification/\"\nTEST_HOME = DATA_HOME + \"test/\"\nSUBMISSION = DATA_HOME + \"sample_submission.csv\"\n\nMODEL_HOME = \"../input/hpa-models/\"\nMODEL_BEST = 'model_best.pt'\n\n# HPA weights\nNUC_MODEL = \"../input/hpa-segmentation-weights/nuclei-model.pth\"\nCELL_MODEL = \"../input/hpa-segmentation-weights/cell-model.pth\"\n\n# Enable segmentation optimization\nON_FLY_MASK = True\n\n# Enable to high speed inference\nFAST_INSTANCES = True # False\n\nKEEP_ORIGINAL_IMAGE = True\nRESIZE_ORIGINAL_IMAGE = None\n\nCLEANUP_NEGATIVE = False","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# HPA TF weights\n# CLASSIFICATION_MODEL = \"../input/hpa-classifcation-v1/merged_keras_model_5.h5\" LB=0.420\n# CLASSIFICATION_MODEL = \"../input/hpa-classifcation-v1/effnetB5_optim_Adam_drop_0.25_fold_0_auc-0.8994-acc-0.9489-ll-2.6214-ep-60.h5\" # LB=0.438\n# CLASSIFICATION_MODEL = \"../input/hpa-classifcation-v1/merged_model_keras_5_with_external.h5\" # LB=0.475\nCLASSIFICATION_MODEL = None # \"../input/hpa-classifcation-v1/merged_model_custom_10.h5\" # LB=0.478? (LB=0.475 + LB=0.470 cellline)\n# CLASSIFICATION_MODEL = \"../input/hpa-classifcation-v1/merged_model_5_net_v29_d121_v2_more_iters.h5\" # DenseNet121 0.463\n\n# CLASSIFICATION_MODEL_CL = \"../input/hpa-classifcation-v1/net_v26_merged_model_5_new_oof_v2.h5\" # LB=0.518\n# CLASSIFICATION_MODEL_CL = \"../input/hpa-classifcation-v1/net_v26_merged_model_5_OOF_5_v4.h5\" # 0.519\n# CLASSIFICATION_MODEL_CL = \"../input/hpa-classifcation-v1/net_v26_merged_model_5_oof_6_models.h5\" # 0.514 #  \"../input/hpa-classifcation-v1/net_v26_merged_model_5_oof_5_models_v1.h5\" # LB=0.521# \nCLASSIFICATION_MODEL_CL = \"../input/hpa-classifcation-v1/net_v26_merged_model_5_more_oof_224px_4_models.h5\" # LB=0.528 # \"../input/hpa-classifcation-v1/net_v26_merged_model_26_epochs_5_v4_uni_classes.h5\" # LB=0.514\n# CLASSIFICATION_MODEL_CL = \"../input/hpa-classifcation-v1/net_v26_merged_model_26_epochs_5_version3_mse.h5\" # LB=0.505\n\n# CLASSIFICATION_MODEL_CLASS11 = \"../input/hpa-classifcation-v1/merged_model_5_net_v20_B0_class_11.h5\" # 0.022\nCLASSIFICATION_MODEL_CLASS11 = \"../input/hpa-classifcation-v1/merged_model_5_class_net_v20_B0_11_v2_300px.h5\" # 0.019\nCLASSIFICATION_MODEL_CLASS11G = \"../input/hpa-classifcation-v1/merged_model_5_class_net_v30_B3_11_only_green_channel.h5\" # 0.019\nCLASSIFICATION_MODEL_CLASS0 = None # \"../input/hpa-classifcation-v1/merged_model_5_class_net_v32_B0_0.h5\"\nCLASSIFICATION_MODEL_CLASS1 = None # \"../input/hpa-classifcation-v1/merged_model_5_class_net_v33_B0_class_1.h5\"\nCLASSIFICATION_MODEL_CLASS2 = None # \"../input/hpa-classifcation-v1/merged_model_5_class_net_v33_B0_class_2.h5\"\nCLASSIFICATION_MODEL_CLASS4 = None # \"../input/hpa-classifcation-v1/net_v25_reduced_dataset_0.512_merged_model_5_class_4.h5\"\nCLASSIFICATION_MODEL_CLASS6 = None # \"../input/hpa-classifcation-v2/merged_model_5_class_net_v38_B0_class_6.h5\" # 0.022\nCLASSIFICATION_MODEL_CLASS7 = None # \"../input/hpa-classifcation-v2/merged_model_5_class_net_v39_B0_class_7.h5\" # 0.031 Works\nCLASSIFICATION_MODEL_CLASS9 = None # \"../input/hpa-classifcation-v2/merged_model_5_class_net_v41_B0_class_9.h5\" # 0.023\n\n# CLASSIFICATION_MODEL_GREEN = \"../input/hpa-classifcation-v1/merged_model_5_net_v24_effnetB3_green_only.h5\"\nCLASSIFICATION_MODEL_GREEN = \"../input/hpa-classifcation-v1/net_v31_merged_model_5_more_epochs_only_green.h5\" # 0.460\nCLASSIFICATION_MODEL_GREEN_BLUE = None # \"../input/hpa-classifcation-v2/net_v37_merged_model_5_green_blue_v2.h5\" # 0.482\n\nclass FixedDropout(Dropout):\n    def _get_noise_shape(self, inputs):\n        if self.noise_shape is None:\n            return self.noise_shape\n        return tuple([shape(inputs)[i] if sh is None else sh for i, sh in enumerate(self.noise_shape)])\n    \nconfig = tf.compat.v1.ConfigProto()\nconfig.gpu_options.allow_growth = True\nsession = tf.compat.v1.Session(config=config)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LABEL = \"Label\"\nID = \"ID\"\nEID = \"EID\"\nTOTAL = \"Total\"\nPREDICTION_STRING = \"PredictionString\"\nIMAGE_WIDTH = \"ImageWidth\"\nIMAGE_HEIGHT = \"ImageHeight\"\nMETA = \"META\"\nCELL_CONF = \"cell_conf\"\n\n# 19 class labels.\nclass_mapping = {\n    0: 'Nucleoplasm', 1: 'Nuclear membrane', 2: 'Nucleoli', 3: 'Nucleoli fibrillar center',\n    4: 'Nuclear speckles', 5: 'Nuclear bodies', 6: 'Endoplasmic reticulum', 7: 'Golgi apparatus', 8: 'Intermediate filaments',\n    9: 'Actin filaments', 10: 'Microtubules', 11: 'Mitotic spindle', 12: 'Centrosome', 13: 'Plasma membrane', 14: 'Mitochondria',\n    15: 'Aggresome', 16: 'Cytosol', 17: 'Vesicles and punctate cytosolic patterns', 18: 'Negative',\n}\n\nclass_mapping_inv = {v:k for k,v in class_mapping.items()}\nclass_labels = [str(k) for k,v in class_mapping.items()]\nclass_names = [str(v) for k,v in class_mapping.items()]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Prepare data\nsubmission_pd = pd.read_csv(SUBMISSION)\n# Encode ID to ease further gathering with dataloader\nle_ = LabelEncoder()\nle_.fit(submission_pd[ID])\nsubmission_pd[EID] = le_.transform(submission_pd[ID])\nsubmission_pd.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SANITY = True if len(submission_pd) == 559 else False\nSANITY_SIZE = 16 # 32","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"COMPOSE = None\nIMAGE_SIZE = 512\nSEG_SCALE_FACTOR = 0.25\n\nclass raw_conf:\n\n    def __init__(self):\n        super().__init__()\n        \n        self.inference = True\n\n        # Factory\n        self.factory = None\n        self.compose = COMPOSE\n        self.normalize = True\n        self.norm_value = 65535.0 # Images are np.uint16\n        \n        # Dataset\n        self.image_size = IMAGE_SIZE # Need to resize\n        self.seg_scale_factor = SEG_SCALE_FACTOR\n        self.denormalize = 255 # Move back normalized image to 0-255 uint8 for Albumentations\n        self.dilate_mask = None\n        \n        # Dataloader        \n        \n        # Model\n        self.mtype = \"siamese\" # \"regular\"\n        self.backbone = 'regnety_064'\n        self.pretrained_weights = \"imagenet\"\n        self.INPUT_RANGE = [0, 1]\n        self.IMG_MEAN = [0.485, 0.456, 0.406, 0.485] if self.compose is None else [0.485, 0.456, 0.406]\n        self.IMG_STD = [0.229, 0.224, 0.225, 0.229] if self.compose is None else [0.229, 0.224, 0.225]\n        self.num_classes = 19\n        self.with_cam = True # False\n        self.puzzle_pieces = 4 # Only for Siamese\n        self.hpa_classifier_weights = None\n        self.dropout = None\n        \n        # Model output\n        self.post_activation = \"sigmoid\"\n        self.output_key = \"logits\" if self.mtype == \"regular\" else \"single_logits\" # None\n        self.output_key_extra = \"features\" if self.mtype == \"regular\" else \"single_features\" # None      \n        self.output_key_siamese = None if self.mtype == \"regular\" else \"tiled_logits\"\n        self.output_key_extra_siamese = None if self.mtype == \"regular\" else \"tiled_features\"      \n        \n        # Loss\n        self.alpha = 1.0 # Single image classification loss\n        self.beta =  0.0 if self.mtype == \"regular\" else 1.0 # Reconstructed image classification loss\n        self.gamma = 0.0 if self.mtype == \"regular\" else 1.0 # Reconstruction distance loss\n        self.delta = 0.0 # Tiled image loss\n        self.loss = None  \n        \n        self.sampler = None\n        self.sampler_cap = None # 0.002 # None 95th percentile of train average prob\n        \n        self.fp16 = True\n        self.finetune = False\n        \n        self.optimizer = \"Adam\"\n        self.scheduler = None if self.finetune is True or self.optimizer != \"Adam\" else \"Cosine\"\n        \n        self.lr = 0.001 if self.finetune is False else 0.00005\n        self.min_lr = 0.0001 if self.finetune is False else 0.00001\n        self.beta1 = 0.9\n        self.train_verbose = True # False\n        self.valid_verbose = True # False\n        self.full_train = False # False\n        self.full_train_save = None # [16,17,18] # None\n\n        # Train parameters\n        self.L_DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # \"cpu\"\n        self.map_location = self.L_DEVICE\n        self.WORKERS = 2 # 0\n        self.BATCH_SIZE = 1 # 8 # 16 if self.mtype == \"siamese\" else 32\n        self.ITERATIONS_LOGS = 30\n        self.CYCLES = 1\n        self.EPOCHS_PER_CYCLE = 32\n        self.EPOCHS = self.CYCLES * self.EPOCHS_PER_CYCLE\n        self.WARMUP = 0\n\n        self.FOLDS = 4 if self.full_train is False else 0\n        self.METRIC_ = \"max\"\n\n        self.pin_memory = True","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"conf_siamese_regnety064_512_384 = raw_conf()\nconf_siamese_regnety064_512_384.mtype = \"siamese\"\nconf_siamese_regnety064_512_384.backbone = \"regnety_064\"\nconf_siamese_regnety064_512_384.image_size = 512\n\nconf_siamese_seresnext50_512_384 = raw_conf()\nconf_siamese_seresnext50_512_384.mtype = \"siamese\"\nconf_siamese_seresnext50_512_384.backbone = 'seresnext50_32x4d'\nconf_siamese_seresnext50_512_384.image_size = 512\n\nconf_siamese_cspresnext50_512_384 = raw_conf()\nconf_siamese_cspresnext50_512_384.mtype = \"siamese\"\nconf_siamese_cspresnext50_512_384.backbone = 'cspresnext50'\nconf_siamese_cspresnext50_512_384.image_size = 512\n\nconf_siamese_seresnext101_512_384 = raw_conf()\nconf_siamese_seresnext101_512_384.mtype = \"siamese\"\nconf_siamese_seresnext101_512_384.backbone = 'gluon_seresnext101_32x4d'\nconf_siamese_seresnext101_512_384.image_size = 512\n\n# Default conf\nconf = conf_siamese_seresnext50_512_384 # conf_siamese_regnety064_512_384","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encode_binary_mask(mask: np.ndarray) -> t.Text:\n    \"\"\"Converts a binary mask into OID challenge encoding ascii text.\"\"\"\n\n    # check input mask --\n    if mask.dtype != np.bool:\n        raise ValueError(\n            \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n            mask.dtype)\n\n    mask = np.squeeze(mask)\n    if len(mask.shape) != 2:\n        raise ValueError(\n            \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n            mask.shape)\n\n    # convert input mask to expected COCO API input --\n    mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n    mask_to_encode = mask_to_encode.astype(np.uint8)\n    mask_to_encode = np.asfortranarray(mask_to_encode)\n\n    # RLE encode mask --\n    encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n    # compress and base64 encoding --\n    binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION) # zlib.Z_BEST_SPEED\n    base64_str = base64.b64encode(binary_str)\n    return base64_str.decode()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 0-1.0 normalized image (H, W, 4)\ndef generate_masks(img, nuclei_only=False, verbose=False):\n    \n    nuclei_mask, cell_mask = None, None\n    \n    # Nuclei segmentation\n    nuc_segmentations = segmentator.pred_nuclei([img[:,:,2]])\n    print(\"Nuclei\", len(nuc_segmentations), nuc_segmentations[0].shape, nuc_segmentations[0].dtype, nuc_segmentations[0].max(), np.unique(nuc_segmentations[0])) if verbose is True else None\n    \n    if nuclei_only is False:\n        img_ryb = np.dstack([img[:,:,0], img[:,:,3], img[:,:,2]])\n        print(\"Image\", img_ryb.shape, img_ryb.dtype, img_ryb.max()) if verbose is True else None\n        # Cell segmentation: Requires list of RYB when multi_channel_model is True, it will apply scale factor\n        cell_segmentations = segmentator.pred_cells([img_ryb], precombined=True)\n        print(\"Cells\", len(cell_segmentations), cell_segmentations[0].shape, cell_segmentations[0].dtype, cell_segmentations[0].max(), np.unique(cell_segmentations[0])) if verbose is True else None\n        # Extract instances\n        nuclei_mask, cell_mask = label_cell(nuc_segmentations[0], cell_segmentations[0])\n        print(cell_mask.shape, cell_mask.dtype, cell_mask.max()) if verbose is True else None # (H, W) uint16\n    else:\n        # Extract instances\n        nuclei_mask = label_nuclei(nuc_segmentations[0])\n        \n    return nuclei_mask, cell_mask","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Use PIL to support 16 bits, normalize=True to return [0-1.0] float32 image\ndef read_image(filename, compose=None, normalize=False, norm_value=65535.0, images_root=TEST_HOME):\n    filename = images_root + filename\n    filename = filename + \"_red.png\" if \"_red.png\" not in filename else filename\n    mt_, pi_, nu_, er_ = filename, filename.replace('_red', '_green'), filename.replace('_red', '_blue'), filename.replace('_red', '_yellow')\n    if compose is None:\n        mt = np.asarray(Image.open(mt_)).astype(np.uint16)\n        pi = np.asarray(Image.open(pi_)).astype(np.uint16)\n        nu = np.asarray(Image.open(nu_)).astype(np.uint16)  \n        er = np.asarray(Image.open(er_)).astype(np.uint16)\n        ret = np.dstack((mt, pi, nu, er))\n    else:\n        if compose == \"RGB\": \n            mt = np.asarray(Image.open(mt_)).astype(np.uint16)\n            pi = np.asarray(Image.open(pi_)).astype(np.uint16)\n            nu = np.asarray(Image.open(nu_)).astype(np.uint16)\n            ret = np.dstack((mt, pi, nu))        \n        elif compose == \"RYB\":\n            mt = np.asarray(Image.open(mt_)).astype(np.uint16)\n            er = np.asarray(Image.open(er_)).astype(np.uint16)\n            nu = np.asarray(Image.open(nu_)).astype(np.uint16)\n            ret = np.dstack((mt, er, nu))\n        elif compose == \"RYGYB\":\n            mt = np.asarray(Image.open(mt_))\n            pi = np.asarray(Image.open(pi_))\n            nu = np.asarray(Image.open(nu_))\n            er = np.asarray(Image.open(er_))\n            ret = np.dstack(((mt + er)/2.0, (pi + er/2)/1.5, nu))\n        else:\n            raise Exception(\"Unknown compose:\", compose)\n    \n    if normalize is True:\n        # Inference: Some images are np.uint16 but from 0-255 range! \"020a29cf-2c24-478b-8603-c22a90dc3e31\"\n        if ret.max() > 255:\n            ret = (ret/norm_value).astype(np.float32)\n        else:\n            ret = (ret/255).astype(np.float32)\n            \n    # Inference: 1728 not compatible with HPA segmentation\n    if ON_FLY_MASK is False:\n        if ret.shape[0] == 1728:\n            ret = skimage.transform.resize(ret, (2048, 2048), anti_aliasing=True)\n    \n    return ret\n\n\ndef read_image_mask(filename, compose=None, normalize=False, norm_value=65535.0, images_root=TEST_HOME, masks_root=None, masks_nu_root=None):\n    # Full size image (H, W, 4)\n    image = read_image(filename, compose=compose, normalize=normalize, norm_value=norm_value, images_root=images_root)\n    cell_mask, nuclei_mask = None, None\n    if ON_FLY_MASK is False:\n        nuclei_mask, cell_mask = generate_masks(image)  \n    return image, cell_mask, nuclei_mask","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataFactory:\n    def __init__(self, paths, mask_paths=None, mask_nu_paths=None, conf=None, verbose=False):\n        super().__init__()\n        \n        self.paths = paths\n        self.mask_paths = mask_paths\n        self.mask_nu_paths = mask_nu_paths\n        self.conf = conf\n        self.verbose = verbose\n        print(\"PNGFile factory\") if self.verbose is True else None\n    \n    def read_image_mask(self, uid):\n        image, mask, mask_nu = read_image_mask(uid, compose=self.conf.compose, normalize=self.conf.normalize, norm_value=self.conf.norm_value, images_root=self.paths, masks_root=self.mask_paths, masks_nu_root=self.mask_nu_paths)        \n        return image, mask, mask_nu\n    \n    def cleanup(self):\n        pass   ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Dataset with all images/masks\ndef zero(x, y=None):\n    return 0\n        \nclass HPADataset(Dataset):\n    def __init__(self, df, factory, conf, subset=\"train\", categoricals=None, augment=None, postprocess=None, modelprepare=None, classes=None, weights=False, dump=None, verbose=False):\n        super().__init__()\n        \n        self.df = df\n        self.categoricals = categoricals\n        self.subset = subset\n        self.augment = augment\n        self.postprocess = postprocess\n        self.modelprepare = modelprepare\n        self.classes = classes\n        self.conf = conf\n        self.factory = factory\n        self.dump = dump\n        self.verbose = verbose\n        \n        if subset == 'train':\n            self.get_offset = np.random.randint\n        elif subset == 'valid':\n            self.get_offset = zero\n        elif subset == 'ho':\n            self.get_offset = zero\n        elif subset == 'test':\n            self.get_offset = zero           \n        else:\n            raise RuntimeError(\"Unknown subset\")\n    \n    \n    def cleanup(self):\n        self.factory.cleanup()\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def read_image_mask(self, row):        \n        uid = row[ID]\n        \n        # Load RGB image and mask\n        img, mask, mask_nu = self.factory.read_image_mask(uid)\n        \n        img_orig = None\n        if KEEP_ORIGINAL_IMAGE is True:\n            img_orig = img.copy() # (H, W, 4) [0-1.0] float32\n            img_orig = skimage.transform.resize(img_orig, (RESIZE_ORIGINAL_IMAGE, RESIZE_ORIGINAL_IMAGE), anti_aliasing=True) if RESIZE_ORIGINAL_IMAGE is not None else img_orig\n        \n        # Scale image/mask after cropping\n        if self.conf.image_size is not None:\n            img = skimage.transform.resize(img, (conf.image_size, conf.image_size), anti_aliasing=True) # Works with float32 image\n            \n            # TODO: Use interpolation = cv2.INTER_NEAREST to simplify/speed up (only when ON FLY MASK is not enabled)\n            if mask is not None:\n                cell_ids = [c for c in np.unique(mask) if c > 0]\n                resized_mask = np.zeros((self.conf.image_size, self.conf.image_size), dtype=np.uint8) # Might be better to use np.uint16 on inference\n                for cell_id in cell_ids:\n                    cell_mask_bool = mask.squeeze() == cell_id\n                    mask_ = cv2.resize(cell_mask_bool.astype(np.uint8), (self.conf.image_size, self.conf.image_size), interpolation = cv2.INTER_AREA) if cell_mask_bool is not None else None # Last dimension lost on resize\n                    mask_ = np.clip(mask_, 0, 1).astype(np.uint8) * cell_id\n                    resized_mask = resized_mask + mask_\n                mask = resized_mask\n            if mask_nu is not None:\n                nu_ids = [c for c in np.unique(mask_nu) if c > 0]\n                resized_mask_nu = np.zeros((self.conf.image_size, self.conf.image_size), dtype=np.uint8) # Might be better to use np.uint16 on inference\n                for nu_id in nu_ids:\n                    nu_mask_bool = mask_nu.squeeze() == nu_id\n                    mask_ = cv2.resize(nu_mask_bool.astype(np.uint8), (self.conf.image_size, self.conf.image_size), interpolation = cv2.INTER_AREA) if nu_mask_bool is not None else None # Last dimension lost on resize\n                    mask_ = np.clip(mask_, 0, 1).astype(np.uint8) * nu_id\n                    resized_mask_nu = resized_mask_nu + mask_\n                mask_nu = resized_mask_nu                \n        \n        if self.conf.denormalize is not None:\n            img = (self.conf.denormalize * img).astype(np.uint8)\n            img_orig = (self.conf.denormalize * img_orig).astype(np.uint8) if img_orig is not None else None\n            \n        if mask is not None:\n            if self.conf.dilate_mask is not None and self.subset == \"train\":\n                mask = cv2.dilate(mask, self.conf.dilate_mask, iterations = 1)           \n            mask = np.expand_dims(mask, axis=2) if len(mask.shape) == 2 else mask\n        if mask_nu is not None:\n            if self.conf.dilate_mask is not None and self.subset == \"train\":\n                mask_nu = cv2.dilate(mask_nu, self.conf.dilate_mask, iterations = 1)           \n            mask_nu = np.expand_dims(mask_nu, axis=2) if len(mask_nu.shape) == 2 else mask_nu        \n        \n        return img, mask, mask_nu, img_orig\n    \n    def get_data(self, row, categoricals):\n\n        # Return image, masks\n        img, mask, mask_nu, img_orig = self.read_image_mask(row)\n        \n        sample = {\n            'image': img,  # (H, W, 4) [0-255]\n        }\n        \n        if img_orig is not None:\n            sample['image_orig'] = img_orig # (Horig, Worig, 4) [0-255]\n        \n        if EID in row:\n            sample[META] = np.array([row[EID], row[IMAGE_WIDTH], row[IMAGE_HEIGHT]], dtype=np.int32)\n            \n        if mask is not None:\n            sample['mask'] = mask\n        if mask_nu is not None:\n            sample['mask_nu'] = mask_nu            \n\n        # Optional augmentation on RGB image (uint8)\n        if self.augment:\n            if sample.get(\"mask\") is not None:\n                tmp = self.augment(image=sample['image'], mask=sample.get('mask'))\n                sample['image'] = tmp[\"image\"] # Apply on full image                \n                sample['mask'] = tmp[\"mask\"] # Apply on full mask (only relevant)\n            else:\n                tmp = self.augment(image=sample['image'])\n                sample['image'] = tmp[\"image\"] # Apply on full image \n        \n        # Mandatory to feed model\n        if self.modelprepare: # Albumentations to normalize data\n            if sample.get(\"mask\") is not None:\n                tmp = self.modelprepare(image=sample['image'], mask=sample.get('mask'))\n                sample['image'] = tmp[\"image\"] # Apply on full image\n                sample['mask'] = tmp[\"mask\"] # Apply on full mask (only relevant)  \n            else:\n                tmp = self.modelprepare(image=sample['image'])\n                sample['image'] = tmp[\"image\"] # Apply on full image                \n\n        return sample\n\n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n\n        row = self.df.iloc[idx]\n        sample = self.get_data(row, self.categoricals)\n        \n        return sample","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# (BS, CLASSES, 8, 8) - Between 0-1.0\ndef make_cam(x, epsilon=1e-5):\n    x = F.relu(x) # (BS, CLASSES, 8, 8)\n\n    b, c, h, w = x.size() # (BS, CLASSES, 8, 8)    \n    flat_x = x.view(b, c, (h * w)) # (BS, CLASSES, 8x8)    \n    max_value = flat_x.max(axis=-1)[0].view((b, c, 1, 1))\n\n    return F.relu(x - epsilon) / (max_value + epsilon) # (BS, CLASSES, 8, 8)    \n    \n# Input  (BS, C, H, W), num_pieces = 4\n# Return (BS*4, C, H//4, W//4)\ndef tile_features(features, num_pieces):\n    _, _, h, w = features.size()\n\n    num_pieces_per_line = int(math.sqrt(num_pieces))\n    \n    h_per_patch = h // num_pieces_per_line\n    w_per_patch = w // num_pieces_per_line\n    \n    \"\"\"\n    +-----+-----+\n    |  1  |  2  |\n    +-----+-----+\n    |  3  |  4  |\n    +-----+-----+\n    +-----+-----+-----+-----+\n    |  1  |  2  |  3  |  4  |\n    +-----+-----+-----+-----+\n    \"\"\"\n    patches = []\n    for splitted_features in torch.split(features, h_per_patch, dim=2):\n        for patch in torch.split(splitted_features, w_per_patch, dim=3):\n            patches.append(patch)\n    \n    return torch.cat(patches, dim=0)\n\ndef merge_features(features, num_pieces, batch_size):\n    \"\"\"\n    +-----+-----+-----+-----+\n    |  1  |  2  |  3  |  4  |\n    +-----+-----+-----+-----+\n    \n    +-----+-----+\n    |  1  |  2  |\n    +-----+-----+\n    |  3  |  4  |\n    +-----+-----+\n    \"\"\"\n    features_list = list(torch.split(features, batch_size))\n    num_pieces_per_line = int(math.sqrt(num_pieces))\n    \n    index = 0\n    ext_h_list = []\n\n    for _ in range(num_pieces_per_line):\n\n        ext_w_list = []\n        for _ in range(num_pieces_per_line):\n            ext_w_list.append(features_list[index])\n            index += 1\n        \n        ext_h_list.append(torch.cat(ext_w_list, dim=3))\n\n    features = torch.cat(ext_h_list, dim=2)\n    return features","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_4channels_conv(stem_conv2d):\n    stem_conv2d_pretrained_weight = stem_conv2d.weight.clone()\n    stem_conv2d_ = nn.Conv2d(4, \n                             stem_conv2d.out_channels, kernel_size=stem_conv2d.kernel_size, stride=stem_conv2d.stride, padding=stem_conv2d.padding, padding_mode=stem_conv2d.padding_mode, dilation=stem_conv2d.dilation, \n                             bias=True if stem_conv2d.bias is True else False)            \n    stem_conv2d_.weight = nn.Parameter(torch.cat([stem_conv2d_pretrained_weight, nn.Parameter(torch.mean(stem_conv2d_pretrained_weight, axis=1).unsqueeze(1))], axis=1))  \n    return stem_conv2d_\n\n\nclass HPAModel(nn.Module):\n    def __init__(self, cfg, pretrained_weights=False):\n        super().__init__()\n        self.num_classes = cfg.num_classes\n        self.backbone = cfg.backbone\n        self.with_cam = cfg.with_cam\n        self.drop_rate = cfg.dropout\n        \n        self.preprocess_input_fn = get_preprocessing_fn(cfg) \n                \n        # Unpooled/NoClassifier (features only)\n        self.mfeatures = timm.create_model(self.backbone, pretrained=False, num_classes=0, global_pool='')\n        \n        # Add one channel more\n        if cfg.compose is None:\n            if \"regnet\" in self.backbone:\n                self.mfeatures.stem.conv = get_4channels_conv(self.mfeatures.stem.conv)\n            elif \"csp\" in self.backbone:\n                self.mfeatures.stem[0].conv = get_4channels_conv(self.mfeatures.stem[0].conv)                \n            elif \"resnest\" in self.backbone:\n                self.mfeatures.conv1[0] = get_4channels_conv(self.mfeatures.conv1[0])\n            elif \"seresnext\" in self.backbone:\n                self.mfeatures.conv1 = get_4channels_conv(self.mfeatures.conv1)                \n            elif \"densenet\" in self.backbone:\n                self.mfeatures.features.conv0 = get_4channels_conv(self.mfeatures.features.conv0) \n        \n        # Classifier\n        num_chs = self.mfeatures.feature_info[-1]['num_chs'] # 1296 # 2048\n        self.mclassifier = nn.Conv2d(num_chs, self.num_classes, 1, bias=False)\n        # self.mclassifier = timm.models.layers.linear.Linear(num_chs, self.num_classes, bias=True)\n        \n        # Initialize weights\n        self.initialize([self.mclassifier])\n        \n        print(\"Model %s, last channels: %d, classes: %d\" % (cfg.backbone, num_chs, self.num_classes))\n    \n    # Pooling\n    def adaptive_avgmax_pool2d(self, x, output_size=1):\n        x_avg = F.adaptive_avg_pool2d(x, output_size)\n        x_max = F.adaptive_max_pool2d(x, output_size)\n        return 0.5 * (x_avg + x_max)\n\n    # Average pooling 2d\n    def global_average_pooling_2d(self, x, keepdims=False):\n        x = torch.mean(x.view(x.size(0), x.size(1), -1), -1)\n        if keepdims:\n            x = x.view(x.size(0), x.size(1), 1, 1)\n        return x\n    \n    def gap(self, x, keepdims=False):\n        return self.global_average_pooling_2d(x, keepdims=keepdims)\n    \n    def initialize(self, modules):\n        for m in modules:\n            if isinstance(m, nn.Conv2d):\n                torch.nn.init.kaiming_normal_(m.weight)\n                \n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()       \n    \n    def forward(self, x):\n        # ([BS, C, H, W])\n        x = self.mfeatures(x) # (BS, num_chs, 8, 8)\n        \n        features = None\n        if self.with_cam is True:\n            if self.drop_rate is not None and self.drop_rate > 0.0:\n                x = F.dropout(x, p=float(self.drop_rate), training=self.training)            \n            features = self.mclassifier(x) # (BS, CLASSES, 8, 8)\n            logits = self.gap(features) # (BS, CLASSES)            \n        else:            \n            x = self.gap(x, keepdims=True) # (BS, num_chs, 1, 1)\n            if self.drop_rate is not None and self.drop_rate > 0.0:\n                x = F.dropout(x, p=float(self.drop_rate), training=self.training)\n            logits = self.mclassifier(x).view(-1, self.num_classes) # (BS, CLASSES)            \n        \n        return {\"logits\": logits, \"features\": features} # (BS, CLASSES), (BS, CLASSES, 8, 8)\n\n\nclass HPASiameseModel(nn.Module):\n    def __init__(self, cfg, pretrained_weights=False):\n        super().__init__()\n        self.num_classes = cfg.num_classes\n        self.backbone = cfg.backbone\n        self.with_cam = cfg.with_cam\n        self.puzzle_pieces = cfg.puzzle_pieces\n        self.preprocess_input_fn = get_preprocessing_fn(cfg) \n        self.cnn1 = HPAModel(cfg)\n        self.discard_tiles = cfg.inference\n        \n        if cfg.hpa_classifier_weights is not None:\n            if os.path.exists(cfg.hpa_classifier_weights):\n                print(\"Load regular HPA weights from: %s\" % cfg.hpa_classifier_weights)\n                self.cnn1.load_state_dict(torch.load(cfg.hpa_classifier_weights, map_location=cfg.map_location))            \n        \n        print(\"Model %s\" % (cfg.mtype))\n         \n\n    def forward_once(self, x):\n        x = self.cnn1(x)\n        return x # {\"logits\": logits, \"features\": features}\n    \n    \n    def forward(self, x):\n        # ([BS, C, H, W])\n        bs, _, _, _ = x.shape\n        \n        # Full image\n        x1 = self.forward_once(x)\n        single_logits, single_features = x1[\"logits\"], x1[\"features\"]\n        \n        # Tiled image\n        if self.discard_tiles is True:\n            return {\n                \"single_logits\": single_logits, \"single_features\": single_features,\n            }    \n        else:\n            tiled_x = tile_features(x, self.puzzle_pieces) # (BS*puzzle_pieces, C, H//puzzle_pieces, W//puzzle_pieces) # 2x memory\n            x2 = self.forward_once(tiled_x) # Shared weights\n            tiled_logits, tiled_features = x2[\"logits\"], x2[\"features\"]        \n            tiled_features = merge_features(tiled_features, self.puzzle_pieces, bs) # (BS, CLASSES, 8, 8)\n            tiled_logits_reconstructed = self.cnn1.gap(tiled_features) # (BS, CLASSES)\n                \n            return {\n                \"single_logits\": single_logits, \"single_features\": single_features,\n                \"tiled_logits_flatten\": tiled_logits, \"tiled_features\": tiled_features,\n                \"tiled_logits\": tiled_logits_reconstructed,\n            }    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model(cfg, device, encoder_weights=None, backbone_weights=None, freeze_backbone=False, verbose=False):\n\n    if cfg.mtype == \"siamese\":\n        model = HPASiameseModel(cfg)\n    else:\n        model = HPAModel(cfg)\n\n    # Load weights\n    if (encoder_weights is not None) and (\"imagenet\" not in encoder_weights):\n        if os.path.exists(encoder_weights):\n            print(\"Load weights before optimizer from: %s\" % encoder_weights)\n            model.load_state_dict(torch.load(encoder_weights, map_location=cfg.map_location))\n\n    # For TPU move model with weight before creating the optimizer.\n    model = model.to(device)\n\n    optimizer = None\n\n    # Loss\n    loss = cfg.loss\n\n    return model, loss, optimizer","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Mandatory transform to feed model\ndef to_tensor(x, **kwargs):\n    return x.transpose(2, 0, 1).astype('float32')\n\ndef preprocess_input(x, mean=None, std=None, input_space=\"RGB\", input_range=None, **kwargs):\n\n    if input_space == \"BGR\":\n        x = x[..., ::-1].copy()\n\n    if input_range is not None:\n        if x.max() > 1 and input_range[1] == 1:\n            x = x / 255.0\n\n    if mean is not None:\n        mean = np.array(mean)\n        x = x - mean\n\n    if std is not None:\n        std = np.array(std)\n        x = x / std\n\n    return x\n\ndef denormalize_input(x, mean=None, std=None, input_space=\"RGB\", input_range=None, **kwargs):\n\n    if input_space == \"BGR\":\n        x = x[..., ::-1].copy()\n\n    if std is not None:\n        std = np.array(std)\n        x = x * std\n        \n    if mean is not None:\n        mean = np.array(mean)\n        x = x + mean\n        \n    if input_range is not None:\n        if input_range[1] == 1:\n            x = x * 255.0\n    \n    return x\n\n\ndef get_denormalize_fn(cfg):\n    params = {\"mean\": cfg.IMG_MEAN, \"std\": cfg.IMG_STD, \"input_range\": cfg.INPUT_RANGE}\n    return functools.partial(denormalize_input, **params)\n\ndef get_preprocessing_fn(cfg):\n    params = {\"mean\": cfg.IMG_MEAN, \"std\": cfg.IMG_STD, \"input_range\": cfg.INPUT_RANGE} if ON_FLY_MASK is False else {\"mean\": None, \"std\": None, \"input_range\": cfg.INPUT_RANGE}\n    return functools.partial(preprocess_input, **params)\n\ndef get_preprocessing(preprocessing_fn):\n    return A.Compose([\n        A.Lambda(image=preprocessing_fn),            # Convert uint8 (0-255) in range [0-1.0] and apply Apply Z-Norm that depends on each model,\n        A.Lambda(image=to_tensor),                   # Convert (H, W, C) to (C, H, W)\n        # A.Lambda(image=to_tensor, mask=to_tensor), # Convert (H, W, C) to (C, H, W) and mask to (CLASSES, H, W)\n    ])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MeanStdNormalize(torch.nn.Module):\n\n    def __init__(self, cfg, mean, std, verbose=False):\n        super(MeanStdNormalize, self).__init__()\n        self.mean = torch.as_tensor(mean, device=cfg.L_DEVICE)\n        self.std = torch.as_tensor(std, device=cfg.L_DEVICE)\n        print(self.mean, self.mean[:, None, None].shape) if verbose is not None else None\n\n    def forward(self, data):\n        # (BS, CHANNELS, H, W) with [0-1] range\n        data_ = data.clone()\n        data_ = data_.sub_(self.mean[:, None, None]).div_(self.std[:, None, None]) # mean=torch.Size([CHANNELS, 1, 1])\n        return data_\n\n\nclass CellSegmentation(nn.Module):\n    def __init__(self, cfg, cell_model_path=None, nu_model_path=None, verbose=False):\n        super().__init__()\n        \n        # Normalize applies on (3, H, W) with [0-1] range\n        NORMALIZE = {\"mean\": [124 / 255, 117 / 255, 104 / 255], \"std\": [1 / (0.0167 * 255)] * 3}        \n        self.normalize = MeanStdNormalize(cfg, NORMALIZE[\"mean\"], NORMALIZE[\"std\"], verbose=verbose)\n        \n        self.nuclei_model = torch.load(nu_model_path, map_location=conf.map_location)\n        self.nuclei_model.eval()\n        print(\"nuclei_model loaded from %s\" % nu_model_path)\n                \n        self.cell_model = torch.load(cell_model_path, map_location=conf.map_location)\n        self.cell_model.eval()\n        print(\"cell_model loaded from %s\" % cell_model_path)\n    \n        self.verbose = verbose\n\n    def forward(self, data):\n        # (BS, 4, H, W) # 0-1 normalized, RGBY\n        batch_size, channels, height, width = data.shape\n        print(\"data\", data.shape) if self.verbose is True else None\n        \n        # Prepare for nucleui segmentation\n        # Build (BS, 3 H, W) with B channel only\n        data_blue = data[:, [2], :, :].expand(batch_size, 3, height, width).clone() # Size([BS, 3, H, W])\n        print(\"data_blue\", data_blue.shape) if self.verbose is True else None\n        \n        # Normalize\n        data_blue = self.normalize(data_blue)\n        # data_blue = data_blue.sub_(self.mean[:, None, None]).div_(self.std[:, None, None])\n        print(\"data_blue norm\", data_blue.shape) if self.verbose is True else None\n        \n        # Predict nuclei mask\n        x_nuclei = self.nuclei_model(data_blue)\n        x_nuclei = F.softmax(x_nuclei, dim=1)\n        print(\"x_nuclei\", x_nuclei.shape, x_nuclei.dtype, x_nuclei.min(), x_nuclei.max()) if self.verbose is True else None\n        \n        # Prepare for cells segmentation\n        # Build (BS, 3, H, W) with RYB channels only\n        data_ryb = data[:, [0,3,2], :, :]\n        # Normalize\n        data_ryb = self.normalize(data_ryb)\n        # data_ryb = data_ryb.sub_(self.mean[:, None, None]).div_(self.std[:, None, None]) # mean=torch.Size([3, 1, 1]) \n        # Predict cells mask\n        x_cells = self.cell_model(data_ryb)\n        x_cells = F.softmax(x_cells, dim=1)\n        print(\"x_cells\", x_cells.shape, x_cells.dtype, x_cells.min(), x_cells.max()) if self.verbose is True else None\n\n        return x_nuclei, x_cells\n    \ndef __resize_img(img_, orig_width, orig_height):\n    if img_.shape[1] != orig_height:\n        # img_ = cv2.cvtColor(cv2.cvtColor(img_, cv2.COLOR_RGB2BGR), cv2.COLOR_BGR2RGB)\n        img_ = cv2.resize(img_, (orig_width, orig_height), interpolation=cv2.INTER_AREA)\n    return img_\n\ndef __resize_masks(mask, new_width, new_height):\n    cell_ids = [c for c in np.unique(mask) if c > 0]\n    resized_mask = np.zeros((new_height, new_width), dtype=np.uint8) # Might be better to use np.uint16 on inference\n    for cell_id in cell_ids:\n        cell_mask_bool = mask.squeeze() == cell_id\n        mask_ = cv2.resize(cell_mask_bool.astype(np.uint8), (new_height, new_width), interpolation = cv2.INTER_AREA) if cell_mask_bool is not None else None\n        mask_ = np.clip(mask_, 0, 1).astype(np.uint8) * cell_id\n        resized_mask = resized_mask + mask_\n    mask = resized_mask\n    return mask\n\n# Post process to extract instances\ndef __fill_holes(image):\n    \"\"\"Fill_holes for labelled image, with a unique number.\"\"\"\n    boundaries = segmentation.find_boundaries(image)\n    image = np.multiply(image, np.invert(boundaries))\n    image = ndi.binary_fill_holes(image > 0)\n    image = ndi.label(image)[0]\n    return image\n\n# Updated to support different scale factors\ndef label_cell_(nuclei_pred, cell_pred, scale_factor=0.25):\n    \"\"\"Label the cells and the nuclei.\n\n    Keyword arguments:\n    nuclei_pred -- a 3D numpy array of a prediction from a nuclei image.\n    cell_pred -- a 3D numpy array of a prediction from a cell image.\n\n    Returns:\n    A tuple containing:\n    nuclei-label -- A nuclei mask data array.\n    cell-label  -- A cell mask data array.\n\n    0's in the data arrays indicate background while a continous\n    strech of a specific number indicates the area for a specific\n    cell.\n    The same value in cell mask and nuclei mask refers to the identical cell.\n\n    NOTE: The nuclei labeling from this function will be sligthly\n    different from the values in :func:`label_nuclei` as this version\n    will use information from the cell-predictions to make better\n    estimates.\n    \"\"\"\n    rounder = np.round # np.ceil\n    \n    def __wsh(\n        mask_img,\n        threshold,\n        border_img,\n        seeds,\n        threshold_adjustment=0.35,\n        small_object_size_cutoff=10,\n    ):\n        img_copy = np.copy(mask_img)\n        m = seeds * border_img  # * dt\n        img_copy[m <= threshold + threshold_adjustment] = 0\n        img_copy[m > threshold + threshold_adjustment] = 1\n        img_copy = img_copy.astype(np.bool)\n        \n        img_copy = remove_small_objects(img_copy, small_object_size_cutoff).astype(np.uint8) # \n\n        mask_img[mask_img <= threshold] = 0\n        mask_img[mask_img > threshold] = 1\n        mask_img = mask_img.astype(np.bool)\n        \n        mask_img = remove_small_holes(mask_img, max(1, int(rounder(1000*scale_factor))) )\n        mask_img = remove_small_objects(mask_img, max(1, int(rounder(8*scale_factor))) ).astype(np.uint8)\n        \n        markers = ndi.label(img_copy, output=np.uint32)[0]\n        labeled_array = segmentation.watershed(mask_img, markers, mask=mask_img, watershed_line=True)\n        return labeled_array\n\n    nuclei_label = __wsh(\n        nuclei_pred[..., 2] / 255.0,\n        0.4,\n        1 - (nuclei_pred[..., 1] + cell_pred[..., 1]) / 255.0 > 0.05,\n        nuclei_pred[..., 2] / 255,\n        threshold_adjustment=-0.25,\n        small_object_size_cutoff=max(1, int(rounder(500*scale_factor))), # \n    )\n\n    # for hpa_image, to remove the small pseduo nuclei\n    nuclei_label = remove_small_objects(nuclei_label, max(1, int(rounder(2500*scale_factor))))\n    nuclei_label = measure.label(nuclei_label)\n    # this is to remove the cell borders' signal from cell mask.\n    # could use np.logical_and with some revision, to replace this func.\n    \n    # Tuned for segmentation hpa images\n    threshold_value = max(0.22, filters.threshold_otsu(cell_pred[..., 2] / 255) * 0.5)\n    # exclude the green area first\n    cell_region = np.multiply(\n        cell_pred[..., 2] / 255 > threshold_value,\n        np.invert(np.asarray(cell_pred[..., 1] / 255 > 0.05, dtype=np.int8)),\n    )\n    sk = np.asarray(cell_region, dtype=np.int8)\n    distance = np.clip(cell_pred[..., 2], 255 * threshold_value, cell_pred[..., 2])\n    cell_label = segmentation.watershed(-distance, nuclei_label, mask=sk)\n    \n    cell_label = remove_small_objects(cell_label, max(1, int(rounder(5500*scale_factor))) ).astype(np.uint8) # \n    \n    selem = disk(max(1, int(rounder(6*np.sqrt(scale_factor) ))) )\n    \n    cell_label = closing(cell_label, selem)\n    cell_label = __fill_holes(cell_label)\n    # this part is to use green channel, and extend cell label to green channel\n    # benefit is to exclude cells clear on border but without nucleus\n    sk = np.asarray(\n        np.add(\n            np.asarray(cell_label > 0, dtype=np.int8),\n            np.asarray(cell_pred[..., 1] / 255 > 0.05, dtype=np.int8),\n        )\n        > 0,\n        dtype=np.int8,\n    )\n    cell_label = segmentation.watershed(-distance, cell_label, mask=sk)\n    cell_label = __fill_holes(cell_label)\n    cell_label = np.asarray(cell_label > 0, dtype=np.uint8)\n    cell_label = measure.label(cell_label)\n    \n    cell_label = remove_small_objects(cell_label, max(1, int(rounder(5500*scale_factor))) ) # \n    \n    cell_label = measure.label(cell_label)\n    cell_label = np.asarray(cell_label, dtype=np.uint16)\n    nuclei_label = np.multiply(cell_label > 0, nuclei_label) > 0\n    nuclei_label = measure.label(nuclei_label)\n    \n    nuclei_label = remove_small_objects(nuclei_label, max(1, int(rounder(2500*scale_factor))) ) # \n    \n    nuclei_label = np.multiply(cell_label, nuclei_label > 0)\n\n    return nuclei_label, cell_label    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Some previews with augmentation\ndef display_preview(df, le, tmp_conf, m=None):\n    tmp_factory = DataFactory(TEST_HOME, None, conf=tmp_conf, verbose=True)\n    tmp_dataset = HPADataset(df, tmp_factory, tmp_conf, subset=\"test\", verbose=False, augment=None, modelprepare=get_preprocessing(m.preprocess_input_fn) if m is not None else None)\n    print(\"tmp_dataset:\", len(tmp_dataset))\n    tmp_loader = DataLoader(tmp_dataset, batch_size=tmp_conf.BATCH_SIZE, num_workers=tmp_conf.WORKERS, drop_last = False, pin_memory=False, sampler=None, shuffle=False)\n    \n    denormalize_ = get_denormalize_fn(tmp_conf)\n    ROWS = 6\n    COLS = 8\n    fig, ax = plt.subplots(ROWS, COLS, figsize=(20, 16))\n\n    print(\"Loading\")\n    i = 0\n    for tmp_batch in tmp_loader:\n        images = tmp_batch[\"image\"]        \n        masks = tmp_batch.get(\"mask\")\n        eids = tmp_batch.get(META)\n        print(images.shape, images.dtype, images.max(), eids.shape, masks.shape, masks.dtype) if i == 0 else None        \n        for img, eid, mask in zip(images, eids, masks):\n            img = denormalize_(img.numpy().transpose(1,2,0)).astype(np.uint8) if m is not None else img.numpy()\n            r = i%ROWS\n            c = i//ROWS\n            d = ax[r, c].imshow(img[:,:,[0,1,2]])\n            d = ax[r, c].imshow((mask.numpy()).astype(np.uint8), alpha=0.30)\n            d = ax[r, c].grid(None)\n            d = ax[r, c].axis('off')\n            d = ax[r, c].set_title(\"%s...%d\" % (le.inverse_transform([eid[0]])[0][0:13], len(np.unique(mask))))\n            i = i + 1\n            if i >= ROWS*COLS: break\n        if i >= ROWS*COLS: break\n    tmp_factory.cleanup()\n    plt.subplots_adjust(wspace=0.1, hspace=0.1)\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# (*, C, H, W)\ndef ident(data):\n    return data\n\n# (*, C, H, W)\ndef rot180(data):\n    return torch.flip(data, [-2, -1])\n\n# (*, C, H, W)\ndef hflip(data):\n    w = data.shape[-1]\n    return data[..., torch.arange(w - 1, -1, -1, device=data.device)]\n\n# (*, C, H, W)\ndef vflip(data):\n    h = data.shape[-2]\n    return data[..., torch.arange(h - 1, -1, -1, device=data.device), :]\n\n# Idempotent TTA\nclass EnsembleTTA(nn.Module):\n    def __init__(self, model, ttas=None, verbose=True):\n        super(EnsembleTTA, self).__init__()\n        self.model = model\n        self.conf = self.model.conf\n        self.ttas = ttas\n        self.preprocess_input_fn = self.model.preprocess_input_fn\n        if verbose is True:\n            print(\"EnsembleTTA:\", self.ttas, self.preprocess_input_fn)\n    \n    def eval(self):\n        self.model.eval()\n    \n    def forward(self, data):\n        if self.ttas is None or len(self.ttas) == 0:\n            return self.model(data)\n        else:            \n            output = {}\n            # Concatenate model outputs\n            output_cat = defaultdict(list)\n            for tta in self.ttas:\n                output_dict = self.model(tta(data))\n                for k, v in output_dict.items():\n                    output_ = output_cat[k]\n                    output_.extend([tta(v) if \"features\" in k else v])\n            # Average all outputs\n            for k, v in output_cat.items():\n                output[k] = torch.mean(torch.stack(v), dim=0)\n            return output","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Ensemble(nn.Module):\n    def __init__(self, models, conf, preprocess_input_fn, verbose=True):\n        super(Ensemble, self).__init__()\n        self.models = models\n        self.conf = conf\n        self.preprocess_input_fn = preprocess_input_fn\n        if verbose is True:\n            print(\"Ensemble of %d %s_%s model(s)\" % (len(self.models), self.conf.mtype, self.conf.backbone))\n    \n    def eval(self):\n        for i, m in enumerate(self.models):\n            m.eval()\n    \n    def forward(self, data):        \n        output = {}\n        # Concatenate model outputs\n        output_cat = defaultdict(list)\n        for m in self.models:\n            output_dict = m(data)\n            for k, v in output_dict.items():\n                output_ = output_cat[k]\n                output_.extend([v])\n        # Average all outputs\n        for k, v in output_cat.items():\n            output[k] = torch.mean(torch.stack(v), dim=0)\n        return output\n    \ndef build_ensemble(name, cfg, model_dict):\n    tmp_models_ = []\n    for k, v in model_dict.items():\n        # Load each model\n        if \"fold\" in k:\n            model_path = model_dict.get(k)\n            if os.path.exists(model_path):\n                model_, _, _ = build_model(cfg, cfg.L_DEVICE)\n                model_.load_state_dict(torch.load(model_path, map_location=cfg.map_location))\n                print(\"Loading %s: %s\" % (name, model_path))\n                model_.eval()\n                tmp_models_.append(model_)\n    ensemble_ = Ensemble(tmp_models_, cfg, tmp_models_[-1].preprocess_input_fn)\n    return ensemble_","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load models\nsegmentator_, normalizer_ = None, None\n\n# Cell segmentation\nif ON_FLY_MASK is False:\n    segmentator = cellsegmentator.CellSegmentator(\n        NUC_MODEL,\n        CELL_MODEL,\n        scale_factor=conf.seg_scale_factor,\n        device=conf.L_DEVICE if isinstance(conf.L_DEVICE, str) else conf.L_DEVICE.type,\n        padding=False,\n        multi_channel_model=True, # RYB\n    )\n    print(\"Segmentator\", segmentator.device)\nelse:\n    segmentator_ = CellSegmentation(conf, cell_model_path=CELL_MODEL, nu_model_path=NUC_MODEL).to(conf.L_DEVICE)\n    normalizer_ = MeanStdNormalize(conf, conf.IMG_MEAN, conf.IMG_STD, verbose=True)\n    print()\n\nMODELS_NN = { \n#     # LB=0.443\n#     \"model1\": {\n#         \"conf\": conf_siamese_regnety064_512_384,  \n#         \"fold1\": MODEL_HOME + \"siamese_regnety_064_512_384_RGBY_fp16_CV4_v1.0/fold1/stage4/snapshots/\" + MODEL_BEST,\n#         \"fold2\": MODEL_HOME + \"siamese_regnety_064_512_384_RGBY_fp16_CV4_v1.0/fold2/stage4/snapshots/\" + MODEL_BEST,\n#         \"fold3\": MODEL_HOME + \"siamese_regnety_064_512_384_RGBY_fp16_CV4_v1.0/fold3/stage4/snapshots/\" + MODEL_BEST,\n#         \"fold4\": MODEL_HOME + \"siamese_regnety_064_512_384_RGBY_fp16_CV4_v1.0/fold4/stage4/snapshots/\" + MODEL_BEST,        \n#     },\n    \n#     # LB=0.457 (3 folds), 0.461 (4 folds)\n#     \"model2\": {\n#         \"conf\": conf_siamese_seresnext50_512_384,\n#         \"fold1\": MODEL_HOME + \"siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v1.0/fold1/stage1/snapshots/\" + MODEL_BEST,\n#         \"fold2\": MODEL_HOME + \"siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v1.0/fold2/stage1/snapshots/\" + MODEL_BEST,\n#         \"fold3\": MODEL_HOME + \"siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v1.0/fold3/stage1/snapshots/\" + MODEL_BEST,\n#         \"fold4\": MODEL_HOME + \"siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v1.0/fold4/stage1/snapshots/\" + MODEL_BEST,\n#     }\n    \n#     \"model13\": {\n#         \"model3\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#         },\n#         \"model5\": {\n#             \"conf\": conf_siamese_cspresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold1/stage1/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold2/stage1/snapshots/model_best.pt\",\n#             \"fold3\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold3/stage1/snapshots/model_best.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold4/stage1/snapshots/model_best.pt\",\n#         },          \n#     }  \n    \n#     \"model13\": {\n#         # L1 loss = 0.5 - Works\n#         \"model3\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#         },\n        \n        # 3 folds S6 with model3 got 0.521\n#         \"model3s6\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage6/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage6/snapshots/model_best.pt\",\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage6/snapshots/model_best.pt\",\n#         },\n        \n#         # L1 loss = 0.5\n#         \"model4\": {\n#             \"conf\": conf_siamese_seresnext101_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage1/snapshots/model_best.pt\", # 0.1984/0.780\n#             \"fold2\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/model_best.pt\", # 0.1975/0.746 \n#             \"fold3\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.pt\", # 0.1987(0.753) # 0.1996/0.746 (epoch24)\n#             \"fold4\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/model_best.pt\", # 0.1996/0.743 (epoch21)\n#         },\n        \n        # L1 loss = 0.25 - Works\n        \"model6\": {\n            \"conf\": conf_siamese_seresnext50_512_384,\n            \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage4/snapshots/model_best.pt\",\n            \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage4/snapshots/model_best.pt\",\n            \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage4/snapshots/model_best.pt\",\n            \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage4/snapshots/model_best.pt\",\n        },         \n        \n        # L1 loss = 0.50\n        \"model6c\": {\n            \"conf\": conf_siamese_seresnext50_512_384,\n            \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage6/snapshots/model_best.pt\",\n            \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage6/snapshots/model_best.pt\",\n            \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage6/snapshots/model_best.pt\",\n            \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage6/snapshots/model_best.pt\",\n        },             \n        \n        \n        # L1 loss = 0.5\n#         \"model7\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models5/siamese_seresnext50_32x4d_512_512_RGBY_fp16_CV4_v2.2/fold1/stage1/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models5/siamese_seresnext50_32x4d_512_512_RGBY_fp16_CV4_v2.2/fold2/stage1/snapshots/model_best.pt\",\n#             \"fold3\": \"../input/hpa-models/wsss_models5/siamese_seresnext50_32x4d_512_512_RGBY_fp16_CV4_v2.2/fold3/stage1/snapshots/model_best.pt\",\n#         },         \n        \n        \n#         # L1 loss = 1.0\n#         \"model7\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage5/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage5/snapshots/model_best.pt\",\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage5/snapshots/model_best.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage5/snapshots/model_best.pt\",\n#         },         \n#         \"model9\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage5/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage5/snapshots/model_best.pt\",\n#         },         \n#    }      \n    \n#     # LB=0.514\n#     \"model3\": {\n#         \"conf\": conf_siamese_seresnext50_512_384,\n#         \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\", # epoch18, loss=0.1830\n#         \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST,\n#         \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#         \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST,\n#     }  \n    \n#     # LB=0.512\n#     \"model4\": {\n#         \"conf\": conf_siamese_seresnext101_512_384,\n#         \"fold1\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage1/snapshots/model_best.pt\", # 0.1984/0.780\n#         \"fold2\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/model_best.pt\", # 0.1975/0.746 \n#         \"fold3\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.pt\", # 0.1987(0.753) # 0.1996/0.746 (epoch24)\n#         \"fold4\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/model_best.pt\", # 0.1996/0.743 (epoch21)\n#     },\n    \n#     \"model3\": {\n#         \"conf\": conf_siamese_seresnext50_512_384,\n#         \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\", # Best\n#         # \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage4/snapshots/model_best.pt\", # 0.1695/0.824 (epoch22)\n#         \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#         \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#         \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#     },\n    \n#     # LB=\n#     \"model13\": {\n#         \"model3\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#         },\n#         \"model4\": {\n#             \"conf\": conf_siamese_seresnext101_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage1/snapshots/model_best.pt\", # 0.1984/0.780\n#             \"fold2\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/model_best.pt\", # 0.1975/0.746 \n#             \"fold3\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.pt\", # 0.1987(0.753) # 0.1996/0.746 (epoch24)\n#             \"fold4\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/model_best.pt\", # 0.1996/0.743 (epoch21)\n#         },\n#         \"model5\": {\n#             \"conf\": conf_siamese_cspresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold1/stage1/snapshots/model_best.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold2/stage1/snapshots/model_best.pt\",\n#             \"fold3\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold3/stage1/snapshots/model_best.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.1/fold4/stage1/snapshots/model_best.pt\",\n#         },        \n#     }\n    \n#     \"model13\": {\n#         \"model3\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             # \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#         },\n#         \"model4\": {\n#             \"conf\": conf_siamese_seresnext101_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_gluon_seresnext101_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/model_best.pt\", # 0.1984/0.78\n#         },\n#         \"model5\": {\n#             \"conf\": conf_siamese_cspresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.0/fold1/stage1/snapshots/model_best.pt\",\n#         },        \n#    }     \n    \n#     \"model13\": {\n#         \"model3\": {\n#             \"conf\": conf_siamese_seresnext50_512_384,\n#             # \"fold1\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold1/stage2/snapshots/model_best.epoch18.pt\",\n#             \"fold2\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold2/stage1/snapshots/\" + MODEL_BEST, # Best is stage1\n#             \"fold3\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold3/stage1/snapshots/model_best.epoch35.pt\",\n#             \"fold4\": \"../input/hpa-models/wsss_models2/siamese_seresnext50_32x4d_512_384_RGBY_fp16_CV4_v2.0/fold4/stage1/snapshots/\" + MODEL_BEST, # best is stage1\n#         },\n#         \"model4\": {\n#             \"conf\": conf_siamese_cspresnext50_512_384,\n#             \"fold1\": \"../input/hpa-models/wsss_models3/siamese_cspresnext50_512_384_RGBY_fp16_CV4_v2.0/fold1/stage1/snapshots/model_best.pt\",\n#         },\n#     }     \n    \n}\n\n# Load Classifier models\nmodels_ = []\nfor name, info in MODELS_NN.items():    \n    cfg = info.get(\"conf\")\n    if cfg is not None:\n        # Folds ensembling\n        models_.append(build_ensemble(name, cfg, info))\n        print()\n    else:\n        print(\"Warning: Only works if preprocess_input_fn is the same for sub models\")\n        sub_models_ = []\n        for subname, subinfo in info.items():\n            subcfg = subinfo.get(\"conf\")\n            if subcfg is not None:\n                sub_models_.append(build_ensemble(subname, subcfg, subinfo))\n                print()\n        models_.append(Ensemble(sub_models_, subcfg, sub_models_[-1].preprocess_input_fn))\n\n# Final Ensemble\nmodel_ = models_[0]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## load dieters models\n\nimport timm\nimport torch\nfrom torch.nn import functional as F\nfrom torch import nn\nimport numpy as np\nimport math\n\nclass DieterNet1(nn.Module):\n    def __init__(self, backbone):\n        super(DieterNet1, self).__init__()\n        \n        self.n_classes = 19\n        in_chans = 4\n        \n        self.backbone = timm.create_model(backbone, pretrained=False, num_classes=0, global_pool='avg',in_chans=in_chans)\n        if 'efficientnet' in backbone:\n            backbone_out = self.backbone.num_features\n        else:\n            backbone_out = self.backbone.feature_info[-1]['num_chs']\n\n        \n        self.head_in_units = backbone_out\n        self.head = nn.Linear(self.head_in_units, self.n_classes)\n        self.att = nn.Sequential(nn.Linear(self.head_in_units, 512),\n                                  nn.ReLU(),\n                                  nn.Linear(512, 1))\n\n    def forward(self, img):\n\n        x = img\n        bs, n, c, w, h = x.shape\n        x = x.reshape(bs*n,c,w,h)\n        x = self.backbone(x)\n        cell_logits = self.head(x)\n        return cell_logits.sigmoid()\n\n\n\nclass DieterNet2(nn.Module):\n    def __init__(self, backbone):\n        super(DieterNet2, self).__init__()\n        \n        self.n_classes = 19\n        in_chans = 4\n        \n        self.backbone = timm.create_model(backbone, pretrained=False, num_classes=0, global_pool='',in_chans=in_chans)\n        backbone_out = self.backbone.feature_info[-1]['num_chs']\n        self.head_in_units = backbone_out\n        self.head = nn.Linear(self.head_in_units, self.n_classes)\n        self.cfg = cfg\n\n        self.att = nn.Sequential(nn.Linear(backbone_out, 512),\n                                  nn.ReLU(),\n                                  nn.Linear(512, 1))\n\n    def forward(self, img, mask):\n\n        x = img\n        m = mask.long()\n        x = self.backbone(x)\n        \n                \n        x_new = []\n        for i in range(x.shape[0]):\n            m1 = m[i]\n            x1 = x[i]\n            ml = m1.unique()[1:].long()\n            cell_means = []\n            for j in ml:\n                mask = (m1 ==j).float()\n                mask = F.interpolate(mask[None,None,:,:].float(), size=(x.shape[2],x.shape[3]), mode='nearest')[0]\n                x2 = x1 * mask\n                mask_div = mask.sum((1,2)) \n                x3 = x2.sum((1,2))\n                if mask_div > 0:\n                    x3 = x3 / mask_div\n                cell_means += [x3]\n            cell_means = torch.stack(cell_means)\n            cell_means = self.head(cell_means)\n    \n        return cell_means.sigmoid(), ml\n\nclass DieterNet3(nn.Module):\n    def __init__(self, backbone):\n        super(DieterNet3, self).__init__()\n        \n        self.n_classes = 18\n        in_chans = 4\n        \n        self.backbone = timm.create_model(backbone, pretrained=False, num_classes=0, global_pool='avg',in_chans=in_chans)\n        self.head_in_units = self.backbone.num_features\n        self.head = nn.Linear(self.head_in_units, self.n_classes)\n\n    def forward(self, img):\n\n        x = self.backbone(img)\n        logits = self.head(x)\n\n        return logits.sigmoid()\n    \n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dieter_weights = {'ch36':['../input/dieter-models/cfg_ch36_otf_ext1b_rerun/fold0/checkpoint_last_seed192185.pth',\n                   '../input/dieter-models/cfg_ch36_otf_ext1b_rerun/fold1/checkpoint_last_seed776732.pth',\n                   '../input/dieter-models/cfg_ch36_otf_ext1b_rerun/fold2/checkpoint_last_seed847064.pth',\n                   '../input/dieter-models/cfg_ch36_otf_ext1b_rerun/fold3/checkpoint_last_seed175131.pth'],\n           'ch54':['../input/dieter-models/cfg_ch54_ext1/fold0/checkpoint_last_seed557578.pth',\n                   '../input/dieter-models/cfg_ch54_ext1/fold1/checkpoint_last_seed339097.pth',\n                   '../input/dieter-models/cfg_ch54_ext1/fold2/checkpoint_last_seed813227.pth',\n                   '../input/dieter-models/cfg_ch54_ext1/fold3/checkpoint_last_seed935642.pth'],\n           'ch_img_mask_4':['../input/dieter-models/cfg_img_mask_4_1024_ext1_19/fold0/checkpoint_last_seed725440.pth',\n                            '../input/dieter-models/cfg_img_mask_4_1024_ext1_19/fold1/checkpoint_last_seed310572.pth',\n                            '../input/dieter-models/cfg_img_mask_4_1024_ext1_19/fold2/checkpoint_last_seed603200.pth',\n                            '../input/dieter-models/cfg_img_mask_4_1024_ext1_19/fold3/checkpoint_last_seed89030.pth'],\n                  \n            'ch_img_4_ext7':['../input/dieter-models/cfg_img_4_ext7/fold0/checkpoint_last_seed855026.pth',\n                            '../input/dieter-models/cfg_img_4_ext7/fold1/checkpoint_last_seed5291.pth',\n                            '../input/dieter-models/cfg_img_4_ext7/fold2/checkpoint_last_seed85922.pth',\n                            '../input/dieter-models/cfg_img_4_ext7/fold3/checkpoint_last_seed984345.pth'],\n                  'ch62':['../input/dieter-models/cfg_ch62_sc_ext7_clus/fold0/checkpoint_last_seed873375.pth',\n '../input/dieter-models/cfg_ch62_sc_ext7_clus/fold1/checkpoint_last_seed343961.pth',\n '../input/dieter-models/cfg_ch62_sc_ext7_clus/fold2/checkpoint_last_seed616029.pth',\n '../input/dieter-models/cfg_ch62_sc_ext7_clus/fold3/checkpoint_last_seed787359.pth']\n          }\n\ncfg = raw_conf()\nmodel_ch54 = []\nfor fold in [0,1,2,3]:\n    model_d = DieterNet1('gluon_seresnext101_32x4d')\n    model_path = dieter_weights['ch54'][fold]\n    model_d.load_state_dict(torch.load(model_path, map_location=cfg.map_location)['model'])\n    print(\"Loading %s: %s\" % ('ch54', model_path))\n    model_d.eval().to(cfg.L_DEVICE)\n    model_ch54 += [model_d]\n\nmodel_ch36 = []\nfor fold in [0,1,2,3]:\n    model_d = DieterNet1('seresnext26t_32x4d')\n    model_path = dieter_weights['ch36'][fold]\n    model_d.load_state_dict(torch.load(model_path, map_location=cfg.map_location)['model'])\n    print(\"Loading %s: %s\" % ('ch36', model_path))\n    model_d.eval().to(cfg.L_DEVICE)\n    model_ch36 += [model_d]\n    \nmodel_ch_img_mask_4 = []\nfor fold in [0,1,2,3]:\n    model_d = DieterNet2('gluon_seresnext101_32x4d')\n    model_path = dieter_weights['ch_img_mask_4'][fold]\n    model_d.load_state_dict(torch.load(model_path, map_location=cfg.map_location)['model'])\n    print(\"Loading %s: %s\" % ('ch_img_mask_4', model_path))\n    model_d.eval().to(cfg.L_DEVICE)\n    model_ch_img_mask_4 += [model_d]\n    \nmodel_ch_img_4_ext7 = []\nfor fold in [0,1,2,3]:\n    model_d = DieterNet3('tf_efficientnet_b7_ns')\n    model_path = dieter_weights['ch_img_4_ext7'][fold]\n    model_d.load_state_dict(torch.load(model_path, map_location=cfg.map_location)['model'])\n    print(\"Loading %s: %s\" % ('ch_img_4_ext7', model_path))\n    model_d.eval().to(cfg.L_DEVICE)\n    model_ch_img_4_ext7 += [model_d]\n    \nmodel_ch62 = []\nfor fold in [0,1,2,3]:\n    model_d = DieterNet1('gluon_seresnext101_32x4d')\n    model_path = dieter_weights['ch62'][fold]\n    model_d.load_state_dict(torch.load(model_path, map_location=cfg.map_location)['model'], strict=False)\n    print(\"Loading %s: %s\" % ('ch62', model_path))\n    model_d.eval().to(cfg.L_DEVICE)\n    model_ch62 += [model_d]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def get_valid_cells(cell_mask):\n#     good_cell_ids = []\n#     for cell_id in np.unique(cell_mask)[1:]:\n#         binary_mask = np.uint8(cell_mask == cell_id)\n#         box = cv2.boundingRect(binary_mask)\n#         if len(box) == 4:\n#             x, y, w, h = box\n#             if (w>127) & (h>127):\n#                 good_cell_ids += [cell_id]                           \n#     return good_cell_ids\n\n\ndef crop_cell(cell_id,cell_mask,img):\n    binary_mask = np.uint8(cell_mask == cell_id)\n    x, y, w, h = cv2.boundingRect(binary_mask)\n    cropped_img = img[y:y+h,x:x+w,:]\n    cropped_mask = binary_mask[y:y+h,x:x+w]\n    new_img = np.zeros((h,w,4), dtype=np.uint8)\n    new_img[cropped_mask>0] = cropped_img[cropped_mask>0]\n    PAD = (np.array(new_img.shape[:2]) * 0.1).astype(np.int32)\n    new_img = np.pad(new_img,((PAD[0], PAD[0]), (PAD[1], PAD[1]), (0,0)))\n    return new_img\n\ndef crop_cell2(cell_id,cell_mask,img):\n    binary_mask = np.uint8(cell_mask == cell_id)\n    x, y, w, h = cv2.boundingRect(binary_mask)\n    cropped_img = img[y:y+h,x:x+w,:]\n    cropped_mask = binary_mask[y:y+h,x:x+w]\n    new_img = np.zeros((h,w,4), dtype=np.uint8)\n    new_img[cropped_mask>0] = cropped_img[cropped_mask>0]\n    new_img2 = cv2.resize(new_img, (0,0),fx=0.8,fy=0.8)\n    return new_img2\n\ndef preprocess_img(img, aug):\n    \n    img = aug(image=img)['image']\n    img = img.astype(np.float32)\n    \n    pixel_mean = img.mean((0,1))\n    pixel_std = img.std((0,1)) + 1e-4\n    img = (img - pixel_mean[None,None,:]) / pixel_std[None,None,:]\n    img = img.clip(-20,20)\n    \n    img_t = torch.from_numpy(img.transpose((2, 0, 1)))\n    return img_t\n\n# def get_input(raw_img,cell_mask, aug):\n#     imgs = []    \n#     # cell_ids = get_valid_cells(cell_mask) # Keep valid cells (background + small cells removed)\n#     cell_ids = np.array([c for c in np.unique(cell_mask) if c > 0]) # Remove background only\n    \n#     for cell_id in cell_ids:\n#         img = crop_cell(cell_id,cell_mask,raw_img)\n#         imgs += [preprocess_img(img, aug)]\n\n#     imgs = torch.stack(imgs)\n#     return imgs","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def per_cell_predictions_dieter1(image, cells_mask, models_list, sub_batch_size, device):\n    \n    aug = A.Compose([A.Resize(int(256*1.2),int(256*1.2)),])\n    \n    # cell_ids = np.array(get_valid_cells(cells_mask)) # Keep valid cells (background + small cells removed)\n    cell_ids = np.array([c for c in np.unique(cells_mask) if c > 0]) # Remove background only\n    \n    cell_ids_batches = np.array_split(cell_ids, (len(cell_ids)//sub_batch_size) + 1)\n    \n    all_preds = []\n    for cell_ids_batch in cell_ids_batches:\n        imgs = []\n        for cell_id in cell_ids_batch:\n            img = crop_cell(cell_id,cells_mask,image)\n            imgs += [preprocess_img(img, aug)]\n\n        imgs = torch.stack(imgs)\n        imgs = imgs[None,:].to(device)\n        preds = torch.stack([model(imgs) for model in models_list])\n        preds = preds.mean(0)\n        all_preds += [preds.detach().cpu().numpy()]\n    all_preds = np.concatenate(all_preds)\n    return all_preds, cell_ids\n\ndef per_cell_predictions_dieter2(img, cells_mask, models_list, sub_batch_size, device):\n    \n    aug = A.Compose([A.Resize(1024,1024)])\n    a = aug(image=img, mask=cells_mask)\n    img = a['image']\n    mask = a['mask']\n    \n    img = img.astype(np.float32)\n    pixel_mean = img.mean((0,1))\n    pixel_std = img.std((0,1)) + 1e-4\n    img = (img - pixel_mean[None,None,:]) / pixel_std[None,None,:]\n    img = img.clip(-20,20)\n\n\n    img = torch.from_numpy(img.transpose((2, 0, 1)))\n    mask = torch.tensor(mask.astype(np.int16))\n    \n    img = img[None,:].to(device)\n    mask = mask[None,:].to(device)\n    \n    all_preds = []\n    for model in models_list:\n        \n        preds, cell_ids = model(img,mask)\n        all_preds += [preds.detach().cpu().numpy()]\n        \n    all_preds = np.mean(all_preds, axis = 0)\n    cell_ids = cell_ids.detach().cpu().numpy()\n\n    return all_preds, cell_ids\n\ndef per_cell_predictions_dieter3(img, cells_mask, models_list, sub_batch_size, device):\n    \n    aug = A.Compose([A.Resize(int(1.2*512),int(1.2*512))])\n    a = aug(image=img)\n    img = a['image']\n    \n    img = img.astype(np.float32)\n    pixel_mean = img.mean((0,1))\n    pixel_std = img.std((0,1)) + 1e-4\n    img = (img - pixel_mean[None,None,:]) / pixel_std[None,None,:]\n    img = img.clip(-20,20)\n\n\n    img = torch.from_numpy(img.transpose((2, 0, 1)))\n    \n    img = img[None,:].to(device)\n    \n    all_preds = []\n    for model in models_list:\n        preds = model(img)\n        all_preds += [preds.detach().cpu().numpy()]\n    all_preds = np.mean(all_preds, axis = 0)\n\n    return all_preds\n\ndef per_cell_predictions_dieter4(image, cells_mask, models_list, sub_batch_size, device):\n    \n    aug = A.Compose([A.Resize(int(256*1.2),int(256*1.2)),])\n    \n    # cell_ids = np.array(get_valid_cells(cells_mask)) # Keep valid cells (background + small cells removed)\n    cell_ids = np.array([c for c in np.unique(cells_mask) if c > 0]) # Remove background only\n    cell_ids_batches = np.array_split(cell_ids, (len(cell_ids)//sub_batch_size) + 1)\n    \n    all_preds = []\n    for cell_ids_batch in cell_ids_batches:\n        imgs = []\n        for cell_id in cell_ids_batch:\n            img = crop_cell2(cell_id,cells_mask,image)\n            imgs += [preprocess_img(img, aug)]\n\n        imgs = torch.stack(imgs)\n        imgs = imgs[None,:].to(device)\n        preds = torch.stack([model(imgs) for model in models_list])\n        preds = preds.mean(0)\n        all_preds += [preds.detach().cpu().numpy()]\n    all_preds = np.concatenate(all_preds)\n    return all_preds, cell_ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load TF model (after Pytorch to avoid CUDA OOM)\ncustomObjects = {\n    'swish': tf.nn.swish,\n    'FixedDropout': FixedDropout\n}\n\nkeras_model = load_model(CLASSIFICATION_MODEL, custom_objects=customObjects) if CLASSIFICATION_MODEL is not None else None\nkeras_model_cl = load_model(CLASSIFICATION_MODEL_CL, custom_objects=customObjects) if CLASSIFICATION_MODEL_CL is not None else None\nkeras_model_class11 = load_model(CLASSIFICATION_MODEL_CLASS11, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS11 is not None else None\nkeras_model_class11g = load_model(CLASSIFICATION_MODEL_CLASS11G, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS11G is not None else None\nkeras_model_class4 = load_model(CLASSIFICATION_MODEL_CLASS4, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS4 is not None else None\nkeras_model_green = load_model(CLASSIFICATION_MODEL_GREEN, custom_objects=customObjects) if CLASSIFICATION_MODEL_GREEN is not None else None\nkeras_model_class6 = load_model(CLASSIFICATION_MODEL_CLASS6, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS6 is not None else None\nkeras_model_class7 = load_model(CLASSIFICATION_MODEL_CLASS7, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS7 is not None else None\nkeras_model_class9 = load_model(CLASSIFICATION_MODEL_CLASS9, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS9 is not None else None\n\n# keras_model_green_blue = load_model(CLASSIFICATION_MODEL_GREEN_BLUE, custom_objects=customObjects) if CLASSIFICATION_MODEL_GREEN_BLUE is not None else None\n# keras_model_class0 = load_model(CLASSIFICATION_MODEL_CLASS0, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS0 is not None else None\n# keras_model_class1 = load_model(CLASSIFICATION_MODEL_CLASS1, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS1 is not None else None\n# keras_model_class2 = load_model(CLASSIFICATION_MODEL_CLASS2, custom_objects=customObjects) if CLASSIFICATION_MODEL_CLASS2 is not None else None","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n# 48 images + cells masks = 8min\nDISPLAY_PREVIEW = False\nif DISPLAY_PREVIEW is True:\n    display_preview(submission_pd, le_, conf, m=model_)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %%time\n# # CPU: 10 full images, nuclei only: 1min26s\n# # CPU: 10 full images, nuclei + cells only: 4min7s\n# # GPU: 10 full images, nuclei + cells only: 1min36s\n# for filename in tqdm(submission_pd[ID][0:11]):\n#     img_full, _ = read_image_mask(filename, compose=None, normalize=True, norm_value=65535.0, images_root=TEST_HOME)\n#     print(filename, img_full.shape, img_full.dtype, img_full.max())\n#     nuclei_mask, cell_mask = generate_masks(img_full, nuclei_only=False)\n#     print(filename, \"nuclei\", len(np.unique(nuclei_mask)))\n\n# fig, ax = plt.subplots(1, 4, figsize=(20, 16))\n# d = ax[0].imshow(img_full[:,:,[0,1,2]])\n# d = ax[1].imshow(cell_mask) if cell_mask is not None else ax[1].imshow(nuclei_mask)\n# d = ax[2].imshow(img_full[:,:,[0,1,2]])\n# d = ax[2].imshow(cell_mask, alpha=0.30) if cell_mask is not None else None\n# d = ax[3].imshow(nuclei_mask) if nuclei_mask is not None else None","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Test loop\ndef test_loop_fn(batches, preprocessing, normalization, model, tmp_conf, device, stage=\"Test\", verbose=True):    \n    model.eval()\n    predictions = []\n    \n    with tqdm(batches, desc=stage, file=sys.stdout, disable=not(verbose)) as iterator:\n        for batch in iterator:\n            try:\n                # torch.cuda.empty_cache()\n                \n                for k, v in batch.items():\n                    if k in [\"image\"]:\n                        batch[k] = v.to(device)\n                \n                samples_data = batch.get(\"image\") # GPU [BS, 4, H, W] [0-1.0]\n                cell_masks = batch.get(\"mask\").numpy() if batch.get(\"mask\") is not None else None\n                nuclei_masks = batch.get(\"mask_nu\").numpy() if batch.get(\"mask_nu\") is not None else None\n                metas_data = batch.get(META).numpy()              \n\n                with torch.no_grad():\n                    # Preprocessing (Cells segmentation)\n                    masks_nu_data, masks_data = preprocessing(samples_data) if preprocessing is not None else (None, None)\n                    \n                    # Feed another model\n                    # Normalization (Std/Mean if not done before)\n                    data = normalization(samples_data) if normalization is not None else samples_data\n                    \n                    # NN model\n                    with torch.cuda.amp.autocast(enabled=tmp_conf.fp16):\n                        output = model(data) # forward pass\n                        if tmp_conf.mtype == \"siamese\":                            \n                            predicted_extras = output[tmp_conf.output_key_extra] if tmp_conf.output_key_extra is not None else None                                                    \n                            output = output[tmp_conf.output_key] if tmp_conf.output_key is not None else output\n                        else:                            \n                            predicted_extras = output[tmp_conf.output_key_extra] if tmp_conf.output_key_extra is not None else None                            \n                            output = output[tmp_conf.output_key] if tmp_conf.output_key is not None else output\n\n                    # Labels predictions\n                    predicted_probs = torch.sigmoid(output) if tmp_conf.post_activation == \"sigmoid\" else output\n                    \n                if preprocessing is not None:\n                    # Finalize nuclei, cells segmentation\n                    masks_nu_data = masks_nu_data.cpu().numpy().transpose([0, 2, 3, 1])\n                    masks_data = masks_data.cpu().numpy().transpose([0, 2, 3, 1]) # (BS, H, W, 3), float32 [0-1]\n                    # Background as zero\n                    masks_nu_data[..., 0] = 0\n                    masks_data[..., 0] = 0\n                    # Move to np.uint8 [0-255] range\n                    nuc_segmentations = list(map(util.img_as_ubyte, masks_nu_data))\n                    cell_segmentations = list(map(util.img_as_ubyte, masks_data))\n                    nuclei_masks, cell_masks = [], []\n                    for nuc_segmentation, cell_segmentation, meta_data in zip(nuc_segmentations, cell_segmentations, metas_data):\n                        if FAST_INSTANCES is True:\n                            # Auto scale because image size can be 4096, 2048, 3072, 1728\n                            auto_scale_factor = tmp_conf.image_size/meta_data[1] # tmp_conf.seg_scale_factor\n                            nuclei_mask_, cell_mask_ = label_cell_(nuc_segmentation, cell_segmentation, scale_factor=auto_scale_factor*auto_scale_factor) # tmp_conf.seg_scale_factor                                          \n                        else:\n                            # Resize to original image before applying morphology to extract instances\n                            nuc_segmentation = __resize_img(nuc_segmentation.astype(np.uint8), meta_data[1], meta_data[2])\n                            cell_segmentation = __resize_img(cell_segmentation.astype(np.uint8), meta_data[1], meta_data[2])\n                            auto_scale_factor = 1.0\n                            nuclei_mask_, cell_mask_ = label_cell_(nuc_segmentation, cell_segmentation, scale_factor=1.0)                 \n                            # Resize masks for further intersect with CAM: To improve\n                            nuclei_mask_ = __resize_masks(nuclei_mask_.astype(np.uint8), tmp_conf.image_size, tmp_conf.image_size)\n                            cell_mask_ = __resize_masks(cell_mask_.astype(np.uint8), tmp_conf.image_size, tmp_conf.image_size)\n                        nuclei_masks.append(nuclei_mask_)\n                        cell_masks.append(cell_mask_)\n                    nuclei_masks = np.expand_dims(np.array(nuclei_masks), axis=-1)\n                    cell_masks = np.expand_dims(np.array(cell_masks), axis=-1)                     \n\n                # Compute predictions from Pytorch model for this batch\n                tmp_result_ = compute_predictions(predicted_probs, predicted_extras, cell_masks, nuclei_masks, metas_data)\n                \n                # Compute predictions from TF model for this batch (H=512, W=512)\n                # images = (samples_data.cpu().numpy().transpose(0, 2, 3, 1)*255).astype(np.uint8) # (BS, H, W, 4) [0-255] \n                \n                # Compute predictions from Keras model for this batch (H=OriginalH, W=OriginalW)\n                images = batch.get(\"image_orig\").numpy() # (BS, H, W, 4) [0-255], # cell_masks # (BS, H, W, 1)\n                # print(\"images\", images.shape, images.dtype, images.max(), cell_masks.shape, cell_masks.dtype, cell_masks.max())\n                \n                # images_512 = data.cpu().numpy().transpose(0, 2, 3, 1) # (BS, H, W, 4)\n                images_512 = data # (BS, 4, H, W)\n\n                ensemble_result_ = []\n                for image, cells_mask, tmp_result, meta_data, image_512, nuclei_mask in zip(images, cell_masks, tmp_result_, metas_data, images_512, nuclei_masks):\n                    # Image meta-data\n                    uid = le_.inverse_transform([meta_data[0]])[0]\n                    orig_width = meta_data[1]\n                    orig_height = meta_data[2]                    \n                    \n                    cells_mask = cells_mask.squeeze() # (512, 512)\n                    nuclei_mask = nuclei_mask.squeeze() if nuclei_mask is not None else None # (512, 512)\n                    \n                    # Get per cell predictions from Pytorch model (extract single cell then predict)\n                    # It looks to act as regulization following classes distribution\n                    per_cell_predictions_generic_, cells_ids_ = per_cell_predictions_generic(image_512, cells_mask, model, tmp_conf, device, SUB_BATCH_SIZE=4)\n                    # print(\"per_cell_predictions_generic_\", per_cell_predictions_generic_.shape, cells_ids_.shape)\n                    \n                    # Resize mask to match image\n                    if cells_mask.shape[0] != image.shape[0]:\n                        cells_mask = __resize_masks(cells_mask, image.shape[1], image.shape[0])                    \n                    \n                    if nuclei_mask is not None:\n                        # Resize nuclei mask to match image\n                        if nuclei_mask.shape[0] != image.shape[0]:\n                            nuclei_mask = __resize_masks(nuclei_mask, image.shape[1], image.shape[0])              \n                    \n                    with torch.no_grad():\n                        # per_cell_predictions_dieter1_, cells_ids_dieter1_ = per_cell_predictions_dieter1(image, cells_mask, model_ch36, sub_batch_size=8, device=device)\n                        per_cell_predictions_dieter1_, cells_ids_dieter1_ = per_cell_predictions_dieter1(image, cells_mask, model_ch36 + model_ch54, sub_batch_size=8, device=device)\n                        per_cell_predictions_dieter2_, cells_ids_dieter2_ = per_cell_predictions_dieter2(image, cells_mask, model_ch_img_mask_4, sub_batch_size=None, device=device)\n                        per_cell_predictions_dieter3_ = per_cell_predictions_dieter3(image, cells_mask, model_ch_img_4_ext7, sub_batch_size=None, device=device)\n                        per_cell_predictions_dieter4_, cells_ids_dieter4_ = per_cell_predictions_dieter4(image, cells_mask, model_ch62, sub_batch_size=8, device=device)\n                        #                         print(per_cell_predictions_dieter2_)\n#                         print(cells_ids_dieter1_)\n#                         print(cells_ids_dieter2_)\n                    per_cell_predictions_dieter1_ = 0.666 * per_cell_predictions_dieter1_ + 0.333 * per_cell_predictions_dieter2_\n                    per_cell_predictions_dieter1_[:,:18] = 0.7 * per_cell_predictions_dieter1_[:,:18] + 0.3 * per_cell_predictions_dieter3_\n                    per_cell_predictions_dieter1_ = 0.5 * per_cell_predictions_dieter1_ + 0.5 * per_cell_predictions_dieter4_\n        \n                    # Get per cell predictions from TF model (5 channels)\n                    # per_cell_predictions_, cells_ids_ = per_cell_predictions(image, cells_mask, keras_model, mask_nuclei=None, aug_=aug_5ch, SUB_BATCH_SIZE=4) if keras_model is not None else (None, None) # (n_cells, 19), (n_cells,)\n\n                    # Get per cell predictions from TF model (6 channels)\n                    per_cell_predictions_, cells_ids_ = per_cell_predictions(image, cells_mask, keras_model, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model is not None else (None, None) # (n_cells, 19), (n_cells,)\n                    \n                    # Get per cell predictions from TF model (6 channels)\n                    per_cell_predictions_cl_, cells_ids_cl_ = per_cell_predictions(image, cells_mask, keras_model_cl, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=3) if keras_model_cl is not None else (None, None) # (n_cells, 19), (n_cells,)                    \n                    # per_cell_predictions_cl_, cells_ids_cl_ = per_cell_predictions(image, cells_mask, keras_model_cl, mask_nuclei=nuclei_mask, aug_=aug_large_6ch, SUB_BATCH_SIZE=2) if keras_model_cl is not None else (None, None) # (n_cells, 19), (n_cells,)                                        \n                    cells_ids_ = cells_ids_cl_ if cells_ids_ is None else cells_ids_\n                                        \n                    # per_cell_predictions_class11_, cells_ids_class11_ = per_cell_predictions(image, cells_mask, keras_model_class11, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class11 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    per_cell_predictions_class11_, cells_ids_class11_ = per_cell_predictions(image, cells_mask, keras_model_class11, mask_nuclei=nuclei_mask, aug_=aug_medium_6ch, SUB_BATCH_SIZE=2) if keras_model_class11 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                                                    \n                    per_cell_predictions_class4_, cells_ids_class4_ = per_cell_predictions(image, cells_mask, keras_model_class4, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class4 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    # per_cell_predictions_class6_, cells_ids_class6_ = per_cell_predictions(image, cells_mask, keras_model_class6, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class6 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    per_cell_predictions_class7_, cells_ids_class7_ = per_cell_predictions(image, cells_mask, keras_model_class7, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=3) if keras_model_class7 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    per_cell_predictions_class9_, cells_ids_class9_ = per_cell_predictions(image, cells_mask, keras_model_class9, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class9 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    \n                    # per_cell_predictions_class0_, cells_ids_class0_ = per_cell_predictions(image, cells_mask, keras_model_class0, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class0 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    # per_cell_predictions_class1_, cells_ids_class1_ = per_cell_predictions(image, cells_mask, keras_model_class1, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class1 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    # per_cell_predictions_class2_, cells_ids_class2_ = per_cell_predictions(image, cells_mask, keras_model_class2, mask_nuclei=nuclei_mask, aug_=aug_6ch, SUB_BATCH_SIZE=2) if keras_model_class2 is not None else (None, None) # (n_cells, 1), (n_cells,)\n                        \n                    per_cell_predictions_green_, cells_ids_green_ = per_cell_predictions(image, cells_mask, keras_model_green, mask_nuclei=None, aug_=aug_6ch, green_only=6, SUB_BATCH_SIZE=3) if keras_model_green is not None else (None, None) # (n_cells, 1), (n_cells,) #  WORKS!\n                    # per_cell_predictions_green_blue_, cells_ids_green_blue_ = per_cell_predictions(image, cells_mask, keras_model_green_blue, mask_nuclei=None, aug_=aug_6ch, green_only=5, SUB_BATCH_SIZE=3) if keras_model_green_blue is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    \n                    # per_cell_predictions_green_, cells_ids_green_ = per_cell_predictions(image, cells_mask, keras_model_green, mask_nuclei=None, aug_=aug_3ch, green_only=3, SUB_BATCH_SIZE=3) if keras_model_green is not None else (None, None) # (n_cells, 1), (n_cells,)\n                    per_cell_predictions_class11g_, cells_ids_class11g_ = per_cell_predictions(image, cells_mask, keras_model_class11g, mask_nuclei=None, aug_=aug_3ch, green_only=3, SUB_BATCH_SIZE=3) if keras_model_class11g is not None else (None, None) # (n_cells, 1), (n_cells,)\n                        \n                    # Get per cell predictions from Pytorch model (full image + intersection)\n                    cell_preds = np.zeros((len(cells_ids_), tmp_conf.num_classes), dtype=np.float32) # (n_cells, 19)\n                    for i, cell_id in enumerate(cells_ids_):                        \n                        for item in tmp_result[3]: # flatten_list = [ (cell_class1, cell_class1_confidence1, cell_mask1_rle, cell_id), (cell_class1, cell_class1_confidence2, cell_mask2_rle, cell_id) ...]\n                            if item[3] == cell_id:\n                                cell_preds[i, item[0]] = item[1]\n                                        \n                    # Ensemble (n_cells, 19), each cell could have 19 labels here\n                    per_cell_ensemble_pt = np.stack([per_cell_predictions_generic_, cell_preds], axis=0).mean(axis=0) # LB=0.514\n                                        \n                    # per_cell_ensemble_tf = np.stack([per_cell_predictions_, per_cell_predictions_cl_], axis=0).mean(axis=0) if per_cell_predictions_cl_ is not None else per_cell_predictions_ # LB=0.475/0.470                                        \n                    # per_cell_ensemble = np.stack([per_cell_ensemble_tf, per_cell_ensemble_pt], axis=0)\n                    # per_cell_ensemble = per_cell_ensemble.mean(axis=0)\n                    \n                    # per_cell_ensemble = 0.75 * per_cell_ensemble_pt + 0.25 * per_cell_predictions_\n                    \n                    #per_cell_predictions_class4_keras = per_cell_predictions_cl_[:, 4]\n                    #per_cell_predictions_class4_pt = per_cell_ensemble_pt[:, 4]\n                    #per_cell_predictions_class4_green = per_cell_predictions_green_[:, 4]\n                    \n                    # per_cell_ensemble = per_cell_predictions_\n                    \n                    # per_cell_ensemble = 0.55 * per_cell_ensemble_pt + 0.35 * per_cell_predictions_cl_ + 0.10 * per_cell_predictions_green_\n                    \n                    per_cell_ensemble = 0.60 * per_cell_ensemble_pt + 0.275 * per_cell_predictions_cl_ + 0.125 * per_cell_predictions_green_ # => Best\n                    \n                    # per_cell_predictions_green_blue__ = 0.60*per_cell_predictions_green_ + 0.40*per_cell_predictions_green_blue_\n                    # per_cell_ensemble = 0.60 * per_cell_ensemble_pt + 0.275 * per_cell_predictions_cl_ + 0.125 * per_cell_predictions_green_blue__                    \n                    # per_cell_ensemble = 0.65 * per_cell_ensemble_pt + 0.25 * per_cell_predictions_cl_ + 0.10 * per_cell_predictions_green_ # 0.589\n                    # per_cell_ensemble = 0.70 * per_cell_ensemble_pt + 0.225 * per_cell_predictions_cl_ + 0.075 * per_cell_predictions_green_ # 0.587\n                    \n                    # per_cell_ensemble = 0.65 * per_cell_ensemble_pt + 0.20 * per_cell_predictions_cl_ + 0.05 * per_cell_predictions_ + 0.10 * per_cell_predictions_green_\n\n                    \n                    # Class 11 models\n                    # per_cell_ensemble[:, 11] = 0.5 * per_cell_predictions_cl_[:, 11] + 0.5 * per_cell_predictions_class11_[:, 0] # It works! (ZFTurbo 0.497 + single class1 0.012) => 0.579\n                    # per_cell_ensemble[:, 11] = 0.5 * per_cell_ensemble[:, 11] + 0.5 * per_cell_predictions_class11_[:, 0] # It works! (MPWARE 0.514 + ZFTurbo 0.497 + single class11 0.012) =>                     \n                    # per_cell_ensemble[:, 11] = 0.4 * per_cell_ensemble[:, 11] + 0.6 * per_cell_predictions_class11_[:, 0] # It works! (MPWARE 0.514 + ZFTurbo 0.497 + single class11 0.012) => Best                    \n                    per_cell_ensemble[:, 11] = 0.4 * per_cell_ensemble[:, 11] + 0.3 * per_cell_predictions_class11_[:, 0] + 0.3 * per_cell_predictions_class11g_[:, 0] #=> Best                    \n                    \n                    # Different ensemble for class6\n                    # per_cell_ensemble[:, 6] = 0.7 * per_cell_ensemble[:, 6] + 0.3 * per_cell_predictions_class6_[:, 0] \n                    \n                    # Different ensemble for class7\n                    # per_cell_ensemble[:, 7] = 0.7 * per_cell_ensemble[:, 7] + 0.3 * per_cell_predictions_class7_[:, 0] # Works\n                                        \n                    # per_cell_ensemble_final = 0.90 * per_cell_ensemble + 0.10 * per_cell_predictions_dieter1_\n                    per_cell_ensemble_final = 0.85 * per_cell_ensemble + 0.15 * per_cell_predictions_dieter1_\n                    \n                    # per_cell_ensemble[:, 9] = 0.7 * per_cell_ensemble[:, 9] + 0.3 * per_cell_predictions_class9_[:, 0]\n                    \n                    # Different ensemble for class4\n                    # per_cell_ensemble[:, 4] = 0.6 * per_cell_ensemble[:, 4] + 0.4 * per_cell_predictions_class4_[:, 0] \n                    \n                    # Different ensemble for class\n                    # per_cell_ensemble[:, 0] = 0.6 * per_cell_ensemble[:, 0] + 0.4 * per_cell_predictions_class0_[:, 0]  \n                    # per_cell_ensemble[:, 1] = 0.6 * per_cell_ensemble[:, 1] + 0.4 * per_cell_predictions_class1_[:, 0] \n                    # per_cell_ensemble[:, 2] = 0.6 * per_cell_ensemble[:, 2] + 0.4 * per_cell_predictions_class2_[:, 0] \n                    \n                    # Class 4 model\n                    # per_cell_ensemble[:, 4] = 0.45 * per_cell_predictions_class4_pt + 0.45 * per_cell_predictions_class4_keras + 0.10 * per_cell_predictions_class4_green             \n                    \n                    # per_cell_ensemble = 0.70 * per_cell_ensemble_pt + 0.25 * per_cell_predictions_ + 0.05 * per_cell_predictions_cl_\n                    # per_cell_ensemble = 0.70 * per_cell_ensemble_pt + 0.15 * per_cell_predictions_ + 0.15 * per_cell_predictions_cl_\n                    # per_cell_ensemble = 0.65 * per_cell_ensemble_pt + 0.30 * per_cell_predictions_ + 0.05 * per_cell_predictions_cl_\n                    \n                    # per_cell_ensemble = 0.65 * per_cell_ensemble_pt + 0.35 * per_cell_predictions_\n                    #per_cell_ensemble = 0.60 * per_cell_ensemble_pt + 0.40 * per_cell_predictions_\n                    #per_cell_ensemble = 0.55 * per_cell_ensemble_pt + 0.45 * per_cell_predictions_\n                    #per_cell_ensemble = 0.50 * per_cell_ensemble_pt + 0.50 * per_cell_predictions_\n                    #per_cell_ensemble = 0.475 * per_cell_ensemble_pt + 0.475 * per_cell_predictions_ + 0.05 * per_cell_predictions_cl_\n                    #per_cell_ensemble = 0.40 * per_cell_ensemble_pt + 0.50 * per_cell_predictions_ + 0.10 * per_cell_predictions_cl_\n                    \n                    # print(\"per_cell_ensemble\", per_cell_ensemble.shape)\n                                        \n                    # Rebuild candidates cells for this image\n                    flatten_list = []\n                    for cell_id, ensemble_probs in zip(cells_ids_, per_cell_ensemble_final): # per_cell_ensemble\n                        # Get mask already computed for this cell (original size)\n                        cell_mask_rle = None\n                        for item in tmp_result[3]:\n                            if item[3] == cell_id:\n                                cell_mask_rle = item[2]\n                                break\n                        if cell_mask_rle is not None:\n                            # Select classes predicted for this cell\n                            flatten_list_ = []\n                            # Filter classes\n                            candidates = [(class_id, ensemble_class_prob) for class_id, ensemble_class_prob in enumerate(ensemble_probs) if ensemble_class_prob > ENSEMBLE_THR]\n                            # Sort by highest confidence and keep ENSEMBLE_TOP_N_PER_CELL\n                            candidates = sorted(candidates, key=operator.itemgetter(1), reverse=True)[:ENSEMBLE_TOP_N_PER_CELL]    \n                            \n                            for j, pair in enumerate(candidates):\n                                class_id, ensemble_class_prob = pair[0], pair[1]\n                                # Check if highest probability for this cell is NEGATIVE\n                                if j == 0 and class_id == NEGATIVE_CLASS and ensemble_class_prob > NEGATIVE_CLASS_ONLY_MIN_THR:\n                                    print(\"NEGATIVE high probability detected, discard other classes\", class_id, ensemble_class_prob)\n                                    flatten_list_.append((class_id, ensemble_class_prob, cell_mask_rle, cell_id))\n                                    break\n                                else:\n                                    flatten_list_.append((class_id, ensemble_class_prob, cell_mask_rle, cell_id))\n                                \n                            #for pair in candidates:\n                            #    class_id, ensemble_class_prob = pair[0], pair[1]                                \n                            #    #if len(flatten_list_) > 0 and class_id == NEGATIVE_CLASS:\n                            #    #    pass\n                            #    #    # print(\"Warning, NEGATIVE class for one cell cannot be mixed with other classes on %s, %s\" % (uid, pair))\n                            #    #    # print(\"Warning, NEGATIVE class for one cell cannot be mixed with other classes on %s, %s, %s\" % (uid, ensemble_probs, pair))\n                            #    #else:\n                            #    #    flatten_list_.append((class_id, ensemble_class_prob, cell_mask_rle, cell_id))\n                            #    flatten_list_.append((class_id, ensemble_class_prob, cell_mask_rle, cell_id))                                \n                                \n                            if len(flatten_list_) == 0:\n                                # No class detected for this cell, set it as NEGATIVE_CLASS \n                                flatten_list_.append((NEGATIVE_CLASS, (1.0 - np.nanmax(ensemble_probs)), cell_mask_rle, cell_id)) # (1.0 - np.nanmax(ensemble_probs), anything better? \n                            flatten_list.extend(flatten_list_)                                                        \n                        else:\n                            print(\"Warning: Cell %d not found for %s\" % (cell_id, uid))\n                                        \n                    # Ensemble results for each image\n                    ensemble_result_.append((uid, orig_width, orig_height, flatten_list))\n                \n                tmp_result_ = ensemble_result_\n                                \n                predictions.extend(tmp_result_)\n\n            except Exception as ex:\n                print(\"Test batch error:\", ex)\n    \n    return predictions","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DELTA = 0 # 100\nSHAPE_SIZE_3CH = (224, 224, 3)\nSHAPE_SIZE_5CH = (224, 224, 5)\nSHAPE_SIZE_6CH = (224, 224, 6)\nSHAPE_LARGE_SIZE_6CH = (360, 360, 6)\nSHAPE_MEDIUM_SIZE_6CH = (300, 300, 6)\n\ndef get_valid_transforms_3ch():\n    return A.Compose(\n        [\n            A.Resize(height=SHAPE_SIZE_3CH[0], width=SHAPE_SIZE_3CH[1], p=1),\n            A.Normalize(\n                mean=(0.5, 0.5, 0.5),\n                std=(0.225, 0.225, 0.225)\n            ),\n        ],\n        p=1.0\n    )\n\naug_3ch = get_valid_transforms_3ch()\n\ndef get_valid_transforms_5ch():\n    return A.Compose(\n        [\n            A.Resize(height=SHAPE_SIZE_5CH[0], width=SHAPE_SIZE_5CH[1], p=1),\n            A.Normalize(\n                mean=(0.5, 0.5, 0.5, 0.5, 0.5),\n                std=(0.225, 0.225, 0.225, 0.225, 0.225)\n            ),\n        ],\n        p=1.0\n    )\n\naug_5ch = get_valid_transforms_5ch()\n\ndef get_valid_transforms_6ch():\n    return A.Compose(\n        [\n            A.Resize(height=SHAPE_SIZE_6CH[0], width=SHAPE_SIZE_6CH[1], p=1),\n            A.Normalize(\n                mean=(0.5, 0.5, 0.5, 0.5, 0.5, 0.5),\n                std=(0.225, 0.225, 0.225, 0.225, 0.225, 0.225)\n            ),\n        ],\n        p=1.0\n    )\n\naug_6ch = get_valid_transforms_6ch()\n\ndef get_valid_transforms_large_6ch():\n    return A.Compose(\n        [\n            A.Resize(height=SHAPE_LARGE_SIZE_6CH[0], width=SHAPE_LARGE_SIZE_6CH[1], p=1),\n            A.Normalize(\n                mean=(0.5, 0.5, 0.5, 0.5, 0.5, 0.5),\n                std=(0.225, 0.225, 0.225, 0.225, 0.225, 0.225)\n            ),\n        ],\n        p=1.0\n    )\n\naug_large_6ch = get_valid_transforms_large_6ch()\n\ndef get_valid_transforms_medium_6ch():\n    return A.Compose(\n        [\n            A.Resize(height=SHAPE_MEDIUM_SIZE_6CH[0], width=SHAPE_MEDIUM_SIZE_6CH[1], p=1),\n            A.Normalize(\n                mean=(0.5, 0.5, 0.5, 0.5, 0.5, 0.5),\n                std=(0.225, 0.225, 0.225, 0.225, 0.225, 0.225)\n            ),\n        ],\n        p=1.0\n    )\n\naug_medium_6ch = get_valid_transforms_medium_6ch()\n\n\n# def preproc_input(x):\n#    return _preprocess_input(x, mode='torch', data_format='channels_last')\n\ndef bbox2_int(img):\n    rows = np.any(img, axis=1)\n    cols = np.any(img, axis=0)\n    rmin, rmax = np.where(rows)[0][[0, -1]]\n    cmin, cmax = np.where(cols)[0][[0, -1]]\n\n    x1 = cmin\n    x2 = (cmax + 1)\n    y1 = rmin\n    y2 = (rmax + 1)\n\n    return x1, x2, y1, y2\n\n# Image must be (H, W, 4) [0-255], Mask (H, W)\ndef per_cell_predictions(orig_img, mask_cell, keras_model_, mask_nuclei=None, aug_=None, green_only=0, SUB_BATCH_SIZE=8):\n    \n    all_preds = None\n    \n    # 224x224x5 cells images    \n    cell_ids = np.array([c for c in np.unique(mask_cell) if c > 0]) # Remove background\n    cell_ids_batches = np.array_split(cell_ids, (len(cell_ids)//SUB_BATCH_SIZE) + 1)\n    \n    for cell_ids_batch in cell_ids_batches:\n        # Prepare sub batch, total = SUB_BATCH_SIZE x TTAs\n        small_images = [] \n        for cell_id in cell_ids_batch:            \n            part = (mask_cell == cell_id).astype(np.uint8) * 255\n            \n            part_nuclei = (mask_nuclei == cell_id).astype(np.uint8) * 255 if mask_nuclei is not None else None\n\n            # Extract Bounding Box from cell mask\n            x1, x2, y1, y2 = bbox2_int(part)\n\n            # Add DELTA margin\n            x1_cut = max(0, x1 - DELTA)\n            y1_cut = max(0, y1 - DELTA)\n            x2_cut = min(part.shape[1], x2 + DELTA)\n            y2_cut = min(part.shape[0], y2 + DELTA)\n            mask_part = part[y1_cut:y2_cut, x1_cut:x2_cut]\n            \n            nuclei_part = part_nuclei[y1_cut:y2_cut, x1_cut:x2_cut] if part_nuclei is not None else None\n            \n            mask_part_small = part[y1:y2, x1:x2]\n\n            # Extract box from RGBY image\n            img_part = orig_img[y1_cut:y2_cut, x1_cut:x2_cut]\n            r = img_part[..., 0].copy()\n            g = img_part[..., 1].copy()\n            b = img_part[..., 2].copy()\n            y = img_part[..., 3].copy()\n            m = mask_part.copy()\n            \n            n = nuclei_part.copy() if nuclei_part is not None else None\n\n            # Build input image\n            if green_only > 0:\n                if green_only == 6:\n                    img = np.stack([g, g, g, g, g, g], axis=-1) # Greenx6\n                elif green_only == 5:\n                    img = np.stack([g, g, g, b, b, b], axis=-1) # Greenx3/Bluex3\n                else:\n                    img = np.stack([g, g, g], axis=-1) # Greenx3\n            else:\n                # Add channel 5 with mask\n                img = np.stack([r, g, b, y, m], axis=-1) if n is None else np.stack([r, g, b, y, m, n], axis=-1)\n\n            # Resize to 224x224 or 300x300 or 360x360\n            img = aug_(image=img)['image'] if aug_ is not None else img\n            \n            # img = aug_5ch(image=img)['image'] if n is None else aug_6ch(image=img)['image'] # Convert to [0-1.0] + Z-Norm (5 or 6 channels)\n\n            # TTA\n            small_images.append(img)\n            small_images.append(img[:, ::-1, :])\n\n        small_images = np.array(small_images, dtype=np.float32)\n        # Predict\n        preds = keras_model_.predict(small_images, batch_size=8) # TF batch size default is 32\n        \n        # TTA average\n        tta_len = 2\n        preds = np.add.reduceat(preds, np.arange(0, len(preds), tta_len)) / tta_len\n\n        # Concatenate preds for all sub-batches\n        all_preds = np.concatenate([all_preds, preds]) if all_preds is not None else preds\n    \n    # One line per cell\n    return all_preds, cell_ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CENTER_PAD = 384 # 0\n\ndef get_test_transforms():\n    return A.Compose(\n        [\n            A.PadIfNeeded(min_height=CENTER_PAD, min_width=CENTER_PAD, border_mode=cv2.BORDER_CONSTANT, value=0, always_apply=True, p=1.0),\n            A.Resize(CENTER_PAD, CENTER_PAD, interpolation=cv2.INTER_LINEAR, always_apply=True, p=1.0),\n        ],\n        p=1.0\n    )\n\naug_test = get_test_transforms()\n\n# Image must be Tensor (4, H, W) Z-Norm, Mask must be numpy (H, W)\ndef per_cell_predictions_generic(image, mask_cell, model, tmp_conf, device, SUB_BATCH_SIZE=8):    \n    # Segmented cells\n    cell_ids = np.array([c for c in np.unique(mask_cell) if c > 0])\n    cell_ids_batches = np.array_split(cell_ids, (len(cell_ids)//SUB_BATCH_SIZE) + 1)\n    cells_predicted_probs = None\n    for cell_ids_batch in cell_ids_batches:\n        # Prepare sub batch\n        cell_images = []      \n        for cell_id in cell_ids_batch:\n            \n            if CENTER_PAD is not None and CENTER_PAD > 0: # +0.002 on LB as PT model was trained with 384x384 crop       \n                part = (mask_cell == cell_id).astype(np.uint8)\n                # Extract Bounding Box from cell mask\n                x1, x2, y1, y2 = bbox2_int(part)\n                x1_cut = max(0, x1)\n                y1_cut = max(0, y1)\n                x2_cut = min(part.shape[1], x2)\n                y2_cut = min(part.shape[0], y2)\n                mask_part = part[y1_cut:y2_cut, x1_cut:x2_cut] # (H', W')\n                # Extract box from RGBY image\n                img_part = image[:, y1_cut:y2_cut, x1_cut:x2_cut] # (4, H', W')\n                cell_mask_bool = torch.from_numpy(mask_part).to(device) # One cell mask (H', W')                        \n                cell_image = img_part * torch.stack([cell_mask_bool for i in range(image.shape[0])], dim=0) # One cell image (4, H', W')\n                # Convert to 384x384: TO IMPROVE, perform such operation in GPU to avoid GPU/CPU/GPU roundtrip\n                cell_image = aug_test(image=cell_image.cpu().numpy().transpose(1,2,0))['image'] \n                cell_image = torch.from_numpy(cell_image.transpose(2, 0, 1)).to(device)                \n            \n            else:\n                cell_mask_bool = torch.from_numpy((mask_cell == cell_id).astype(np.uint8)).to(device) # One cell mask (H, W)                        \n                # (4, H, W) * (4, H, W)\n                cell_image = image * torch.stack([cell_mask_bool for i in range(image.shape[0])], dim=0) # One cell image (4, H, W)            \n            \n            cell_images.append(cell_image)\n        cell_images = torch.stack(cell_images, dim=0) # (SUB_BATCH_SIZE, 4, H, W) # GPU        \n        # Predict for a few individual cells\n        with torch.no_grad():\n            # NN model\n            with torch.cuda.amp.autocast(enabled=tmp_conf.fp16):\n                output = model(cell_images) # forward pass\n                if tmp_conf.mtype == \"siamese\":                            \n                    predicted_extras = output[tmp_conf.output_key_extra] if tmp_conf.output_key_extra is not None else None                                                    \n                    output = output[tmp_conf.output_key] if tmp_conf.output_key is not None else output\n                else:                            \n                    predicted_extras = output[tmp_conf.output_key_extra] if tmp_conf.output_key_extra is not None else None                            \n                    output = output[tmp_conf.output_key] if tmp_conf.output_key is not None else output        \n                # Labels predictions\n                predicted_probs = torch.sigmoid(output) if tmp_conf.post_activation == \"sigmoid\" else output # (SUB_BATCH_SIZE, 19) # GPU                \n        predicted_probs = predicted_probs.cpu().numpy()        \n        cells_predicted_probs = np.concatenate([cells_predicted_probs, predicted_probs], axis=0) if cells_predicted_probs is not None else predicted_probs\n    # One line per cell\n    return cells_predicted_probs, cell_ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def resize_and_rle_encode_one_cell(target_masks, cell_id, orig_width, orig_height):\n    mask_bool = target_masks.squeeze() == cell_id\n    mask_bool = cv2.resize(mask_bool.astype(np.uint8), (orig_width, orig_height), interpolation = cv2.INTER_AREA)\n    mask_bool = np.clip(mask_bool, 0, 1).astype('bool')\n    cell_rle = encode_binary_mask(mask_bool)\n    return cell_rle","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def find_centers_countours(ids, masks, bb=None):\n    centers_ = {}\n    for uid in ids:\n        try:\n            contours, hierarchy= cv2.findContours((masks.squeeze() == uid).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n            M = cv2.moments(contours[0])\n            cX = int(M[\"m10\"] / M[\"m00\"])\n            cY = int(M[\"m01\"] / M[\"m00\"])\n            if bb is not None:\n                if not (bb[0] < cY < bb[0]+bb[2] and bb[1] < cX < bb[1]+bb[3]):\n                    centers_[uid] = (cX, cY, contours[0])\n            else:\n                centers_[uid] = (cX, cY, contours[0])\n        except Exception as e:\n            pass\n    return centers_\n\ndef get_border_cells_ids(target_masks, target_masks_nu):\n    border_cells = {}\n    if BORDER_SIZE_PERCENT > 0:\n        cell_ids = [c for c in np.unique(target_masks) if c > 0]\n        nu_ids = [c for c in np.unique(target_masks_nu) if c > 0]\n        # Nuclei is used as seed so we should have the same total? Answer is NO\n        cells_with_nu = np.intersect1d(np.array(cell_ids), np.array(nu_ids))\n        # Find center of each nucluei (if available) outside a bounding box\n        border_cells = find_centers_countours(cells_with_nu, target_masks_nu, bb=(int(np.round(target_masks_nu.shape[0]*BORDER_SIZE_PERCENT)), int(np.round(target_masks_nu.shape[1]*BORDER_SIZE_PERCENT)),\n                                                                                  int(np.round(target_masks_nu.shape[0]*(1-2*BORDER_SIZE_PERCENT))), int(np.round(target_masks_nu.shape[1]*(1-2*BORDER_SIZE_PERCENT)))) )\n    return border_cells","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# preds: [(class_id, class_prob), ...] for selected classes above THR\n# predicted_cams: CAMs generated from features model output (BS, CLASSES, N, N)\n# target_masks: cells masks\n# target_masks_nu: nuclei masks\n# cell_ids: list of cells identifier to predict\n# image: optional for debug\n# Return dictionary per cell_id = { class_id: {\"class_prob\": ..., \"cell_conf\": ..., other meta data} ...}\ndef cells_prediction_puzzlecam(selected_class_preds, predicted_cams, target_masks, target_masks_nu, cell_ids, image=None):    \n    cells_masks_meta = dict()\n    empty_intersection = False\n    \n    # Only on confident predicted classes\n    for pair in selected_class_preds:\n        class_, class_prob_ = pair[0], pair[1]\n        \n        # Cam for the predicted class\n        cam_class_ = predicted_cams[class_].astype(np.float32) # (Hc, Wc)\n        \n        # Interpolated cam to initial size (different interpolation to test as results are different especially on borders)        \n        cam_class_ = skimage.transform.resize(cam_class_, (target_masks.shape[1], target_masks.shape[0]), anti_aliasing=True) # Works with float32 image\n        \n        # Quantile for full image\n        total_class_cam_qt = np.quantile(cam_class_.flatten(), CAM_PRED_QUANTILE)\n        \n        # Find cells for the predicted class\n        for cell_id in cell_ids:\n            cell_mask_bool = target_masks.squeeze() == cell_id\n            \n            # Cam/mask intersection + quantile for cell only\n            cell_class_cam_qt = np.quantile(cam_class_[cell_mask_bool], CAM_PRED_QUANTILE)\n            cell_class_cam_max = cam_class_[cell_mask_bool].max()\n            # Cell confidence\n            cell_conf = np.clip(cell_class_cam_qt*class_prob_/total_class_cam_qt, 0, class_prob_)\n            # Final score\n            score = cell_conf/class_prob_\n            if score > SCORE_TH:\n                # We keep this cell                \n                meta_coords_centroid = (int(np.where(cell_mask_bool)[1].mean()), int(np.where(cell_mask_bool)[0].mean()) ) # Cell centroid\n                meta_coords_max = (np.where(cam_class_ == cell_class_cam_max)[1][0], np.where(cam_class_ == cell_class_cam_max)[0][0])\n                cell_dict_ = {\"class_prob\": class_prob_, \"total_class_cam_qt\": total_class_cam_qt, \"cell_class_cam_qt\": cell_class_cam_qt, \"cell_class_cam_max\": cell_class_cam_max, CELL_CONF: cell_conf, \"score\": score, \"meta_coords_max\": meta_coords_max, \"meta_coords_centroid\": meta_coords_centroid}\n                if cell_id not in cells_masks_meta:\n                    cells_masks_meta[cell_id] = {class_: cell_dict_}\n                else:\n                     cells_masks_meta[cell_id][class_] = cell_dict_\n            else:\n                empty_intersection = True\n        \n        if image is not None:\n            cam = cv2.applyColorMap((cam_class_*255).astype(np.uint8), cv2.COLORMAP_JET)\n            image = cv2.addWeighted(image, 0.5, cam, 0.5, 0)[..., ::-1]        \n        \n    return cells_masks_meta, empty_intersection, image","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def compute_predictions(all_predicted_probs, all_predicted_extras, all_target_masks, all_target_masks_nu, all_metas_data):\n    \n    results = []\n    \n    # Compute CAMs on GPU then move to CPU\n    all_predicted_cams = make_cam(all_predicted_extras).cpu().numpy()\n    \n    # Move other Tensors to CPU\n    all_target_masks = all_target_masks # .cpu().numpy()\n    all_target_masks_nu = all_target_masks_nu # .cpu().numpy()\n    all_metas_data = all_metas_data # .cpu().numpy()\n    all_predicted_probs = all_predicted_probs.cpu().numpy()\n    \n    for predicted_probs, predicted_cams, target_masks, target_masks_nu, metas_data in zip(all_predicted_probs, all_predicted_cams, all_target_masks, all_target_masks_nu, all_metas_data):\n        # Image uid\n        uid = le_.inverse_transform([metas_data[0]])[0]\n        orig_width = metas_data[1]\n        orig_height = metas_data[2]\n                \n        # Class predicted\n        preds = [(i, x) for i, x in enumerate(predicted_probs) if x > CLASS_PRED_THR]\n        \n        # Detected cells (without background)\n        cell_ids = [c for c in np.unique(target_masks) if c > 0]        \n        \n        # --------------------\n        # Identify border cells\n        # Remove border cells: A good rule of thumb (that our annotators used in generating ground truth) is if more than half of the cell is not present, don't predict it!\n        border_cells = get_border_cells_ids(target_masks, target_masks_nu) \n\n        # --------------------\n        # Per cell predictions    \n        cells_masks_meta, empty_intersection, image = cells_prediction_(preds, predicted_cams, target_masks, target_masks_nu, cell_ids, image=None)\n                            \n        # --------------------\n        # Per class prediction\n        cell_class_ids = defaultdict(list)\n        cell_class_confidences_rle = defaultdict(list)\n        for cell_id, cell_dict in cells_masks_meta.items():\n            for cell_class, cell_meta in cell_dict.items():\n                # Find unique cells per class\n                ids = cell_class_ids[cell_class]            \n                if cell_id not in ids:\n                    ids.extend([cell_id])\n                    confidences_list = cell_class_confidences_rle[cell_class]                \n                    # Extract cell mask, resize and encode\n                    cell_rle = resize_and_rle_encode_one_cell(target_masks, cell_id, orig_width, orig_height) \n                    confidences_list.extend([(cell_class, cell_meta[CELL_CONF], cell_rle, cell_id)])\n        \n        # Flatten all list for each class (Fixed!)\n        flatten_list = None\n        for cell_class, cells_ids in cell_class_ids.items():\n            confidences_list_ = cell_class_confidences_rle[cell_class] # [ (cell_class1, cell_class1_confidence1, cell_mask1_rle, cell_id), (cell_class1, cell_class1_confidence2, cell_mask2_rle, cell_id) ...]\n            if flatten_list is None:\n                flatten_list = confidences_list_  \n            else:\n                flatten_list.extend(confidences_list_)\n\n        # Nothing detected, RLE encode all cells (if available) with Negative class. It could be because:\n        # No cells/masks detected by segmentation\n        # No class detected (all class_prob below THR)\n        # No cells/cams intersection\n        # Detected cells must be labeled as Negative\n        if flatten_list is None:\n            print(\"%s - Nothing detected\" % uid)\n            flatten_list = [] if len(cell_ids) > 0 else None\n            for cell_id in cell_ids:\n                cell_rle = resize_and_rle_encode_one_cell(target_masks, cell_id, orig_width, orig_height)\n                negative_conf = np.nanmax(predicted_probs) if empty_intersection is True else (1.0 - np.nanmax(predicted_probs))\n                flatten_list.append((NEGATIVE_CLASS, negative_conf, cell_rle, cell_id))\n        else:\n            # Final cleanup\n            # Sort detected class by max confidence and clip on TOP_N_PER_IMAGE\n            unique_class_max_confidence = defaultdict(float)\n            for item in flatten_list:\n                confidence_ = unique_class_max_confidence[item[0]] # 0 if not set\n                unique_class_max_confidence[item[0]] = max(item[1], confidence_)\n            unique_class_max_confidence = OrderedDict(sorted(unique_class_max_confidence.items(), key=operator.itemgetter(1), reverse=True)[:TOP_N_PER_IMAGE]) # [:TOP_N_PER_IMAGE]\n            if (NEGATIVE_CLASS in list(unique_class_max_confidence.keys())):\n                print(\"%s - Warning 'Negative' class might be mixed\" % uid)\n            # Keep cells with filtered TOP_N classes per image\n            flatten_list = [item for item in flatten_list if item[0] in list(unique_class_max_confidence.keys())]        \n            # All non-labeled cells must be labeled as Negative\n            if LABEL_MISSING_AS_NEGATIVE is True:\n                missing_labeled_cells_ids = np.setxor1d(np.array(cell_ids), np.array([item[3] for item in flatten_list]))\n                if len(missing_labeled_cells_ids) > 0:\n                    # print(\"%s - Missing labels for cells, Negative label applied\" % uid, missing_labeled_cells_ids)\n                    for missing_cell_id in missing_labeled_cells_ids:\n                        # What confidence should we set here? predicted_probs[NEGATIVE_CLASS] or 1-predicted_probs[NEGATIVE_CLASS] or or 1-max(predicted_probs[NEGATIVE_CLASS]) ?\n                        flatten_list.append((NEGATIVE_CLASS, predicted_probs[NEGATIVE_CLASS], resize_and_rle_encode_one_cell(target_masks, missing_cell_id, orig_width, orig_height), missing_cell_id))\n        \n        # Remove border cells (if any)\n        # print(\"%s border cells\" % uid, list(border_cells.keys()))\n        flatten_list = [item for item in flatten_list if item[3] not in list(border_cells.keys())] if flatten_list is not None else None\n        \n        results.append((uid, orig_width, orig_height, flatten_list))\n            \n    return results","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NEGATIVE_CLASS = 18\nLABEL_MISSING_AS_NEGATIVE = True\nBORDER_SIZE_PERCENT = 0 # 0.005 # 0.5%\n\n# CAM/Segmented cells intersection: Different solutions/approaches\ncells_prediction_ = cells_prediction_puzzlecam # cells_prediction_puzzlecam_nu\n\nTOP_N_PER_IMAGE = 18 # 19 # 18 # 8 # 4 # TOP_N classes max per image: 3 to 5 (only used for Pytorch model)\nCLASS_PRED_THR = 0.01 # 0.001 # 0.01 # 0.05 # 0.1 # 0.2 # 0.2 # 0.3 # 0.4 # 0.5 # 0.6 # 0.125 # 0.25\nCAM_PRED_QUANTILE = 0.99 # 0.995 # 0.97 # 0.95 # 0.95 # 0.90\nSCORE_TH = 0.02 # 0.01 # 0.02 # 0.03 # 0.0625 # 0.04 # 0.0625 # 0.125 # 0.25 # 0.5 # 0.9\n\n# Class confidence threshold for ensemble\nENSEMBLE_TOP_N_PER_CELL = 19 # 18 # 8 # 4\nENSEMBLE_THR = 0.001 # 0.005\nNEGATIVE_CLASS_ONLY_MIN_THR = 1.0 # 1.0 # 0.99 # 0.9 # 0.5\n\n# Pytorch TTA (no real boost, any bug?)\nLOCAL_TTAS = None # [ident, vflip, hflip] # None\nmodel_ = EnsembleTTA(model_, ttas=LOCAL_TTAS) if LOCAL_TTAS is not None else model_","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = conf.L_DEVICE\ntest_pd = submission_pd if SANITY is False else submission_pd.head(SANITY_SIZE)\n\nfactory = DataFactory(TEST_HOME, None, conf=conf, verbose=True)\ndataset = HPADataset(test_pd, factory, conf, subset=\"test\", verbose=False, augment=None, modelprepare=get_preprocessing(model_.preprocess_input_fn))\nprint(\"Device:\", device, \"workers:\", conf.WORKERS, \"post_activation:\", conf.post_activation, \"batch size:\", conf.BATCH_SIZE, \"test dataset:\", len(dataset), \n      \"num_classes:\", conf.num_classes, \"fp16:\", conf.fp16, \"compose:\", conf.compose, \"seg_scale_factor\", conf.seg_scale_factor)\n    \nloader = DataLoader(dataset, batch_size=conf.BATCH_SIZE, num_workers=conf.WORKERS if ON_FLY_MASK is True else 0, drop_last = False, pin_memory=conf.pin_memory, sampler=None, shuffle=False)\n\npredictions_ = test_loop_fn(loader, segmentator_, normalizer_, model_, conf, device)\n\nfactory.cleanup()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# predictions_ if SANITY is True else None","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"CLEANUP_NEGATIVE:\", CLEANUP_NEGATIVE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions_pd = []\nfor prediction_ in predictions_:\n    uid, orig_width, orig_height, flatten_list = prediction_\n    predicted_string = \"\"\n    if flatten_list is not None: # None means no cells detected        \n        #print(\"uid\", uid)\n        remove_negative = set()\n        if CLEANUP_NEGATIVE is True:\n            labels_per_cell = {}\n            # For each cell\n            for item in flatten_list:\n                cell_class, cell_class_confidence, cell_mask1_rle, cell_id = item\n                labels_dict = labels_per_cell.get(cell_id)\n                if labels_dict is None:\n                    labels_dict = {cell_class: cell_class_confidence}\n                else:\n                    conf = labels_dict.get(cell_class)\n                    if conf is None:\n                        labels_dict[cell_class] = cell_class_confidence\n                    else:\n                        if cell_class_confidence > conf:\n                            labels_dict[cell_class] = cell_class_confidence\n                labels_per_cell[cell_id] = labels_dict\n\n            for cell_id, labels_dict in labels_per_cell.items():\n                unique_class_max_confidence = OrderedDict(sorted(labels_dict.items(), key=operator.itemgetter(1), reverse=True))\n                \n                unique_classes = list(unique_class_max_confidence.keys())\n                # print(unique_classes)\n                # print(cell_id, unique_class_max_confidence)            \n                if (NEGATIVE_CLASS in unique_classes and len(unique_classes) > 1 and (unique_classes[-1] == NEGATIVE_CLASS or unique_classes[-2] == NEGATIVE_CLASS)):\n                    # print(\"%s - 'Negative' class mixed\" % (cell_id))\n                    remove_negative.add(cell_id)\n                #else:\n                #    print(\"%s - 'Negative' class allowed\" % (cell_id))\n                # print()\n            \n        for item in flatten_list:\n            cell_class, cell_class_confidence, cell_mask1_rle, cell_id = item\n            if cell_id in remove_negative and cell_class == NEGATIVE_CLASS:\n                # print(\"Remove Negative for cell %s, %s\" % (cell_id, uid))\n                continue\n            #if cell_class == 4:\n            predicted_string = predicted_string + \"%d %.4f %s \" % (cell_class, cell_class_confidence, cell_mask1_rle)\n    predictions_pd.append((uid, orig_width, orig_height, predicted_string.strip()))\npredictions_pd = pd.DataFrame(predictions_pd, columns=[ID, IMAGE_WIDTH, IMAGE_HEIGHT, PREDICTION_STRING])\npredictions_pd.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = submission_pd[[ID, IMAGE_WIDTH, IMAGE_HEIGHT]]\nsubmission = pd.merge(submission, predictions_pd[[ID, PREDICTION_STRING]], on=[ID], how=\"left\")\nsubmission[PREDICTION_STRING].fillna(\"\", inplace=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.tail()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}