commit 0fede818d770f28d9fe327f4798513288d25a2ee Author: Dmytro S Lituiev Date: Fri Oct 12 17:38:36 2018 -0700 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c341784 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +**/*.hdf5 +**/*.csv diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bcda3a --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Code for automatic labeling of special diagnostic mammography views from images and DICOM headers + +## DICOM +### Extract selected fields from DICOM headers + + dicom_header_extraction/extract_dicom_headers_w_generator_150K.py + +### Normalize / expand data + + dicom_header_extraction/normalize_selected_dcm_headers.py + +### Machine learning on DICOM headers + + caret_on_headers.R # most methods + caret_on_headers_nona.R # GLMNET + +## Image pipeline + +### General image model +- scripts and config files: `image_classifiers/e5ce2d69b035975cb5336cec0da9a32a` + +- weight files: + +### Wire localization model + +- scripts and config files: `image_classifiers/e8e71fc090141d7c6fb334359152d295` + +- weight files: + + +## Visualization of performance metrics +Scripts used to generate Fig. 1 + + combine_predictions_hdr_and_img.ipynb + visualize_predictions_hdr_and_img.ipynb + + +## Significance tests +Scripts used to generate Supplementary Figures S1 & S2 + + calc_auroc_confidence_intervals.R + plot_auroc_difference_pvalue.ipynb diff --git a/calc_auroc_confidence_intervals.R b/calc_auroc_confidence_intervals.R new file mode 100644 index 0000000..9bdf8fa --- /dev/null +++ b/calc_auroc_confidence_intervals.R @@ -0,0 +1,169 @@ +rm(list=ls()) +library(pROC) +library(ggplot2) +library(ggsignif) +library(dplyr) +library(data.table) +read.gz <- function(filename, ...){ + as.data.frame(fread(paste("zcat < ",filename), + header=TRUE, fill = TRUE, ...)) +} + + +tag <- "e5ce2d69b035975cb5336cec0da9a32a" +fnall <- "../tables/all_predictions_with_images.tab" +fnall <- paste0("../tables/all_predictions_with_images-", tag,".tab") + +predictions <- as.data.frame(fread(fnall, sep='\t'), header=TRUE, fill = TRUE) + +labelled <- sapply(predictions$label, function(x) nchar(x)>0) + +print(nrow(predictions[labelled,])) +predictions <- predictions[labelled,] + + +predictions[,'ViewModifier'] <- as.numeric(predictions[,'ViewModifier']!='') + +predictions[, "label"] <- factor(predictions[, "label"], c('normal', 'special')) + +predictions[,"view"] <- factor(predictions[,"view"], c('N','M','T','W','X')) +head(predictions) +# holdout <- predictions[predictions$set == 'val',] + +ggplot(holdout, aes(view, `score_max_wire_image+gbmt`)) + geom_point() + +validation <- predictions[predictions$set == 'test',] + +clmns <- colnames(predictions) + +othercols <- c('id', 'set', 'view', 'label') +modelnames <- c('ViewModifier', 'rpart', 'gbm', 'glmnet','xgb', 'gbmt', + 'image', + 'image_max', + 'wire', + 'wire_max', + 'max_image_wire_max', + 'image+gbmt', + 'max_wire_max_image+gbmt', + 'max_image_wire', + 'max_wire_image+gbmt') + + + +clean_score_names <- function(x){ + return( gsub('score_', '', x) ) + # paste(strsplit(x, '_')[[1]][-1],collapse='_') +} + +clmns_clean <- vapply(clmns, clean_score_names, '') + +cols_ <- factor(vapply(colnames(predictions) , clean_score_names, ''), + c(othercols,modelnames)) + +colnames(validation) <- cols_ + +validation <- validation[,!is.na(colnames(validation))] + +cols_ <- cols_[!is.na(cols_)] +cols_ <- cols_[order(cols_)] + +validation <- validation[,as.character(cols_)] + +colnames(validation) +# clmns <-clmns[vapply(clmns, function(x) strsplit(x, '_')[[1]][1]=='score', TRUE)] + +## Perform McNemars test for prediction difference ---------------------------------------------------- + +mcnemar.test(table(validation$`max_wire_max_image+gbmt`>0.5, validation$max_image_wire_max>0.5)) + +mcnemar.test(table(validation$`max_wire_max_image+gbmt`>0.5, validation$gbmt>0.5)) + +## Calculate significance of pairwise auROC differences ----------------------------------------------- +cis <- list() +rocobjects <- list() +ii <- 0 +for (clmn in modelnames){ + # ii = 1 + print('====================') + print(clmn) + rocobj <- plot.roc( validation[, "label"], + validation[,clmn], + levels = (levels(validation[, "label"])), + xlim = c(100,0), + ylim = c(0,100), + percent=TRUE, + print.auc=TRUE) + rocobjects[[clmn]] <- rocobj + cis[[clmn]] <- ci(rocobj, of="auc", thresholds="best") +} + +## Wire model on wire cases +for (clmn in c('wire', 'wire_max')){ + print('====================') + print(clmn) + rocobj <- plot.roc( validation[, "view"]=='W', + validation[,clmn], + # levels = (levels(validation[, "label"])), + xlim = c(100,0), + ylim = c(0,100), + percent=TRUE, + print.auc=TRUE) + rocobjects[[clmn]] <- rocobj + cis[[paste0(clmn, ' (vs other views)')]] <- ci(rocobj, of="auc", thresholds="best") +} +### +modelnames <- c('ViewModifier', 'rpart', 'gbm', 'glmnet','xgb', 'gbmt', + 'image', "image_max", + 'wire', 'wire_max', + 'wire (vs other views)', 'wire_max (vs other views)', + 'max_image_wire_max', + 'image+gbmt', + 'max_wire_max_image+gbmt') + +## + +dfcis <- as.data.frame(t(do.call(cbind.data.frame, lapply(cis, as.vector)))) +colnames(dfcis) <- c('lower', 'auROC', 'upper') + +dfcis[,"model"] <- factor(rownames(dfcis), + modelnames) + +dfcis <- dfcis[!is.na(dfcis[,"model"]),] + +rownames(dfcis) <- dfcis[,"model"] + +dfcis <- dfcis[modelnames,] + + +# dfcis <-dfcis %>% mutate(model = factor(model, levels=rev(levels(model)))) +dfcis_nowire <- dfcis[!(rownames(dfcis) %in% c('wire','wire_max')),] +dfcis_nowire$model <- factor(dfcis_nowire$model) +# +# +# annotation_df <- data.frame(color=c("E", "H"), +# start=c("Good", "Fair"), +# end=c("Very Good", "Good"), +# y=c(3.6, 4.7), +# label=c("Comp. 1", "Comp. 2")) + +roc.test(rocobjects[["ViewModifier"]], rocobjects[["gbmt"]]) + +## Format Pairwise comparisons + +keys <- names(rocobjects) +dfcompar <- data.frame() +for (a in 1:length(rocobjects)){ + for (b in 1:a){ + na <- keys[a] + nb <- keys[b] + if ((as.numeric(rocobjects[[na]]$auc)==100)||(as.numeric(rocobjects[[nb]]$auc)==100)){ + dfcompar[na, nb] <- NA + } else { + dfcompar[na, nb] <- roc.test(rocobjects[[na]], rocobjects[[nb]], method='delong')$p.value + } + } +} + + +fn.comparison <- paste0("../tables/auroc_delong_comparison-", tag,".csv") +write.csv(dfcompar, file=fn.comparison) diff --git a/caret_on_headers.R b/caret_on_headers.R new file mode 100644 index 0000000..2eb61ac --- /dev/null +++ b/caret_on_headers.R @@ -0,0 +1,284 @@ +# coding: utf-8 +rm(list=ls()) + +library(caret) +library(gbm3) +library(data.table) +library(ggplot2) +library(fastmatch) + +read.gz <- function(filename, ...){ + as.data.frame(fread(paste("zcat < ",filename), + header=TRUE, fill = TRUE, ...)) +} + +TABLEDIR = "../tables/" +fn_ids = paste(TABLEDIR, + "2017-06-mammo_tables/df_dcm_reports_birads_path_indic_dens_birad_wi_year_noreport_nodupl.csv.gz", sep='/') + +ids = read.gz(fn_ids, select="id")$id + +fn_features = paste(TABLEDIR, "mammo_dicom_headers/df_all_mammos_dicom_headers_selected_expanded.tab.gz", sep='/') +dffeatures = read.gz(fn_features, sep='\t') +print(nrow(dffeatures)) +print(length(ids)) + +dffeatures <- dffeatures[fmatch(unique(ids), dffeatures$filename),] +dffeatures <- dffeatures[!is.na(dffeatures$filename),] +rm(ids) + +# Data formatting ----------------------------------------- + +collist = c("BodyPartThickness", "XRayTubeCurrentInuA", "ContentTime", + "DetectorTemperature", "WindowCenter", "FieldOfViewRotation") +for (cc in collist){ + dffeatures[,cc] <- as.numeric(dffeatures[,cc]) +} + + +dtypes = sapply(dffeatures, class) +names(dtypes[dtypes == 'character']) + + +row.names(dffeatures) = dffeatures$filename +excludeCols <- c("filename", + "CollimatorLeftVerticalEdge", + "CollimatorLowerHorizontalEdge", + "DistanceSourceToEntrance", + "ExposuresOnDetectorSinceLastCalibration", + "ExposuresOnDetectorSinceManufactured", + "ShutterLowerHorizontalEdge", + "ShutterRightVerticalEdge", + "XRayTubeCurrentInuA" + # "ManufacturerModelName" + ) +dffeatures <- (dffeatures[, !(colnames(dffeatures) %in% excludeCols)]) + + +catcols <- c('ViewModifierCodeMeaning', + 'ViewCodeValue', + 'DetectorActiveDimensionsMissing', + 'FieldOfViewOriginMissing', + 'Grid', + 'Manufacturer', + 'ManufacturerModelName') + +for (cc in catcols){ + dffeatures[,cc] = as.factor(dffeatures[,cc]) +} +#cell# + +colSums(sapply(dffeatures, is.na)) + +# Read labels -------------------------------- + + +fn.labelledset = paste(TABLEDIR, "spotmag_predictions/train_test_split-2018-02-15-within7e5.csv", sep='/') +# filelist.labelled = read.table(fn.labelledset, ) +df.labelled = as.data.frame(fread(fn.labelledset)) +rownames(df.labelled) <- df.labelled$id +vec.labelled = df.labelled$id +df.labelled$label <- as.factor(df.labelled$label) + +#cell# + +vec.labelled.valset = rownames(df.labelled[df.labelled$set == 'val',]) +vec.labelled.tr_set = rownames(df.labelled[df.labelled$set == 'train',]) +vec.labelled.ts_set = rownames(df.labelled[df.labelled$set == 'test',]) + +############################################################ + +dffeatures.labelled <- dffeatures[vec.labelled,] +dffeatures.labelled$label <- df.labelled$label + +#cell# + +dffeatures.labelled.devset <- dffeatures.labelled[!(rownames(dffeatures.labelled) %in% vec.labelled.valset),] +dffeatures.labelled.tr_set <- dffeatures.labelled[vec.labelled.tr_set,] +dffeatures.labelled.ts_set <- dffeatures.labelled[vec.labelled.ts_set,] + +colnames(dffeatures.labelled.tr_set) + + +for (cc in colnames(dffeatures.labelled.tr_set)){ + if (is.factor(dffeatures.labelled.tr_set[,cc]) ){ + setdiff_ = setdiff(dffeatures.labelled.ts_set[,cc], dffeatures.labelled.tr_set[,cc]) + if (length(setdiff_)>0){ + print(cc) + print(setdiff_) + } + } +} + + + + +# GBM3 ---------------------------------------- + +par_detail <- gbmParallel(num_threads = 4) # Pass to par_details in gbmt +gbmt_fit <- gbmt(label ~ ., + data = dffeatures.labelled.tr_set, + cv_folds = 10, + # training_params = training_params(num_trees = 100, + # interaction_depth = 1, + # min_num_obs_in_node = 10, + # shrinkage = 0.005, + # bag_fraction = 0.5, + # num_features = 2), + keep_gbm_data = TRUE, + par_detail=par_detail) + +best_iter_cv <- gbmt_performance(gbmt_fit, method='cv') +plot(best_iter_cv) + +best.iter.oob <- gbmt_performance(gbmt_fit,method="OOB") # returns out-of-bag estimated best number of trees +plot(best.iter.oob) + +saveRDS(gbmt_fit, sprintf("gbm3_ntrees_%d_%s.rds", best_iter_cv, Sys.Date())) + +## Feature Importance Plotting ---------------- + +infl_gbmt <- (as.data.frame(relative_influence(gbmt_fit, best_iter_cv, rescale=T))) +colnames(infl_gbmt) <- "relative influence" +infl_gbmt[,"variable"] <- rownames(infl_gbmt) + +infl_gbmt = infl_gbmt[infl_gbmt$`relative influence` >0,] + +plimp <- ggplot(data=infl_gbmt) + + geom_segment(size=5, colour='blue') + + aes(x=reorder(variable,`relative influence`), + xend = variable, + y = 2e-6, + yend=`relative influence`, + label=`relative influence`) + + scale_y_log10() + + # coord_cartesian(ylim= c(0.8e-6, 1.05)) + + ylab("relative influence") + xlab("") + + coord_flip() + + theme(axis.text.y = element_text(colour="black",size=16,angle=0,face="plain"), + axis.text.x = element_text(colour="black",size=16,angle=0,face="plain"), + axis.title.x = element_text(colour="black",size=16,angle=0,face="plain"), + # panel.background = element_rect(fill = "transparent"), # bg of the panel + #plot.background = element_rect(fill = "transparent"), # bg of the plot + # panel.grid.major = element_blank(), # get rid of major grid + # , panel.grid.minor = element_blank() # get rid of minor grid + , legend.background = element_rect(fill = "transparent") # get rid of legend bg + , legend.box.background = element_rect(fill = "transparent") # get rid of legend panel bg + ) + +plimp + coord_trans(limy= c(0.5e-6, 1.05)) + coord_flip() + +plimp + ggsave("img/xgbt_importances.eps", device = 'eps', bg = "transparent", + width = 8, height = 6, dpi = 300, units = "in" ) +plimp + ggsave("img/xgbt_importances.png", device = 'png', bg = "transparent", + width = 8, height = 6, dpi = 300, units = "in" ) + + +dffeatures[,"predictions_gbmt"] = predict(gbmt_fit, newdata = dffeatures, + n.trees = best_iter_cv, + type = "response", na.action = na.pass) + +# GBM-CARET --------------------------------------------------- + +control <- trainControl(method = "cv", + number = 10, + p =.8, + savePredictions = TRUE, + classProbs = TRUE, + summaryFunction = twoClassSummary) + +tuneGrid <- expand.grid(n.trees = c(80,100,120,140,160), + shrinkage=c(0.025, 0.05, 0.1, 0.2), + interaction.depth = c(1,2), + n.minobsinnode = c(10, 15)) + +gbmFit1 <- train(label ~ ., + data = dffeatures.labelled.tr_set, + method = "gbm", + na.action = na.pass, + tuneGrid=tuneGrid, + ## This last option is actually one + ## for gbm() that passes through + metric = "ROC", + trControl = control, + # importance = TRUE, + verbose = FALSE) +gbmFit1 + +## Feature Importance Plotting --------------------------------------------- + +gbmsmmry <- summary(gbmFit1, normalize=T, plotit=F) + +gbmsmmry <- gbmsmmry[gbmsmmry$rel.inf>0,] + + +ggplot(data=gbmsmmry) + + geom_segment(size=3, colour='red') + + aes(x=reorder(var,rel.inf, sum), + xend = var, + y = 0.002, + yend=(rel.inf), + label=rel.inf) + + scale_y_log10() + + ylab("relative influence") + xlab("") + + coord_flip() + +saveRDS(gbmFit1, "gbm_ntrees80_interactiondepth2_shrinkage0.2_nminobsinnode15_trainset_2018-02-18.rds") + +dffeatures[,"predictions_gbm"] = predict(gbmFit1, newdata = dffeatures, type = "prob", na.action = na.pass)$special + +# RPART ----------------------------------------------------------------- + +tuneGrid <- expand.grid(cp=c(0.0, 0.0125, 0.025, 0.05, 0.1, 0.2)) + +rpartFit1 <- train(label ~ ., data = dffeatures.labelled.tr_set, + method = "rpart", + na.action = na.pass, + tuneGrid=tuneGrid, + ## This last option is actually one + ## for gbm() that passes through + metric = "ROC", + trControl = control +) +varImp(rpartFit1) + + +predictions.ts_set = predict(rpartFit1, + newdata = dffeatures.labelled.ts_set, + type='prob', na.action = na.pass) + +dffeatures[,"predictions_rpart"] = predict(rpartFit1, newdata = dffeatures, type = "prob", na.action = na.pass)$special + +# XGB --------------------------------------------------------------------- +control <- trainControl(method="cv", number=10) +#classProbs = TRUE + +#tuneGrid <- expand.grid(cp=c(0.0, 0.0125, 0.025, 0.05, 0.1, 0.2)) +xgbFit <- train(label ~ ., data = dffeatures.labelled.tr_set, + method = "xgbTree", + na.action = na.pass, + #tuneGrid=tuneGrid, + metric = "Accuracy", + trControl = control) + +varImp(xgbFit, scale=T) + +as.data.frame(xgbFit$finalModel$params) + +xgbFit$bestTune + +saveRDS(xgbFit, sprintf("xgbtree_maxdepth1_subsample1_eta0.3_%s.rds", Sys.Date())) + +predictions.ts_set = predict(xgbFit, + newdata = dffeatures.labelled.ts_set, + type='prob', na.action = na.pass) + + +## Save all predictions --------------------------------------------------------- + +dffeatures[,"predictions_xgb"] = predict(xgbFit, newdata = dffeatures, type = "prob", na.action = na.pass)$special + +write.table(dffeatures[, c(grep('prediction',colnames(dffeatures), value=T), + "ViewModifierCodeMeaning", "ViewCodeValue")], + file = "all_predictions_allmodels_trained_on_train.tab", quote=F, sep='\t') + diff --git a/caret_on_headers_nona.R b/caret_on_headers_nona.R new file mode 100644 index 0000000..edcab2a --- /dev/null +++ b/caret_on_headers_nona.R @@ -0,0 +1,170 @@ +# coding: utf-8 +############################################################################ +# stratify by BT column: those are 100% sure digital, others can be either +############################################################################ +rm(list=ls()) +setwd(dir = "~/repos/mammo/learn_spotmag_from_dicom_headers") +#cell# +library(caret) +library(data.table) + +library(pROC) +# install.packages(c("pROC")) +library(ggplot2) +library(fastmatch) + +read.gz <- function(filename, ...){ + as.data.frame(fread(paste("zcat < ",filename), + header=TRUE, fill = TRUE, ...)) +} + + +fn_ids = "../tables/2017-06-mammo_tables/df_dcm_reports_birads_path_indic_dens_birad_wi_year_noreport_nodupl.csv.gz" +ids = read.gz(fn_ids, select="id")$id + +fn_features = "../tables/mammo_dicom_headers/df_all_mammos_dicom_headers_selected_nona.tab.gz" +dffeatures = read.gz(fn_features, sep='\t') + +# rownames(dffeatures) <- dffeatures$filename +print(nrow(dffeatures)) +print(length(ids)) + +dffeatures <- dffeatures[fmatch(unique(ids), dffeatures$filename),] +dffeatures <- dffeatures[!is.na(dffeatures$filename),] + +rm(ids) + +collist = c("BodyPartThickness", "XRayTubeCurrentInuA", "ContentTime", + "DetectorTemperature", "WindowCenter", "FieldOfViewRotation") +for (cc in collist){ + dffeatures[,cc] <- as.numeric(dffeatures[,cc]) +} + + + +# (head(as.numeric(dffeatures$BodyPartThickness))) +dtypes = sapply(dffeatures, class) + +row.names(dffeatures) = dffeatures$filename +excludeCols <- c("filename", + "CollimatorLeftVerticalEdge", + "CollimatorLowerHorizontalEdge", + "DistanceSourceToEntrance", + "ExposuresOnDetectorSinceLastCalibration", + "ExposuresOnDetectorSinceManufactured", + "ShutterLowerHorizontalEdge", + "ShutterRightVerticalEdge", + "XRayTubeCurrentInuA" + # "ManufacturerModelName" +) +dffeatures <- (dffeatures[, !(colnames(dffeatures) %in% excludeCols)]) + + +catcols <- c('ViewModifierCodeMeaning', + 'ViewCodeValue', + 'DetectorActiveDimensionsMissing', + 'FieldOfViewOriginMissing', + 'Grid', + 'Manufacturer', + 'ManufacturerModelName') + +for (cc in catcols){ + dffeatures[,cc] = paste0("=", dffeatures[,cc]) + dffeatures[,cc] = as.factor(dffeatures[,cc]) +} + +dffeatures[,"HighBit"] <- as.numeric(dffeatures[,"HighBit"]) + +colSums(sapply(dffeatures, is.na)) + +# Read labels --------------------------------- + +fn.labelledset = "../tables/spotmag_predictions/train_test_split-2018-02-15-within7e5.csv" +# filelist.labelled = read.table(fn.labelledset, ) +df.labelled = as.data.frame(fread(fn.labelledset)) +rownames(df.labelled) <- df.labelled$id +vec.labelled = df.labelled$id +df.labelled$label <- as.factor(df.labelled$label) + +#cell# + +vec.labelled.valset = rownames(df.labelled[df.labelled$set == 'val',]) +vec.labelled.tr_set = rownames(df.labelled[df.labelled$set == 'train',]) +vec.labelled.ts_set = rownames(df.labelled[df.labelled$set == 'test',]) +############################################################ +dffeatures.labelled <- dffeatures[vec.labelled,] +dffeatures.labelled$label <- df.labelled$label + +dffeatures.labelled.devset <- dffeatures.labelled[!(rownames(dffeatures.labelled) %in% vec.labelled.valset),] +dffeatures.labelled.tr_set <- dffeatures.labelled[vec.labelled.tr_set,] +dffeatures.labelled.ts_set <- dffeatures.labelled[vec.labelled.ts_set,] + +table(dffeatures.labelled.tr_set$label) + + +goodrows <- 1 - colSums(sapply(dffeatures.labelled.tr_set, is.na)) / nrow(dffeatures.labelled.tr_set) + +names(goodrows[goodrows<0.1]) + + +for (cc in colnames(dffeatures.labelled.tr_set)){ + if (is.factor(dffeatures.labelled.tr_set[,cc]) ){ + setdiff_ = setdiff(dffeatures.labelled.ts_set[,cc], dffeatures.labelled.tr_set[,cc]) + if (length(setdiff_)>0){ + print(cc) + print(setdiff_) + } + } +} + + +# GLMNET --------------------------------------------------------------------- + +library(glmnet) +# Using glmnet to directly perform CV +set.seed(0) + +x_train <- model.matrix( ~ .-1, dffeatures.labelled.tr_set[,!(colnames(dffeatures.labelled.tr_set) %in% c("label"))]) +dim(x_train) + +cvob1=cv.glmnet(x=x_train, + y=dffeatures.labelled.tr_set[,"label"], + family="binomial",alpha=1, + type.measure="auc", nfolds = 5, lambda = seq(0.001,0.1,by = 0.001), + standardize=FALSE) +plot(cvob1) + +control <- trainControl(method="cv", number=5, returnResamp="all", + classProbs=TRUE, summaryFunction=twoClassSummary) +#classProbs = TRUE + +tuneGrid <- expand.grid(alpha=c(0.00, 0.25, 0.50, 0.75, 0.99, 1.00), lambda = 10^seq(-5,-2,0.5)) +tune = list() +fits = list() +rocs = list() +for (ii in 1:5){ + glmnetFit <- train(label ~ ., data = dffeatures.labelled.tr_set, + method = "glmnet", + na.action = na.pass, + tuneGrid=tuneGrid, + metric = "ROC", + trControl = control) + fits[[ii]] <- glmnetFit + tune[[ii]] <- glmnetFit$bestTune + rocs[[ii]] <- max(glmnetFit$results$ROC) +} + +tune + +varImp(glmnetFit, scale=T) +as.data.frame(glmnetFit$bestTune) + +saveRDS(glmnetFit, sprintf("glmnet.rds", Sys.Date())) + +## Save predictions --------------------------------------------------------- + +dffeatures[,"predictions_glmnet"] = predict(glmnetFit, newdata = dffeatures, type = "prob", na.action = na.pass)$special + +write.table(dffeatures[,c("predictions_glmnet"), drop=F], + file="all_predictions_glmnet.tab", quote=F, sep='\t') + diff --git a/combine_predictions_hdr_and_img.ipynb b/combine_predictions_hdr_and_img.ipynb new file mode 100644 index 0000000..c10769f --- /dev/null +++ b/combine_predictions_hdr_and_img.ipynb @@ -0,0 +1,763 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n", + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read labels" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "tabledir = \"../tables/\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(772423, 1)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fn = f\"{tabledir}/2017-06-mammo_tables/df_dcm_reports_birads_path_indic_dens_birad_wi_year_noreport_nodupl.csv.gz\"\n", + "df_bt = pd.read_csv(fn, usecols=[\"id\", \"BT_case\"])\n", + "df_bt.set_index(\"id\", inplace=True)\n", + "df_bt = ~df_bt.isnull()\n", + "df_bt.columns = [\"digital\"]\n", + "df_bt.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
setlabelview
id
1013372709_1.2.840.113654.2.70.1.175625299786291545159233542096043464711_3_1testnormalN
1028995243_1.2.840.113654.2.70.1.56947963181878834591544466761404805157_45576_2testnormalN
1105112884_1.2.840.113654.2.70.1.178729598744204462442695104630823323474_8905_2testnormalN
1185125156_1.2.840.113654.2.70.1.45840593750642722243371816041014016032_2_4testnormalN
1496452586_1.2.840.113654.2.70.1.5582568668770891599992528318631583880_1351_4testnormalN
\n", + "
" + ], + "text/plain": [ + " set label view\n", + "id \n", + "1013372709_1.2.840.113654.2.70.1.17562529978629... test normal N\n", + "1028995243_1.2.840.113654.2.70.1.56947963181878... test normal N\n", + "1105112884_1.2.840.113654.2.70.1.17872959874420... test normal N\n", + "1185125156_1.2.840.113654.2.70.1.45840593750642... test normal N\n", + "1496452586_1.2.840.113654.2.70.1.55825686687708... test normal N" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "infile = f\"{tabledir}/spotmag_predictions/train_test_split-2018-02-16-within7e5-label.csv\"\n", + "dflab = pd.read_csv(infile, index_col='id')\n", + "dflab[:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read header-based predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(772367, 1)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "infile = f\"{tabledir}/spotmag_predictions/all_predictions_glmnet.tab\"\n", + "dfpred_glmnet = pd.read_table(infile, index_col=0)\n", + "dfpred_glmnet.columns = [cc.replace(\"predictions\", \"score\") for cc in dfpred_glmnet.columns]\n", + "dfpred_glmnet.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(772367, 5)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
score_gbmscore_xgbscore_rpartscore_xgbtViewModifierCodeMeaning
id
2454166001_1.2.840.113654.2.70.1.269947926355209368181920716215505958953_149405_21045560.0090050.0202070.0068820.059474NaN
2454166001_1.2.840.113654.2.70.1.269947926355209368181920716215505958953_149405_21045570.0133370.0167620.0068820.059660NaN
2454166001_1.2.840.113654.2.70.1.269947926355209368181920716215505958953_149484_21415380.0133370.0167620.0068820.061051NaN
2454166001_1.2.840.113654.2.70.1.269947926355209368181920716215505958953_149484_21415370.0133370.0167620.0068820.061051NaN
3337971863_1.2.840.113654.2.70.1.337982194343327746313656933304494759333_1_10.0315600.0591420.0068820.157488NaN
\n", + "
" + ], + "text/plain": [ + " score_gbm score_xgb \\\n", + "id \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.009005 0.020207 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.013337 0.016762 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.013337 0.016762 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.013337 0.016762 \n", + "3337971863_1.2.840.113654.2.70.1.33798219434332... 0.031560 0.059142 \n", + "\n", + " score_rpart score_xgbt \\\n", + "id \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.006882 0.059474 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.006882 0.059660 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.006882 0.061051 \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... 0.006882 0.061051 \n", + "3337971863_1.2.840.113654.2.70.1.33798219434332... 0.006882 0.157488 \n", + "\n", + " ViewModifierCodeMeaning \n", + "id \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... NaN \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... NaN \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... NaN \n", + "2454166001_1.2.840.113654.2.70.1.26994792635520... NaN \n", + "3337971863_1.2.840.113654.2.70.1.33798219434332... NaN " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "infile = f\"{tabledir}/spotmag_predictions/all_predictions_allmodels_trained_on_train.tab\"\n", + "dfpred = pd.read_table(infile, index_col=0)\n", + "dfpred.columns = [cc.replace(\"predictions\", \"score\") for cc in dfpred.columns]\n", + "dfpred.index.name = 'id'\n", + "print(dfpred.shape)\n", + "dfpred[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(772367, 8)\n" + ] + } + ], + "source": [ + "if 'set' not in dfpred.columns:\n", + " dfpred = dfpred.merge(dflab, left_index=True, right_index=True, how='left')\n", + " print(dfpred.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "normal 3526\n", + "magn/spot 572\n", + "wire loc 57\n", + "stereotactic 25\n", + "other 9\n", + "Name: view, dtype: int64" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "colmap = {\"N\":\"normal\", \"M\": \"magn/spot\",\n", + " \"T\":\"stereotactic\", \"W\":\"wire loc\", \"X\":\"other\"}\n", + "view_counts = dfpred[~dfpred.view.isnull()].view.map(lambda x: colmap[x]).value_counts()\n", + "view_counts" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
settraintestval
view
magn/spot3809696
normal2310612604
other432
stereotactic1744
wire loc37119
\n", + "
" + ], + "text/plain": [ + "set train test val\n", + "view \n", + "magn/spot 380 96 96\n", + "normal 2310 612 604\n", + "other 4 3 2\n", + "stereotactic 17 4 4\n", + "wire loc 37 11 9" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpred[~dfpred.view.isnull()].view.map(lambda x: colmap[x]), dfpred.set)[[\"train\", \"test\", \"val\"]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read image-based predictions (general)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "../tables//spotmag_predictions/predictions_images_4189-epoch55-e5ce2d69b035975cb5336cec0da9a32a.csv\n" + ] + }, + { + "data": { + "text/plain": [ + "Index(['score_image', 'score_image_max'], dtype='object')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tag = \"e5ce2d69b035975cb5336cec0da9a32a\"\n", + "epoch = 55\n", + "infile = f\"{tabledir}/spotmag_predictions/predictions_images_4189-epoch{epoch}-{tag}.csv\"\n", + "# infile = f\"{tabledir}/spotmag_predictions/df_dcm_reports_birads_path_indic_dens_birad_wi_year_noreport_nodupl-spotmag_img_prediction-{tag}.csv\"\n", + "print(infile)\n", + "dfpred_img = pd.read_csv(infile, index_col=0)\n", + "dfpred_img = dfpred_img[['score_image', 'score_image_max']]\n", + "dfpred_img = dfpred_img.groupby(level=0).mean()\n", + "dfpred_img.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read image-based predictions (wire localization)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "infile = f\"{tabledir}/spotmag_predictions/predictions_wire_combined_e8e71fc090141d7c6fb334359152d295.csv\"\n", + "\n", + "dfpred_imgwire = pd.read_csv(infile, index_col=0)\n", + "dfpred_imgwire[\"score_wire_max\"] = 1-dfpred_imgwire[[\"scores_0_or\",\"scores_0_fl\"]].min(1)\n", + "dfpred_imgwire = dfpred_imgwire.drop([\"scores_0_or\",\"scores_0_fl\", \"label\"], axis=1)\n", + "dfpred_imgwire.columns = [cc.replace(\"scores\", \"score_wire\") for cc in dfpred_imgwire.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(772367, 13)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "if 'score_image' not in dfpred.columns:\n", + " dfpred = pd.concat([dfpred, dfpred_img], axis=1)\n", + " dfpred.index.name = 'id'\n", + " del dfpred_img\n", + " \n", + "if 'score_glmnet' not in dfpred.columns:\n", + " dfpred = pd.concat([dfpred, dfpred_glmnet], axis=1)\n", + " dfpred.index.name = 'id'\n", + " del dfpred_glmnet\n", + " \n", + "if 'score_wire' not in dfpred.columns:\n", + " dfpred = pd.concat([dfpred, dfpred_imgwire], axis=1)\n", + " dfpred.index.name = 'id'\n", + " del dfpred_imgwire\n", + "\n", + "dfpred.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "if 'label' not in dfpred.columns:\n", + " dfpred = pd.concat([dfpred, dflab], axis=1)\n", + "if 'digital' not in dfpred.columns:\n", + " dfpred = pd.concat([dfpred, df_bt], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
score_imageFalseTrue
score_wire
False35840
True605768234
\n", + "
" + ], + "text/plain": [ + "score_image False True \n", + "score_wire \n", + "False 3584 0\n", + "True 605 768234" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpred[\"score_wire\"].isnull(), dfpred[\"score_image\"].isnull())" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "dfpred.rename(columns={\"score_xgbt\":\"score_gbmt\"}, inplace=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add ensembled (max, avg) scores" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "dfpred['score_wire'] = dfpred['score_wire'].fillna(0)\n", + "dfpred['score_wire_max'] = dfpred['score_wire_max'].fillna(0)\n", + "dfpred['score_image+glmnet'] = (dfpred['score_image'] + dfpred['score_glmnet'])/2\n", + "dfpred['score_image+gbmt'] = (dfpred['score_image'] + dfpred['score_gbmt'])/2\n", + "\n", + "dfpred['score_max(image;gbmt)'] = dfpred[['score_image','score_gbmt']].max(1)\n", + "\n", + "dfpred['score_image*glmnet'] = np.sqrt(dfpred['score_image'] * dfpred['score_glmnet'])\n", + "dfpred['score_image*gbmt'] = np.sqrt(dfpred['score_image'] * dfpred['score_gbmt'])\n", + "dfpred['score_max_image_wire'] = np.nanmax(dfpred[['score_image','score_wire']].values, axis=1)\n", + "dfpred['score_max_image_wire_max'] = np.nanmax(dfpred[['score_image','score_wire_max']].values, axis=1)\n", + "# dfpred['score_wire'].isnull()\n", + "dfpred['score_max_image_wire+gbmt'] =(dfpred['score_max_image_wire'] + dfpred['score_gbmt'])/2\n", + "\n", + "dfpred['score_max_image_wire_max+gbmt'] =(dfpred['score_max_image_wire_max'] + dfpred['score_gbmt'])/2\n", + "\n", + "dfpred['score_max(image;wire_max;gbmt)'] = dfpred[['score_wire_max','score_gbmt', 'score_image']].max(1)\n", + "\n", + "dfpred['score_max_wire_image+gbmt'] = np.nanmax(dfpred[['score_image+gbmt','score_wire']].values, axis=1)\n", + "\n", + "dfpred['score_max_wire_max_image+gbmt'] = np.nanmax(dfpred[['score_image+gbmt','score_wire_max']].values, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "dfpred.rename(columns={\"ViewModifierCodeMeaning\":\"ViewModifier\"}, inplace=True)\n", + "dfpred.index.name = 'id'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Save the combined table" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "772423" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(dfpred)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "dfpred.to_csv(f'{tabledir}/all_predictions_with_images-{tag}.tab', sep='\\t')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [default]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/dicom_header_extraction/extract_dicom_headers_w_generator_150K.py b/dicom_header_extraction/extract_dicom_headers_w_generator_150K.py new file mode 100644 index 0000000..f166c3c --- /dev/null +++ b/dicom_header_extraction/extract_dicom_headers_w_generator_150K.py @@ -0,0 +1,98 @@ +# coding: utf-8 +import numpy as np +import pandas as pd +import dicom +from warnings import warn + +def get_tuples(plan, outlist = None, key = ""): + if len(key)>0: + key = key + "_" + if not outlist: + outlist = [] + for aa in plan.dir(): + if (hasattr(plan, aa) and aa!='PixelData'): + value = getattr(plan, aa) + if type(value) is dicom.sequence.Sequence: +# if len(list(value))==1: +# outlist.extend(get_tuples(list(value)[0], outlist = None, key = key+aa)) +# else: + for nn, ss in enumerate(list(value)): + newkey = "_".join([key,("%d"%nn),aa]) if len(key) else "_".join([("%d"%nn),aa]) + outlist.extend(get_tuples(ss, outlist = None, key = newkey)) + else: + if type(value) is dicom.valuerep.DSfloat: + value = float(value) + elif type(value) is dicom.valuerep.IS: + value = str(value) + elif type(value) is dicom.valuerep.MultiValue: + value = tuple(value) + elif type(value) is dicom.UID.UID: + value = str(value) + outlist.append((key + aa, value)) + return outlist + + +def filter_row_common_field(row, common_fields): + for kk in list(row.keys()): + if kk not in common_fields: + row.pop(kk) + return row + + + +""" +fn_allheaders = '/home/dlituiev/data_dlituiev/manuallabeller/filelist/dicom_headers_all_fields_filelist_nonscreening_4000_seed42.csv' + +df_allheaders = pd.read_csv(fn_allheaders, index_col=0) + + +"at least 5% of rows are there" +thr = 0.05 +valid_fields = (~df_allheaders.isnull()).mean() > thr +valid_fields = valid_fields[valid_fields].index.tolist() +print(len(valid_fields)) +""" + +valid_fields = pd.read_table("/data/dlituiev/learn_spotmag_from_dicom_headers/LogisticRegression_common_fields_names.tab", + header=None, + squeeze=True).values + + +#filelist_fn = '/home/dlituiev/data_dlituiev/tables/df_newest_mammos.pickle' +filelist_fn = "/home/dlituiev/data_dlituiev/tables/2017-06-mammo_tables/df_original_mammos.pickle" +filelist = pd.read_pickle(filelist_fn, )["Filename"].unique().tolist() +len(filelist) + +BUFFER_N_LINES = 100 +SEP = '\t' +outpath = filelist_fn.replace('.pickle','') + '_dicom_headers_selected.tab' +final_columns = ['filename'] + list(valid_fields) +print("len(final_columns)", len(final_columns) ) +print('saving to %s' % outpath) +with open(outpath, 'w+') as outfh: + outfh.write(SEP.join(final_columns) + '\n') + headerlist = [] + for nn, ff in enumerate(filelist): + if nn% BUFFER_N_LINES == (BUFFER_N_LINES-1): + df_hl = pd.DataFrame( headerlist, columns=final_columns) + df_hl.to_csv(outfh, sep=SEP, header=None, index=None, mode = 'a') + outfh.flush() + del df_hl + print(nn+1) + headerlist = [] + try: + plan = dicom.read_file(ff) + row = get_tuples(plan) + row = dict(row) + row = tuple([ff] + [(row[kk] if (kk in row) else np.nan) for kk in valid_fields ]) + print("len(row)", len(row)) + headerlist.append(row) + except Exception as ex: +# raise ex + warn('header extraction failed on #\t%s\t%s\t%s' % (nn, ff, ex)) + # in the end, print the rest: + df_hl = pd.DataFrame( headerlist, columns=final_columns) + df_hl.to_csv(outfh, sep=SEP, header=None, index=None, mode = 'a') + outfh.flush() + +print("DONE") diff --git a/dicom_header_extraction/header_cleaner.py b/dicom_header_extraction/header_cleaner.py new file mode 100644 index 0000000..45b211d --- /dev/null +++ b/dicom_header_extraction/header_cleaner.py @@ -0,0 +1,798 @@ + +# coding: utf-8 + +import numpy as np +import pandas as pd +import os +from functools import partial +from itertools import chain + +def entropy(x): + f = x.value_counts() +# f.loc["nan"] = x.isnull().sum() + return (f*f.map(np.log2)).sum() + + +def select_text_fields(df_allheaders): + text_fields = df_allheaders.dtypes.map(lambda x: x is pd.np.dtype(object)) + text_fields = text_fields[text_fields].index.tolist() + len(text_fields) + text_fields = (~df_allheaders[text_fields].isnull()).mean() > 0.05 + + text_fields = text_fields[text_fields].index.tolist() + remove_list = [] + for tt in text_fields: + numunique = len(df_allheaders[tt].unique()) + entr = entropy(df_allheaders[tt]) + if entr<1000 | (numunique == 1) | (numunique > 0.75*df_allheaders.shape[1]): + remove_list.append(tt) + + for tt in remove_list: + text_fields.remove(tt) + + len(text_fields) + return text_fields + + +def get_good_numeric_fields(df_allheaders, thr_stderr = 1e-6): + stderr = df_allheaders.std()/df_allheaders.mean() + field_list = stderr[stderr> thr_stderr].index.tolist() + return field_list + + +def get_index_from_int_tuple(x, ind): + if type(x) is str: + x = eval(x) + return int(float(x[ind])) + else: + return x + + +def clean_up_field_list(field_list, + prefices_remove = ["date", "accession", "number", + "Filename", + "ImageLaterality", + "GantryID", + #"0_ViewCodeSequence_CodeMeaning", + "ViewCodeSequence_CodeMeaning", + "ViewModifierCodeSequence_CodeValue", + "EthnicGroup", + "BodyPartExamined", + "LossyImageCompression", + "DeidentificationMethodCodeSequence", + "UID", + 'EntranceDoseInmGy', + 'ProcedureCodeSequence_CodeMeaning', + 'CommentsOnRadiationDose', + 'DetectorID', + 'SeriesDescription', # potentially informative but too many values + 'SoftwareVersions', + 'PatientAge', + ], + fields_remove = [ 'PatientID', 'PatientName', "BitsStored", + 'AcquisitionTime', + 'AdmittingTime', + 'ScheduledStudyStartTime', + 'InstanceCreationTime', + 'PerformedProcedureStepStartTime', + 'PregnancyStatus', + 'StudyArrivalTime', + 'StudyCompletionTime', + 'StudyTime', + 'TimeOfLastCalibration', + 'TimeOfLastDetectorCalibration', + 'TimeOfSecondaryCapture',]): + + prefices_remove = [x.lower() for x in prefices_remove] + + for ff in field_list: + for pp in prefices_remove: + if pp in ff.lower(): + if ff not in fields_remove: + fields_remove.append(ff) + + for ff in fields_remove: + try: + field_list.remove(ff) + except ValueError as ve: + print(ff, ve) + return field_list + + +def make_lowercase_text_fields(df_allheaders): + """## make all text fields lowercase + (except accession and file name)""" + for cname in df_allheaders.columns[1:]: + cc = df_allheaders[cname] + if cc.dtype is np.dtype(object): + df_allheaders[cname] = cc.str.lower() + return df_allheaders + + +def format_PixelSpacing(x): + if type(x) is float: + return x + else: + xstr = x.lstrip("(").rstrip(")").replace("'", "").replace(" ","").split(",") + return np.unique(tuple([float(y) for y in xstr]))[0] + +def parse_float(x): + x = str(x).replace("'","").replace("b","").replace("None","nan") + if x == "": + x = np.nan + return x + +def parse_float_tuples(x, to_int=False): + x = list(str(x)) + for nn,ss in enumerate(x): + if not ss.isdigit() and ss!='.': + x[nn] = ';' + x = "".join(x).split(';') + if to_int: + x = tuple([int(float(dd)) for dd in x if len(dd)]) + else: + x = tuple([float(dd) for dd in x if len(dd)]) + if type(x) is not tuple: + raise TypeError("returned non-list: {}".format(str(x))) + return x + +def parse_float_tuples_prod(x): + if x not in (None, np.nan) and len(x)>0: + x = str(x) + assert type(x) is str + x = parse_float_tuples(x) + if type(x) is not tuple: + raise TypeError("returned non-list: {} of type {}".format(str(x), type(x))) + try: + x = np.prod(x) + except TypeError as ee: + print('"%s"' % x) + raise ee + else: + x = np.nan + return x + +def parse_int_tuples_median(x): + x = parse_float_tuples(x) + x = np.median(x) + return x +""" +def parse_float_tuples(x): + x = eval(x) if type(x) is str else x + if type(x) in [tuple, list]: + x = tuple([float(y) for y in x]) + return x +""" + +def parse_str_tuples(x): + try: + x = eval(x) if type(x) is str else x + except: + x = tuple(x.split(" ")) if type(x) is str else x + return x +#############################33 +def extract_list_text_field(df_allheaders, colprefix = "ViewModifierCodeSequence_CodeMeaning"): + allcols = df_allheaders.columns + cols = allcols[np.asarray(allcols.map(lambda x: colprefix in x and x!=colprefix), dtype=bool)] + + ViewModifierCodeSequence_CodeMeaning = set() + for cc in cols: + ViewModifierCodeSequence_CodeMeaning |= set(df_allheaders[cc].dropna().unique()) + + for vv in (True, False): + if (vv in ViewModifierCodeSequence_CodeMeaning): + ViewModifierCodeSequence_CodeMeaning.remove(vv) + + ViewModifierCodeSequence_CodeMeaning = dict(zip( + ViewModifierCodeSequence_CodeMeaning, + [None]*len(ViewModifierCodeSequence_CodeMeaning))) + + for kk in ViewModifierCodeSequence_CodeMeaning.keys(): + ViewModifierCodeSequence_CodeMeaning[kk] = df_allheaders[cols[0]].copy() + ViewModifierCodeSequence_CodeMeaning[kk][:] = False + ViewModifierCodeSequence_CodeMeaning[kk] = \ + ViewModifierCodeSequence_CodeMeaning[kk].astype(bool) + for cc in cols: + ViewModifierCodeSequence_CodeMeaning[kk] |= df_allheaders[cc].map(lambda x: kk in x if type(x) is str else False) + + + ViewModifierCodeSequence_CodeMeaning = pd.DataFrame(ViewModifierCodeSequence_CodeMeaning) + ViewModifierCodeSequence_CodeMeaning.columns = \ + ViewModifierCodeSequence_CodeMeaning.columns.map(lambda x: colprefix + "_" + x.replace(" ","")) + + for cc in cols: + df_allheaders.drop(cc, axis=1, inplace=True) + df_allheaders = pd.concat([df_allheaders, ViewModifierCodeSequence_CodeMeaning], axis=1) + return df_allheaders + +#############################33 +def normalize_fields(df_allheaders): + # ## Clean up + # ### PixelSpacing + if "PatientAge" in df_allheaders.columns: + df_allheaders.PatientAge = df_allheaders.PatientAge.map(lambda x: int(x.lower().rstrip('y'))) + if "DetectorActiveDimensions" in df_allheaders.columns: + df_allheaders.DetectorActiveDimensions = df_allheaders.DetectorActiveDimensions.map(parse_float_tuples_prod) + #df_allheaders.DetectorActiveDimensions = list(map(parse_float_tuples_prod, + # df_allheaders.DetectorActiveDimensions.tolist())) + + if "PixelSpacing" in df_allheaders.columns: + df_allheaders.PixelSpacing = df_allheaders["PixelSpacing"].map(format_PixelSpacing) + if "ImagerPixelSpacing" in df_allheaders.columns: + df_allheaders.ImagerPixelSpacing = df_allheaders["ImagerPixelSpacing"].map(format_PixelSpacing) + if "ModalitiesInStudy" in df_allheaders.columns: + df_allheaders["ModalitiesInStudy"] = df_allheaders["ModalitiesInStudy"].map(lambda x: "mg" in str(x)) + if "HalfValueLayer" in df_allheaders.columns: + df_allheaders["HalfValueLayer"] = df_allheaders["HalfValueLayer"].map(lambda x: x if type(x) is float else float(str(x).replace('b','').replace("'", ''))) + + + + # ### FieldOfViewDimensions + # computing area and filling in the gaps with the mode **worsens** the FNR + + # df_allheaders['FieldOfViewDimensions'] = df_allheaders['FieldOfViewDimensions'].map(lambda x: np.prod([int(y) for y in eval(x)]) if type(x) is str else x) + # df_allheaders.loc[df_allheaders['FieldOfViewDimensions'].isnull(), 'FieldOfViewDimensions'] = df_allheaders['FieldOfViewDimensions'].value_counts().argmax() + + + # df_allheaders["PartialView"].map(lambda x: type(x)).value_counts() + if "ViewPosition" in df_allheaders.columns: + df_allheaders["ViewPosition"] = df_allheaders["ViewPosition"].map(lambda x: x in ['cc', 'mlo']) + + df_allheaders = extract_list_text_field(df_allheaders, + colprefix = "ViewModifierCodeSequence_CodeMeaning") + + #df_allheaders = extract_list_text_field(df_allheaders, + # colprefix = "ViewModifierCodeSequence_CodeMeaning") + + # ### BreastImplantPresent + # #### clean up + if "BreastImplantPresent" in df_allheaders.columns: + # BreastImplantPresent = pd.Series([np.nan]*df_allheaders.shape[0]) + #BreastImplantPresent = pd.Series([False]*df_allheaders.shape[0]) + #BreastImplantPresent[df_allheaders["BreastImplantPresent"].map(str).map(lambda x: "yes" in x)] = True + BreastImplantPresent = df_allheaders["BreastImplantPresent"].map(str).map(lambda x: "yes" in x) + # BreastImplantPresent[df_allheaders["BreastImplantPresent"].map(str).map(lambda x: "no" in x)] = False + df_allheaders['BreastImplantPresent'] = BreastImplantPresent + del BreastImplantPresent + if "PartialView" in df_allheaders: + df_allheaders["PartialView"] = df_allheaders["PartialView"].map(lambda x : "yes" in x if type(x) is str else False) + + for kk in ["WindowWidth", "WindowCenter"]: + if kk in df_allheaders.columns: + df_allheaders[kk] = df_allheaders[kk].map(parse_int_tuples_median) + + if "PatientOrientation" in df_allheaders.columns: + df_allheaders.PatientOrientation = df_allheaders.PatientOrientation.map(parse_str_tuples) + if "DetectorElementPhysicalSize" in df_allheaders.columns: + df_allheaders["DetectorElementPhysicalSize"] = df_allheaders.DetectorElementPhysicalSize.map(parse_float_tuples) + # ### Grid + # df_allheaders["Grid"].value_counts() + if "Grid" in df_allheaders.columns: + df_allheaders["Grid"] = (df_allheaders["Grid"] + .map(str) + .map(lambda x: x.replace('(','') + .replace(')','') + .replace("'","") + .replace(',','') + .replace("parrallel", "parallel"))) + + df_allheaders.loc[df_allheaders["Grid"] == "('reciprocating', 'parrallel')", "Grid"] = "('reciprocating', 'parallel')" + df_allheaders["Grid"].value_counts() + # df_allheaders.PixelSpacing = df_allheaders.PixelSpacing.astype(str) + # df_allheaders.PixelSpacing.value_counts() + if "FieldOfViewOrigin" in df_allheaders.columns: + df_allheaders["FieldOfViewOrigin_x"] = df_allheaders.FieldOfViewOrigin.map(lambda x : get_index_from_int_tuple(x, 0)) + df_allheaders["FieldOfViewOrigin_y"] = df_allheaders.FieldOfViewOrigin.map(lambda x : get_index_from_int_tuple(x, 1)) + df_allheaders.drop("FieldOfViewOrigin", axis=1, inplace=True) + + #informative_cols.remove("FieldOfViewOrigin") + #informative_cols.append("FieldOfViewOrigin_x") + #informative_cols.append("FieldOfViewOrigin_y") + if "FocalSpots" in df_allheaders.columns: + df_allheaders.loc[df_allheaders["FocalSpots"].isnull(), "FocalSpots"] = df_allheaders["FocalSpots"].value_counts().argmax() + for kk in ["PixelSpacing", "EstimatedRadiographicMagnificationFactor", "XRayTubeCurrent", "DistanceSourceToPatient"]: + # print(kk) + if kk in df_allheaders.columns: + df_allheaders.loc[df_allheaders[kk].isnull(), kk] = df_allheaders[kk].median() + if "ImageType" in df_allheaders.columns: + keywords = set(chain(*(df_allheaders.ImageType.map(lambda x: parse_str_tuples(x)).tolist()))) + keywords.remove("") + for kk in keywords: + key = "ImageType"+"_"+kk + df_allheaders[key] = df_allheaders.ImageType.map(lambda x: kk in x) + df_allheaders.drop("ImageType", axis=1, inplace=True) + + return df_allheaders + + +def move_digits_back(allcolumns): + allcolumns = list(allcolumns) + for nn, x in enumerate(allcolumns): + if x[0] in set(list('0123456789')): + x = "_".join(x.split("_")[1:] + x.split("_")[:1]) + allcolumns[nn] = x + return allcolumns + +def get_features(df_allheaders, thr_stderr = 1e-6): + # df_allheaders.columns = move_digits_back(df_allheaders.columns) + + df_allheaders = normalize_fields(df_allheaders.copy()) + text_fields = select_text_fields(df_allheaders) + # df_allheaders[text_fields].apply(entropy).hist() + + if thr_stderr >0: + field_list = get_good_numeric_fields(df_allheaders,thr_stderr=thr_stderr) + field_list = list(set(clean_up_field_list(field_list + text_fields))) + + df_allheaders = make_lowercase_text_fields(df_allheaders) + + # pd.crosstab(df_allheaders['0_ViewCodeSequence_CodeMeaning'], df_allheaders['ViewPosition']) + # informative_cols = ['Filename', 'AccessionNumber','BreastImplantPresent','DistanceSourceToPatient','EstimatedRadiographicMagnificationFactor', + # 'FocalSpots','Grid','PixelSpacing','XRayTubeCurrent', 'ViewPosition', 'PartialView'] + + informative_cols = ['Filename', 'AccessionNumber'] + field_list + + feature_columns = informative_cols[2:] + + noncategorical = ['ContentTime', + 'FieldOfViewOrigin_x', + 'FieldOfViewOrigin_y', + 'HalfValueLayer', + 'WindowWidth', + 'CompressionForce', + 'DetectorActiveDimensions', + 'RelativeXRayExposure', + 'ExposureTime', + 'Exposure', + 'BodyPartThickness', + 'FieldOfViewOrigin_y', + 'CollimatorLowerHorizontalEdge', + 'WindowCenter', + 'FieldOfViewRotation', + 'KVP', + 'DistanceSourceToDetector', + 'DistanceSourceToEntrance', + 'CollimatorLeftVerticalEdge', + 'DetectorTemperature', + 'HighBit'] + categorical = ['Manufacturer', + 'ManufacturerModelName', + 'Grid_htc', + 'ViewModifierCodeSequence_CodeMeaning', + 'ViewModifierCodeSequence_CodeMeaning'] + + noncategorical = list(set(feature_columns) & set(noncategorical)) + potentially_categorical = (set(feature_columns) - set(noncategorical)) + potentially_categorical |= set(categorical) & set(df_allheaders.columns) + potentially_categorical = list(potentially_categorical) + print("potentially_categorical", len(potentially_categorical)) + print("non_categorical", len(noncategorical)) + for cc in noncategorical: + if str(df_allheaders[cc].dtype) == 'object': + df_allheaders[cc] = df_allheaders[cc].map(parse_float).astype(float) + if len(potentially_categorical)>0: + df_allheaders[potentially_categorical] = df_allheaders[potentially_categorical].fillna('unknown') + features_onehot = pd.get_dummies(df_allheaders[potentially_categorical], + drop_first=True, prefix_sep='=') + features_onehot = pd.concat([features_onehot, df_allheaders[noncategorical]], axis=1) + else: + print("no features to binarise!") + features_onehot = df_allheaders[non_categorical].copy() + + #features_onehot = pd.concat([df_allheaders.Filename, features_onehot],axis=1,).set_index("Filename") + + features_onehot.shape, features_onehot.dropna().shape + + # ### Map DICOM file name to PNG file name (remove directories) + #features_onehot.index = features_onehot.index.map(lambda x: "_".join(x.split("/")[-4:]).replace(".dcm", ".png")).tolist() + for cc in features_onehot.columns[features_onehot.isnull().any()]: + print("filling in with median:\t%s" % cc) + features_onehot.loc[features_onehot[cc].isnull(),cc] = \ + features_onehot[cc].median() + features_onehot = features_onehot.loc[:,~features_onehot.isnull().any()] + + onehotcols = np.asarray(features_onehot.columns[features_onehot.dtypes.map(lambda x : x is pd.np.dtype("uint8"))].tolist()) + thr_frac = 0.01 + bad_feature_cols = onehotcols[(features_onehot[onehotcols].sum(0) < 5) | + (features_onehot[onehotcols].mean(0) < thr_frac) | + (features_onehot[onehotcols].mean(0) > (1-thr_frac))] + len(bad_feature_cols) + features_onehot.drop(bad_feature_cols, axis=1, inplace=True) + if "FocalSpots" in features_onehot: + features_onehot.loc[features_onehot["FocalSpots"].isnull(), "FocalSpots"] = \ + features_onehot["FocalSpots"].value_counts().argmax() + + return features_onehot + + +############################# +if __name__ == '__main__': + PREFIX="allfeatures" + + # !sudo pip3 install dicom + # # read a table of DICOM headers + filelist_fn = '/home/dlituiev/data_dlituiev/manuallabeller/filelist/filelist_nonscreening_4000_seed42.csv' + outpath = os.path.join(os.path.dirname(filelist_fn), "dicom_headers_all_fields_" + os.path.basename(filelist_fn)) + print(outpath) + df_allheaders = pd.read_csv(outpath, index_col=0) + features_onehot = get_features(df_allheaders) + + # ## Read labels + fn_man_labels = "/data/dlituiev/tables/cleaned_manual_labels_valset_4000.txt" + df = pd.read_table(fn_man_labels, index_col=0) + df.index = df.index.map(lambda x : x.split("/")[-1]) + + # process labels + df["special_view"] = df["regular_view"].map(lambda x: not x) + + + dfm = pd.merge(df[["special_view"]], features_onehot, how='left', left_index=True, right_index=True) + dfm.shape + + import seaborn as sns + import matplotlib.pyplot as plt + from statsmodels.graphics.mosaicplot import mosaic + plt.matplotlib.rcParams["hatch.color"] = [0.7]*3 + + dfm.var() + dfm.isnull().sum() + dfm.plot(x='special_view', y='XRayTubeCurrent', kind='scatter', alpha=0.05) + dfm.plot(x='special_view', y='DistanceSourceToPatient', kind='scatter', alpha=0.05) + dfm["special_view"].isnull().sum() + + + target = dfm["special_view"] + features = dfm.drop("special_view", axis=1) + + + from sklearn.utils import shuffle + # for building and visualizing the decision tree + from sklearn.naive_bayes import GaussianNB, BernoulliNB + # from sklearn.svm import SVC + from sklearn.tree import DecisionTreeClassifier + from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier + # visualization + from vis_tree import visualize_tree + from sklearn.model_selection import train_test_split, cross_val_score + from sklearn.metrics import (accuracy_score, auc, confusion_matrix, f1_score, + precision_score, roc_curve, precision_recall_curve) + + + + + y_dev, y_val, X_dev, X_val = train_test_split(target, features, random_state=0, test_size=1/6) + + y_tr, y_ts, X_tr, X_ts = train_test_split(y_dev, X_dev, random_state=0, test_size=1/5) + + + + + # dtree = DecisionTreeClassifier(max_depth=10, min_samples_leaf=5, criterion="entropy") + # dtree = RandomForestClassifier(min_samples_split=10, min_samples_leaf=5) + # dtree = AdaBoostClassifier(base_estimator=dtree, n_estimators=60, learning_rate=0.01) + # dtree = AdaBoostClassifier(base_estimator=GaussianNB(), n_estimators=50, learning_rate=0.01) + + + + + dtree = GradientBoostingClassifier(max_depth=8, n_estimators=40, learning_rate=0.05, min_samples_leaf=12) + modelname = str((dtree).__class__).split(".")[-1].rstrip(""" "'> """).lstrip('"') + + + + + dtree.fit(X_tr, y_tr) + pred_y_ts = dtree.predict(X_ts) + pred_yscore_ts = dtree.predict_proba(X_ts) + + + + + get_ipython().magic('pinfo auc') + + + + + pr_, rec_, thresholds = precision_recall_curve(y_ts.tolist(), pred_yscore_ts[:,1], pos_label=1) + # auc_pr = auc(pr_, rec_) + + plt.plot(pr_, rec_) + plt.xlabel('Precision') + plt.ylabel('Recall') + # plt.title('auPRC = {0:.2f}%'.format(auc_pr)) + plt.xlim([0,1]) + plt.ylim([0,1]) + plt.axis('equal') + plt.axis('square') + + print("%.2f" % (100*auc_)) + frmt = 'png' + plt.savefig("{}_{}_auc.{}".format(PREFIX, modelname, frmt), dpi=300, format=frmt) + + + + + fpr_, tpr_, thresholds = roc_curve(y_ts.tolist(), pred_yscore_ts[:,1], pos_label=1) + auc_ = auc(fnr_, tpr_) + + plt.plot(fpr_, tpr_) + plt.xlabel('False Positive Rate') + plt.ylabel('True Positive Rate') + plt.title('AUC = {0:.2f}%'.format(auc_)) + plt.axis('equal') + plt.axis('square') + + print("%.2f" % (100*auc_)) + frmt = 'png' + plt.savefig("{}_{}_auc.{}".format(PREFIX, modelname, frmt), dpi=300, format=frmt) + + + + + # pd.DataFrame(dict(FNR=fnr_, TPR=tpr_, threshold=thresholds)) + features.plot(x="EstimatedRadiographicMagnificationFactor", y="PixelSpacing", kind='scatter') + + + + + fig,ax = plt.subplots(1, figsize=(6,14)) + feat_imp = pd.Series(dtree.feature_importances_, index=features.columns) + feat_imp = feat_imp[feat_imp>0.0].sort_values()[::-1] + feat_imp[::-1].plot(kind='barh', ax=ax) + print(feat_imp) + # plt.xlim([0,0.5]) + # plt.tight_layout() + frmt = 'png' + plt.savefig("{}_{}_feature_importances.{}".format(PREFIX, modelname, frmt), dpi=300, format=frmt) + + + + + + + + + + len(thresholds) + + + + + # pd.DataFrame(dict( + # FNR=fnr_, + # TPR=tpr_, + # threshold = thresholds)) + + + + + df_confusion = pd.crosstab(pd.Series(y_ts.as_matrix(), name="observed"), pd.Series(pred_y_ts, name="predicted")) + df_confusion + confusion_matrix(y_ts, pred_y_ts) + cm = confusion_matrix(y_ts, pred_y_ts) + cm[1,0]/cm[1,:].sum() + def fnr(dtree, X_val, y_val, thr = None): + if not thr: + pred_y_val = dtree.predict(X_val) + else: + pred_y_val = dtree.predict_proba(X_val)[:,1] > thr + # df_confusion = pd.crosstab(pd.Series(np.asarray(y_val), name="observed"), + # pd.Series(pred_y_val, name="predicted")) + # out = df_confusion[False][True] / (df_confusion[False][True] + df_confusion[True][True]) + + cm = confusion_matrix(y_val, pred_y_val) + out = cm[1,0]/cm[1,:].sum() + return out + + + + + def fpr(dtree, X_val, y_val, thr = None): + if not thr: + pred_y_val = dtree.predict(X_val) + else: + pred_y_val = dtree.predict_proba(X_val)[:,1] > thr + # df_confusion = pd.crosstab(pd.Series(np.asarray(y_val), name="observed"), + # pd.Series(pred_y_val, name="predicted")) + # out = df_confusion[True][False] / (df_confusion[False][False] + df_confusion[True][False]) + + + cm = confusion_matrix(y_val, pred_y_val) + if cm[0,:].sum() !=0: + out = cm[0,1]/cm[0,:].sum() + else: + out = 0.0 + return out + + + + + + + + + + THR = 0.15 + + + # True | False + # True TP | FN + # False FP | TN + # + # + # FPR = FP / (FP + TN) + # + + + + pred_y_ts = dtree.predict_proba(X_ts)[:,1] > THR + df_confusion = pd.crosstab(pd.Series(y_ts.as_matrix(), name="observed"), pd.Series(pred_y_ts, name="predicted")) + print(df_confusion.to_csv(sep='|')) + + + + + THR = 0.05 + + modelname = str((dtree).__class__).split(".")[-1].rstrip(""" "'> """).lstrip('"') + cv_fnr = cross_val_score(dtree, X_dev, y_dev, groups=None, scoring=partial(fnr, thr=THR), cv=5, n_jobs=1, pre_dispatch='2*n_jobs') + cv_fpr = cross_val_score(dtree, X_dev, y_dev, groups=None, scoring=partial(fpr, thr=THR), cv=5, n_jobs=1, pre_dispatch='2*n_jobs') + + tmpstr = """model: {} + threshold = {} + + on the hold-out set:\tFNR = {:.2f}%, FPR = {:.2f}% + + in 5-fold cross-validation (mean):\tFNR = {:.2f}%, FPR = {:.2f}%""".format( + modelname, THR, + 100*fnr(dtree, X_ts, y_ts, thr = THR), 100*fpr(dtree, X_ts, y_ts, thr = THR), + 100*cv_fnr.mean(), 100*cv_fpr.mean()) + print(tmpstr) + + + + + THR = 0.5 + modelname = str((dtree).__class__).split(".")[-1].rstrip(""" "'> """).lstrip('"') + cv_fnr = cross_val_score(dtree, X_dev, y_dev, groups=None, scoring=partial(fnr, thr=THR), cv=5, n_jobs=1, pre_dispatch='2*n_jobs') + cv_fpr = cross_val_score(dtree, X_dev, y_dev, groups=None, scoring=partial(fpr, thr=THR), cv=5, n_jobs=1, pre_dispatch='2*n_jobs') + + tmpstr = """model: {} + threshold = {} + + on the hold-out set:\tFNR = {:.2f}%, FPR = {:.2f}% + + in 5-fold cross-validation (mean):\tFNR = {:.2f}%, FPR = {:.2f}%""".format( + modelname, THR, + 100*fnr(dtree, X_ts, y_ts, thr = THR), 100*fpr(dtree, X_ts, y_ts, thr = THR), + 100*cv_fnr.mean(), 100*cv_fpr.mean()) + print(tmpstr) + + + + + 6/72 + + + # ## fnr + # 0.1443 -- AdaBoostClassifier(50, lr=0.1) with: + # + # + # DecisionTreeClassifier(max_depth=7, min_samples_leaf=5, criterion="entropy") + # GaussianNB() + # + # 0.1134 -- AdaBoostClassifier(50, lr=0.01) with: + # GaussianNB() + + + + accuracy_score(y_true=y_val, y_pred=pred_y_val) + + + + + f1_score(y_true=y_val, y_pred=pred_y_val) + + + + + + + + + + confusion_matrix(y_true=y_val, y_pred=pred_y_val) + + + + + + df_confusion = pd.crosstab(pd.Series(y_val.as_matrix(), name="observed"), + pd.Series(pred_yscore_dev[:,1]>0.15, name="predicted")) + df_confusion + + + + + df_confusion[False][True] / (df_confusion[False][True] + df_confusion[True][True]) + + + + + df_confusion[True][False] / (df_confusion[False][False] + df_confusion[True][False]) + + + + + 109/(385+109) + + + # ## Misclassified: examples and comments + + + + # pred_false = (pd.Series(pred_y_val, name="predicted")==False) + pred_false = (pd.Series(pred_yscore_dev[:,1]<0.15, name="predicted")==False) + false_negatives = (pd.Series(y_val.as_matrix(), name="observed")) & pred_false + false_negatives.index=y_val.index + false_negatives.shape, df.shape + # y_val[false_negatives.tolist()].shape + + + + + + + + + + + + + + + xstr = """1805162996_1.2.840.113654.2.70.1.75424722723272471565664976911416714890_2_37.png -- implant? + 1433463766_1.2.840.113654.2.70.1.243422935316700791950696878743366703411_6_6.png -- male? + 3395322213_1.2.840.113654.2.70.1.161905211577383187509354224390811944382_1161_7.png -- overexposed with scale grid + 1383662805_1.2.840.113654.2.70.1.194667288082835549565211946781626641146_1_88.png -- mag? bars in the image + 5717508670_1.2.840.113654.2.70.1.135196805563780165444562848954663016070_2_6.png -- spot + 1582554801_1.2.840.113654.2.70.1.202883517655342643705007475928329105895_1_1.png -- strange shape; plate + 3248534628_1.2.840.113654.2.70.1.153327658320065917717726871735320153117_14_8.png -- RLMID, implant + 1050998385_1.2.840.113654.2.70.1.294672228525412928579179278566440354700_168_12.png -- RMLO, underexposed, plate + 2431514667_1.2.840.113654.2.70.1.132697486450403983700631264913146412468_1_1.png -- regular CC + 2836025574_1.2.840.113654.2.70.1.94728406891527814842052605970255602447_31728_4.png -- regular CC, wire? + 2774547752_1.2.840.113654.2.70.1.152335331945150793610356395498084601027_47428_6.png -- poor exposure? + 6784971236_1.2.840.113654.2.70.1.276140387730485551768768734852859745761_21705_2.png -- regular CC + 6120027884_1.2.840.113654.2.70.1.202389441802705593488291262945242015864_28128_3.png -- spot + 2127109953_1.2.840.113654.2.70.1.136443797025605972119376095795980286524_5_26.png -- RML, scar + 5015120217_1.2.840.113654.2.70.1.8576402180164318136049174781190805706_19615_3.png -- regular MLO, underexposure + 2915273528_1.2.840.113654.2.70.1.50904067248781976561131370015339684052_3_51.png -- RLM + 2859796079_1.2.840.113654.2.70.1.248757700026158935826319533755178408586_3_51.png -- LMLO, scar""".split("\n") + + + + + df_misclassified_comments = pd.DataFrame([x.split(" -- ") for x in xstr], columns=["Filename", "comment"]).applymap(lambda x: x.rstrip().lstrip()).set_index("Filename")["comment"] + df_misclassified_comments + + + + + df_misclassified_comments[false_negatives & X_val[false_negatives]['ViewPosition'] & ~X_val[false_negatives]['ViewModifierCodeSequence'] ] + + + + + df_misclassified_comments[false_negatives & X_val[false_negatives]['ViewPosition'] & ~X_val[false_negatives]['ViewModifierCodeSequence'] ] + + + + + X_val.columns + + + + + # X_val[false_negatives][['ViewPosition_ccid', 'ViewPosition_lm', 'ViewPosition_lmid', + # 'ViewPosition_ml', 'ViewPosition_mlo', 'ViewPosition_mloid', + # 'ViewPosition_xccl', "FieldOfViewDimensions_('145', '105')"]] + + X_val[false_negatives][['ViewPosition', + 'ViewModifierCodeSequence']] + diff --git a/dicom_header_extraction/normalize_selected_dcm_headers.py b/dicom_header_extraction/normalize_selected_dcm_headers.py new file mode 100644 index 0000000..8b39df8 --- /dev/null +++ b/dicom_header_extraction/normalize_selected_dcm_headers.py @@ -0,0 +1,97 @@ + +# coding: utf-8 + +#cell# + +import pandas as pd +import sys +from header_cleaner import get_features, normalize_fields, parse_float_tuples, parse_float + +#cell# +fn_features = "../tables/df_all_mammos_dicom_headers_selected.tab.gz" +outfn = "../tables/df_all_mammos_dicom_headers_selected_norm.tab" + +dffeatures = pd.read_table(fn_features, index_col="filename") + +#cell# +mask_nonnumeric = ~dffeatures["ContentTime"].map(lambda x: isinstance(x, float) | isinstance(x, int)) +dffeatures.loc[mask_nonnumeric, "ContentTime"] = dffeatures["ContentTime"][mask_nonnumeric].map(lambda x: float(x.replace(':','').replace('--',"30"))) + +#cell# +print("shape", dffeatures.shape) + +#cell# +normalize_fun = {"0_ViewCodeSequence__0_ViewModifierCodeSequence_CodeMeaning": + lambda x: str(x).lower(), + "0_ViewCodeSequence_CodeValue": lambda x: str(x), + "Grid": lambda x: str(x).replace("'","") + .replace("(","").replace(")","") + .replace(",","").replace("/"," ") + .replace('PARRALLEL',"PARALLEL") + .lower(), + "HighBit": lambda x: str(int(x)) if (isinstance(x, float) and x*1==x) else str(x), + "WindowCenter": lambda x: np.median(parse_float_tuples(x)), + "FieldOfViewOrigin":parse_float_tuples, + "EstimatedRadiographicMagnificationFactor": lambda x: x, + "ContentTime": lambda x: x, + "FieldOfViewRotation": lambda x: float(parse_float(x)), + "KVP": lambda x: float(parse_float(x)), + "ShutterLowerHorizontalEdge": lambda x: float(parse_float(x)), + "ShutterRightVerticalEdge": lambda x: float(parse_float(x)), + "XRayTubeCurrentInuA": lambda x: float(parse_float(x)), + "RelativeXRayExposure": lambda x: float(parse_float(x)), + "ManufacturerModelName": lambda x: str(x).lower().replace('"',''), + "Manufacturer": lambda x: str(x).lower().replace('"','').replace(',', '').replace(" inc", "").rstrip('.'), + "BodyPartThickness":lambda x: float(parse_float(x)), + "CollimatorLeftVerticalEdge": lambda x: float(parse_float(x)), + "CollimatorLowerHorizontalEdge": lambda x: float(parse_float(x)), + "DetectorActiveDimensions" : lambda x: parse_float_tuples(x.replace("\\", ", ") if isinstance(x, str) else x), + "ExposureTime": lambda x: x, + "ExposuresOnDetectorSinceLastCalibration": lambda x: x, + "ExposuresOnDetectorSinceManufactured": lambda x: x, + "DistanceSourceToEntrance": lambda x: x, + "DetectorTemperature":lambda x: float(parse_float(x)), + "DistanceSourceToDetector": lambda x: x, + +} + +dtypes = {"0_ViewCodeSequence__0_ViewModifierCodeSequence_CodeMeaning": str, + "0_ViewCodeSequence_CodeValue": str, + "Grid": str, + "HighBit": str, # int + "WindowCenter": int, + "FieldOfViewOrigin": 'O', + "EstimatedRadiographicMagnificationFactor": float, + "ContentTime": float, #NaN + "FieldOfViewRotation": float, + "KVP": float, + "ShutterLowerHorizontalEdge": float, + "ShutterRightVerticalEdge": float, + "XRayTubeCurrentInuA": float, + "RelativeXRayExposure": float, + "ManufacturerModelName": str, + "Manufacturer": str, + "BodyPartThickness": float, + "CollimatorLeftVerticalEdge": float, + "CollimatorLowerHorizontalEdge": float, + "DetectorActiveDimensions" : 'O', + "ExposureTime": float, + "ExposuresOnDetectorSinceLastCalibration": float, # NaNs + "ExposuresOnDetectorSinceManufactured": float, # NaNs + "DistanceSourceToEntrance": float, + "DetectorTemperature": float, + "DistanceSourceToDetector": float, + +} + +#cell# + +set(dffeatures.columns) - set(normalize_fun.keys()) + +#cell# + +for kk, vv in dffeatures.items(): + print(kk) + dffeatures.loc[:,kk] = vv.map(normalize_fun[kk]).astype(dtypes[kk]) + +dffeatures.to_csv(outfn, sep='\t', compression='gzip') diff --git a/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/checkpoint.info b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/checkpoint.info new file mode 100644 index 0000000..41a0c83 --- /dev/null +++ b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/checkpoint.info @@ -0,0 +1,48 @@ +ReduceLROnPlateau: + cooldown: 32 + epsilon: 0.001 + factor: 0.5 + min_lr: 1.0e-08 + mode: auto + monitor: val_loss + patience: 32 + verbose: 0 +base_trainable: true +batch_size: 256 +class_mode: binary +class_weights: null +classes: +- normal +- special +contrast: null +data_augmentation: true +data_train: /data/UCSF_MAMMO/2018-02-png/withx_valset_4000_train +data_val: /data/UCSF_MAMMO/2018-02-png/withx_valset_4000_test +dropout: 0.5 +fill_mode: reflect +final_activation: sigmoid +height_shift_range: 0.125 +horizontal_flip: true +init_epoch: 0 +loss_weights: null +lr: 0.0001 +n_classes: 1 +nb_epoch: 500 +ndense: 0 +oversampling: false +pretrained: true +rotation_range: 15 +samplewise_center: false +seed: 2 +target_side: 99 +target_size: +- 99 +- 99 +truncate_quantile: null +vertical_flip: false +weightfile: null +width_shift_range: 0.125 +zoom_range: +- 0.8 +- 1.2 +ztransform: false diff --git a/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/inception_short.py b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/inception_short.py new file mode 120000 index 0000000..0a184cd --- /dev/null +++ b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/inception_short.py @@ -0,0 +1 @@ +../inception_short.py \ No newline at end of file diff --git a/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/predict.py b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/predict.py new file mode 100644 index 0000000..4150372 --- /dev/null +++ b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/predict.py @@ -0,0 +1,185 @@ + +# coding: utf-8 +import sys +import pandas as pd +sys.path.append('../..') + +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from image import ImageDataGenerator +# from keras.preprocessing.image import ImageDataGenerator +from keras.models import load_model +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, TensorBoard, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger, lr_cyclic_schedule +from shutil import copy2 +from functools import partial + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +import os +import yaml +import numpy as np +import keras +from hashlib import md5 +os.environ["PYTHONHASHSEED"]='0' +os.environ['KERAS_BACKEND'] = 'tensorflow' +os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' + +if os.environ["CUDA_VISIBLE_DEVICES"] == '': + os.environ["CUDA_VISIBLE_DEVICES"] = '1' + + +indir = "./" + +import yaml +with open(os.path.join(indir, "checkpoint.info")) as chkpt_fh: + prms = AttrDict(yaml.load(chkpt_fh)) + print("\n".join(["%s\t%s" %(kk,vv) for kk,vv in prms.items()]),) + +weightfile = os.environ["WFILE"] +#weightfile = "model.175-0.068012.hdf5" +prms['weightfile'] = weightfile +prms['weightfile'] = os.path.join(indir, prms['weightfile']) +prms['weightfile'] + + +# In[6]: + + +prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) +print("loss:", prms["loss"]) + +# CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + +SAMPLES_PER_EPOCH = get_num_files(prms.data_train) +STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + +print('='*50) +print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) +print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) +print('='*50) +######################################### + +if prms.weightfile: + print("LOADING WEIGHTS FROM:\t%s" % prms.weightfile) +# model.load_weights(prms.weightfile) + model = load_model(prms.weightfile) + + +# In[22]: + + +flowfromdir_params = dict( +# color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + +norm_params = dict( + #rescale=prms.scaleup, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + ) + + +# In[23]: + + +train_datagen = ImageDataGenerator(**norm_params) + +train_datagen.preprocessing_function = lambda x: x[...,::-1,:]#*2**-8 +datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + #stratify = prms.oversampling, + #sampling_factor=prms.sampling_factor, + #oversampling=prms.oversampling, + shuffle=False, **flowfromdir_params) +SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) +STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + +########################################## +def get_predictions(data_dir, + preprocessing_function = lambda x:x, + model=model): + if isinstance(preprocessing_function, str): + if preprocessing_function == 'fliplr': + preprocessing_function = lambda x: x[...,::-1,:] + elif preprocessing_function in ('identity', 'orig'): + preprocessing_function = lambda x:x + else: + raise ValueError('unknown preprocessing_function:\t%s' + % preprocessing_function) + + val_datagen = ImageDataGenerator(**norm_params) + val_datagen.preprocessing_function = preprocessing_function + datagen_val_output = val_datagen.flow_from_directory( + data_dir, + shuffle=False, **flowfromdir_params) + + gen_ = datagen_val_output + yhat = model.predict_generator(gen_, + steps=len(gen_), + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":gen_.filenames, "label": gen_.classes}) + dfres = pd.DataFrame(dfdict) + return dfres +########################################## +# HOLDOUT +########################################## +data_holdout = '/data/UCSF_MAMMO/2018-02-png/withx_valset_4000_val' +dfres = get_predictions( + data_holdout, + preprocessing_function = lambda x:x, + model=model) +dfres.to_csv("predictions_val.csv", index=False) +########################################## +preprocessing_function = lambda x: x[...,::-1,:] +dfres = get_predictions( + data_holdout, + preprocessing_function = preprocessing_function, + model=model) + +dfres.to_csv("predictions_val_fliplr.csv", index=False) +########################################## +# Test +########################################## + +dfres = get_predictions( + prms.data_val, + preprocessing_function = lambda x:x, + model=model) +dfres.to_csv("predictions_test.csv", index=False) +########################################## + +preprocessing_function = lambda x: x[...,::-1,:] +dfres = get_predictions( + prms.data_val, + preprocessing_function = preprocessing_function, + model=model) +dfres.to_csv("predictions_test_fliplr.csv", index=False) +########################################## +# TRAIN +########################################## +dfres = get_predictions( + prms.data_train, + preprocessing_function = lambda x:x, + model=model) +dfres.to_csv("predictions_train.csv", index=False) +########################################## +preprocessing_function = lambda x: x[...,::-1,:] +dfres = get_predictions( + prms.data_train, + preprocessing_function = preprocessing_function, + model=model) +dfres.to_csv("predictions_train_fliplr.csv", index=False) + diff --git a/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/trainer_inception_simple_nodense.py b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/trainer_inception_simple_nodense.py new file mode 100644 index 0000000..a228d69 --- /dev/null +++ b/image_classifiers/e5ce2d69b035975cb5336cec0da9a32a/trainer_inception_simple_nodense.py @@ -0,0 +1,239 @@ +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from image import ImageDataGenerator +#from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, TensorBoard, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger, lr_cyclic_schedule +from shutil import copy2 +from functools import partial + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +if __name__ == '__main__': + import sys + import os + import yaml + import numpy as np + import keras + from hashlib import md5 + os.environ["PYTHONHASHSEED"]='0' + os.environ['KERAS_BACKEND'] = 'tensorflow' + os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' + os.environ["CUDA_VISIBLE_DEVICES"] = '1' + + prms = AttrDict( + dropout=0.5, + base_trainable=True, + horizontal_flip = True, + vertical_flip = False, + zoom_range = [0.8, 1.2], + rotation_range = 15, + fill_mode='reflect', + ndense=0, + batch_size = 128*2, + init_epoch=0, + nb_epoch = 500, + data_augmentation = True, + contrast = None, #0.8, + truncate_quantile = None,#0.001, + ztransform = False, + oversampling = False, + #sampling_factor = None, [1, 6, 16, 64, 4], + seed=2, + width_shift_range = 0.125, + height_shift_range = 0.125, + class_mode = 'binary', # 'binary', # + n_classes = 1, + final_activation = 'sigmoid', + lr = 1e-4, + samplewise_center = False, #True + target_side = 99, + weightfile = None, + pretrained = True, + data_train = '/data/UCSF_MAMMO/2018-02-png/withx_valset_4000_train', + data_val = '/data/UCSF_MAMMO/2018-02-png/withx_valset_4000_test', + classes = ['normal', 'special'], + class_weights=None,#[1, 1, 4, 8, 4], + loss_weights = None, + ReduceLROnPlateau = dict( + monitor='val_loss', + factor=1/2, + patience=32, + verbose=0, + mode='auto', epsilon=0.001, + cooldown=32, + min_lr=1e-8, + ), +# lr_cyclic_schedule = dict( +# #lr_init = 1.0e-3, +# drop = 2/5, +# epochs_drop = 20, +# cycle_len = 200.0 +# ) + ) + + + paramhash = md5(str(prms).encode()).hexdigest() + + prms["target_size"] = [ prms.target_side ]*2 + + CHECKPOINT_DIR = "checkpoints/" + paramhash + "/" + os.makedirs(CHECKPOINT_DIR, exist_ok=True) + print("SAVING TO:\t%s" % CHECKPOINT_DIR) + # copy the script to the checkpoint directory + copy2(os.path.abspath(__file__), CHECKPOINT_DIR) + with open(os.path.join(CHECKPOINT_DIR, "checkpoint.info"), "w+") as outfh: + yaml.dump(dict(prms), outfh, default_flow_style=False) + + prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) + print("loss:", prms["loss"]) + + CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + + SAMPLES_PER_EPOCH = get_num_files(prms.data_train) + STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + ######################################### + checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=False, save_weights_only=False, mode='auto', period=1) + + csv_path = os.path.join(CHECKPOINT_DIR, "progresslog.csv") + csv_callback = CSVWallClockLogger(csv_path, separator=',', append=False) + + + callback_list = [checkpoint, csv_callback] + + if ("ReduceLROnPlateau" in prms) and prms["ReduceLROnPlateau"]: + callback_list.append(ReduceLROnPlateau(**prms["ReduceLROnPlateau"])) + + elif "lr_cyclic_schedule" in prms: + callback_list.append( + LearningRateScheduler( + partial(lr_cyclic_schedule, + lr_init = prms.lr, + **prms.lr_cyclic_schedule) + ) + ) + ######################################### + model = get_model(n_classes=prms.n_classes, + final_activation=prms.final_activation, + ndense=prms.ndense, + dropout=prms.dropout, + base_trainable=prms.base_trainable, + weights = 'imagenet' if prms.pretrained else None, + input_shape = prms.target_size + [3]) + + + #from keras.utils import plot_model + #plot_model(model, to_file='model.png') + + model.compile(optimizer=Adam(lr=prms.lr), loss=prms.loss, + metrics=['accuracy'], + ) + ######################################### + if prms.weightfile: + print("loading weights from:\t%s" % prms.weightfile) + model.load_weights(prms.weightfile) + + ######################################### + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + norm_params = dict( + #rescale=prms.scaleup, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + ) + + def _ztransform(x): + return (x-np.mean(x)) / np.std(x) + + if 'preprocessing_function' in prms: + if prms.preprocessing_function=='ztransform': + preprocessing_function = _ztransform + elif prms.preprocessing_function=='m1p1': + preprocessing_function = lambda x: x/128.0 - 1 + else: + raise ValueError("unknown preprocessing_function") + else: + preprocessing_function = lambda x: x + + + if prms.data_augmentation: + + print('Using real-time data augmentation.') + train_datagen = ImageDataGenerator( + zoom_range=prms.zoom_range, + fill_mode=prms.fill_mode, + rotation_range = prms.rotation_range, + width_shift_range = prms.width_shift_range, + height_shift_range = prms.height_shift_range, + horizontal_flip=prms.horizontal_flip, + vertical_flip=prms.vertical_flip, + contrast = prms.contrast, + z_transform = prms.ztransform, + truncate_quantile = prms.truncate_quantile, + #histeq_alpha=prms.histeq_alpha, + **norm_params) + else: + train_datagen = ImageDataGenerator(**norm_params) + + val_datagen = ImageDataGenerator(**norm_params) + + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + stratify = prms.oversampling, + sampling_factor=prms.sampling_factor if (prms.oversampling) else None, + oversampling=prms.oversampling, + shuffle=True, **flowfromdir_params) + + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + + #VALIDATION_STEPS = get_num_files(prms.data_val) // prms.batch_size + VALIDATION_STEPS = len(datagen_val_output.filenames)/prms['batch_size'] + print("validation steps", VALIDATION_STEPS) + ######################################### + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + model.fit_generator(datagen_train_output, + steps_per_epoch=STEPS_PER_EPOCH, + epochs=prms.nb_epoch, verbose=1, + validation_data=datagen_val_output, + validation_steps=VALIDATION_STEPS, + #class_weight='auto', + class_weight=class_weights, + callbacks=callback_list, + initial_epoch=prms.init_epoch) + + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + + print("""loss\t%.4f + accuracy\t%.4f\n""" % + tuple(model.evaluate_generator(datagen_val_output, + steps=VALIDATION_STEPS, + workers=1, + pickle_safe=True))) + + + #model.predict() diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoint.info b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoint.info new file mode 100644 index 0000000..b153d43 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoint.info @@ -0,0 +1,48 @@ +ReduceLROnPlateau: + cooldown: 8 + epsilon: 0.001 + factor: 0.5 + min_lr: 1.0e-12 + mode: auto + monitor: val_loss + patience: 64 + verbose: 0 +base_trainable: false +batch_size: 16 +class_mode: categorical +class_weights: +- 1 +- 1 +classes: +- normal +- wire +data_augmentation: true +data_train: /data/UCSF_MAMMO/2018-02-png/each_class_4189_train/ +data_val: /data/UCSF_MAMMO/2018-02-png/each_class_4189_test/ +dropout: 0.5 +fill_mode: reflect +final_activation: softmax +height_shift_range: 0.125 +horizontal_flip: true +init_epoch: 0 +lr: 0.001 +n_classes: 2 +nb_epoch: 500 +ndense: 0 +oversampling: false +rescale: 1 +rotation_range: 30 +samplewise_center: false +seed: 1 +target_side: 299 +target_size: +- 299 +- 299 +truncate_quantile: null +vertical_flip: false +weightfile: null +width_shift_range: 0.125 +zoom_range: +- 0.8 +- 1.2 +ztransform: true diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/checkpoint.info b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/checkpoint.info new file mode 100644 index 0000000..65d7fc6 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/checkpoint.info @@ -0,0 +1,49 @@ +ReduceLROnPlateau: + cooldown: 8 + epsilon: 0.001 + factor: 0.5 + min_lr: 1.0e-12 + mode: auto + monitor: val_loss + patience: 64 + verbose: 0 +base_trainable: false +batch_size: 16 +class_mode: categorical +class_weights: +- 1 +- 1 +classes: +- normal +- wire +data_augmentation: true +data_holdout: /data/UCSF_MAMMO/2018-02-png/each_class_augm_xw_4189_val/ +data_train: /data/UCSF_MAMMO/2018-02-png/each_class_4189_train/ +data_val: /data/UCSF_MAMMO/2018-02-png/each_class_4189_test/ +dropout: 0.5 +fill_mode: reflect +final_activation: softmax +height_shift_range: 0.125 +horizontal_flip: true +init_epoch: 0 +lr: 0.001 +n_classes: 2 +nb_epoch: 500 +ndense: 0 +oversampling: false +rescale: 1 +rotation_range: 30 +samplewise_center: false +seed: 2 +target_side: 299 +target_size: +- 299 +- 299 +truncate_quantile: null +vertical_flip: false +weightfile: model.147-0.000774.hdf5 +width_shift_range: 0.125 +zoom_range: +- 0.8 +- 1.2 +ztransform: true diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/predict_inc_wire-no_el-no_upw-no_ups-2.py b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/predict_inc_wire-no_el-no_upw-no_ups-2.py new file mode 100644 index 0000000..78af319 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/ab0035588a1f2adf401c73020865b206/predict_inc_wire-no_el-no_upw-no_ups-2.py @@ -0,0 +1,315 @@ +import sys +import pandas as pd +sys.path.append('../..') + +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from image import ImageDataGenerator +#from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger +from shutil import copy2 +from losses import acc_0, acc_1, acc_2, acc_3, acc_4 + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +import sys +import os +import yaml +import numpy as np +import keras +from hashlib import md5 +os.environ["PYTHONHASHSEED"]='0' +os.environ['KERAS_BACKEND'] = 'tensorflow' +os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' +os.environ["CUDA_VISIBLE_DEVICES"]="0" + +prms = AttrDict( + dropout=0.5, + base_trainable=False, + horizontal_flip = True, + vertical_flip = False, + zoom_range = [0.8, 1.2], + rotation_range = 30, + fill_mode='reflect', + ndense=0, + batch_size = 16, + init_epoch=0, + nb_epoch = 500, + data_augmentation = True, + rescale = 1, #2**-8, + #contrast = 0.9, + truncate_quantile = None,#0.001, + ztransform = True, + oversampling = False, + #sampling_factor = [1, 4], + seed=2, + width_shift_range = 0.125, + height_shift_range = 0.125, + class_mode = 'categorical', # 'binary', # + n_classes = 2, + final_activation = "softmax", # 'sigmoid', + lr = 1e-3, + samplewise_center = False, #True + target_side = 299, + #weights = None, + weightfile = "model.147-0.000774.hdf5", + data_train = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_train/', + data_val = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_test/', + data_holdout = "/data/UCSF_MAMMO/2018-02-png/each_class_augm_xw_4189_val/", + classes = ["normal", "wire"], + class_weights=[1, 1], + ReduceLROnPlateau = dict( + monitor='val_loss', + factor=1/2, + patience=32*2, + verbose=0, + mode='auto', epsilon=0.001, + cooldown=8, + min_lr=1e-12, + ), +) + + +paramhash = md5(str(prms).encode()).hexdigest() + +prms["target_size"] = [ prms.target_side ]*2 + +CHECKPOINT_DIR = "checkpoints/" + paramhash + "/" +os.makedirs(CHECKPOINT_DIR, exist_ok=True) +print("SAVING TO:\t%s" % CHECKPOINT_DIR) +# copy the script to the checkpoint directory +copy2(os.path.abspath(__file__), CHECKPOINT_DIR) +with open(os.path.join(CHECKPOINT_DIR, "checkpoint.info"), "w+") as outfh: + yaml.dump(dict(prms), outfh, default_flow_style=False) +# w_categorical_crossentropy +CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + +SAMPLES_PER_EPOCH = get_num_files(prms.data_train) +STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + +print('='*50) +print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) +print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) +print('='*50) +######################################### +checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=True, save_weights_only=False, mode='auto', period=1) + +csv_path = os.path.join(CHECKPOINT_DIR, "progresslog.csv") +csv_callback = CSVWallClockLogger(csv_path, separator=',', append=False) + +prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) + +callback_list = [checkpoint, csv_callback] + + +if ("ReduceLROnPlateau" in prms) and prms["ReduceLROnPlateau"]: + callback_list.append(ReduceLROnPlateau(**prms["ReduceLROnPlateau"])) + +######################################### +model = get_model(n_classes=prms.n_classes, + final_activation=prms.final_activation, + ndense=prms.ndense, + #weights = prms.weights, + dropout=prms.dropout, + base_trainable=prms.base_trainable) + + +#from keras.utils import plot_model +#plot_model(model, to_file='model.png') +if __name__ == '__main__': + model.compile(optimizer=Adam(lr=prms.lr), loss=prms.loss, + metrics=['accuracy', acc_0, acc_1,# acc_2, acc_3, acc_4 + ], + ) + ######################################### + if prms.weightfile: + print("loading weights from:\t%s" % prms.weightfile) + model.load_weights(prms.weightfile) + + ######################################### + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + norm_params = dict( + rescale=prms.rescale, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + z_transform = prms.ztransform, + ) + + def _ztransform(x): + return (x-np.mean(x)) / np.std(x) + + if 'preprocessing_function' in prms: + if prms.preprocessing_function=='ztransform': + preprocessing_function = _ztransform + elif prms.preprocessing_function=='m1p1': + preprocessing_function = lambda x: x/128.0 - 1 + else: + raise ValueError("unknown preprocessing_function") + else: + preprocessing_function = lambda x: x + + if prms.data_augmentation: + + print('Using real-time data augmentation.') + train_datagen = ImageDataGenerator( + zoom_range=prms.zoom_range, + fill_mode=prms.fill_mode, + rotation_range = prms.rotation_range, + width_shift_range = prms.width_shift_range, + height_shift_range = prms.height_shift_range, + horizontal_flip=prms.horizontal_flip, + vertical_flip=prms.vertical_flip, + contrast = prms.contrast if "contrast" in prms else None, + truncate_quantile = prms.truncate_quantile, + #histeq_alpha=prms.histeq_alpha, + **norm_params) + else: + train_datagen = ImageDataGenerator(**norm_params) + + + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + #VALIDATION_STEPS = get_num_files(prms.data_val) // prms.batch_size + + ########################################## + # HOLDOUT + ########################################## + val_datagen = ImageDataGenerator(**norm_params) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout.csv", index=False) + ########################################## + # HOLDOUT FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout_fliplr.csv", index=False) + ######################################### + # VAL + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test.csv", index=False) + ######################################### + # VAL FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test_fliplr.csv", index=False) + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train.csv", index=False) + + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + train_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train_filplr.csv", index=False) diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/checkpoint.info b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/checkpoint.info new file mode 100644 index 0000000..6aecb0b --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/checkpoint.info @@ -0,0 +1,50 @@ +ReduceLROnPlateau: + cooldown: 8 + epsilon: 0.001 + factor: 0.5 + min_lr: 1.0e-12 + mode: auto + monitor: val_loss + patience: 64 + verbose: 0 +base_trainable: false +batch_size: 16 +class_mode: categorical +class_weights: +- 1 +- 1 +classes: +- normal +- wire +data_augmentation: true +data_everything: /media/exx/tron/2017-07-png-jae/ +data_holdout: /data/UCSF_MAMMO/2018-02-png/each_class_augm_xw_4189_val/ +data_train: /data/UCSF_MAMMO/2018-02-png/each_class_4189_train/ +data_val: /data/UCSF_MAMMO/2018-02-png/each_class_4189_test/ +dropout: 0.5 +fill_mode: reflect +final_activation: softmax +height_shift_range: 0.125 +horizontal_flip: true +init_epoch: 0 +lr: 0.001 +n_classes: 2 +nb_epoch: 500 +ndense: 0 +oversampling: false +rescale: 1 +rotation_range: 30 +samplewise_center: false +seed: 2 +target_side: 299 +target_size: +- 299 +- 299 +truncate_quantile: null +vertical_flip: false +weightfile: model.147-0.000774.hdf5 +width_shift_range: 0.125 +zoom_range: +- 0.8 +- 1.2 +ztransform: true diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/predict_inc_wire-no_el-no_upw-no_ups-2.py b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/predict_inc_wire-no_el-no_upw-no_ups-2.py new file mode 100644 index 0000000..de57f31 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/checkpoints/b7c5b29760c5717e3597787a6c1d217c/predict_inc_wire-no_el-no_upw-no_ups-2.py @@ -0,0 +1,398 @@ +import sys +import pandas as pd +sys.path.append('../..') +sys.path.append("/data/dlituiev/kerastrainutils/") + +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from _image import ImageDataGenerator +#from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger +from shutil import copy2 +from losses import acc_0, acc_1, acc_2, acc_3, acc_4 + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +import sys +import os +import yaml +import numpy as np +import keras +from hashlib import md5 +os.environ["PYTHONHASHSEED"]='0' +os.environ['KERAS_BACKEND'] = 'tensorflow' +os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' +os.environ["CUDA_VISIBLE_DEVICES"]="3" + +prms = AttrDict( + dropout=0.5, + base_trainable=False, + horizontal_flip = True, + vertical_flip = False, + zoom_range = [0.8, 1.2], + rotation_range = 30, + fill_mode='reflect', + ndense=0, + batch_size = 16, + init_epoch=0, + nb_epoch = 500, + data_augmentation = True, + rescale = 1, #2**-8, + #contrast = 0.9, + truncate_quantile = None,#0.001, + ztransform = True, + oversampling = False, + #sampling_factor = [1, 4], + seed=2, + width_shift_range = 0.125, + height_shift_range = 0.125, + class_mode = 'categorical', # 'binary', # + n_classes = 2, + final_activation = "softmax", # 'sigmoid', + lr = 1e-3, + samplewise_center = False, #True + target_side = 299, + #weights = None, + weightfile = "model.147-0.000774.hdf5", + data_train = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_train/', + data_val = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_test/', + data_holdout = "/data/UCSF_MAMMO/2018-02-png/each_class_augm_xw_4189_val/", + data_everything = "/media/exx/tron/2017-07-png-jae/", + classes = ["normal", "wire"], + class_weights=[1, 1], + ReduceLROnPlateau = dict( + monitor='val_loss', + factor=1/2, + patience=32*2, + verbose=0, + mode='auto', epsilon=0.001, + cooldown=8, + min_lr=1e-12, + ), +) + + +paramhash = md5(str(prms).encode()).hexdigest() + +prms["target_size"] = [ prms.target_side ]*2 + +CHECKPOINT_DIR = "checkpoints/" + paramhash + "/" +os.makedirs(CHECKPOINT_DIR, exist_ok=True) +print("SAVING TO:\t%s" % CHECKPOINT_DIR) +# copy the script to the checkpoint directory +copy2(os.path.abspath(__file__), CHECKPOINT_DIR) +with open(os.path.join(CHECKPOINT_DIR, "checkpoint.info"), "w+") as outfh: + yaml.dump(dict(prms), outfh, default_flow_style=False) +# w_categorical_crossentropy +CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + +SAMPLES_PER_EPOCH = get_num_files(prms.data_train) +STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + +print('='*50) +print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) +print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) +print('='*50) +######################################### +checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=True, save_weights_only=False, mode='auto', period=1) + +csv_path = os.path.join(CHECKPOINT_DIR, "progresslog.csv") +csv_callback = CSVWallClockLogger(csv_path, separator=',', append=False) + +prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) + +callback_list = [checkpoint, csv_callback] + + +if ("ReduceLROnPlateau" in prms) and prms["ReduceLROnPlateau"]: + callback_list.append(ReduceLROnPlateau(**prms["ReduceLROnPlateau"])) + +######################################### +model = get_model(n_classes=prms.n_classes, + final_activation=prms.final_activation, + ndense=prms.ndense, + #weights = prms.weights, + dropout=prms.dropout, + base_trainable=prms.base_trainable) + + +#from keras.utils import plot_model +#plot_model(model, to_file='model.png') +if __name__ == '__main__': + model.compile(optimizer=Adam(lr=prms.lr), loss=prms.loss, + metrics=['accuracy', acc_0, acc_1,# acc_2, acc_3, acc_4 + ], + ) + ######################################### + if prms.weightfile: + print("loading weights from:\t%s" % prms.weightfile) + model.load_weights(prms.weightfile) + + ######################################### + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + norm_params = dict( + rescale=prms.rescale, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + z_transform = prms.ztransform, + ) + + def _ztransform(x): + return (x-np.mean(x)) / np.std(x) + + if 'preprocessing_function' in prms: + if prms.preprocessing_function=='ztransform': + preprocessing_function = _ztransform + elif prms.preprocessing_function=='m1p1': + preprocessing_function = lambda x: x/128.0 - 1 + else: + raise ValueError("unknown preprocessing_function") + else: + preprocessing_function = lambda x: x + + if prms.data_augmentation: + + print('Using real-time data augmentation.') + train_datagen = ImageDataGenerator( + zoom_range=prms.zoom_range, + fill_mode=prms.fill_mode, + rotation_range = prms.rotation_range, + width_shift_range = prms.width_shift_range, + height_shift_range = prms.height_shift_range, + horizontal_flip=prms.horizontal_flip, + vertical_flip=prms.vertical_flip, + #contrast = prms.contrast if "contrast" in prms else None, + #truncate_quantile = prms.truncate_quantile, + #histeq_alpha=prms.histeq_alpha, + **norm_params) + else: + train_datagen = ImageDataGenerator(**norm_params) + ########################################## + # Everything + ########################################## + + val_datagen = ImageDataGenerator(**norm_params) + flowfromdir_params['classes'] = [os.path.basename(prms.data_everything.rstrip('/'))] + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_fliplr.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,:,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_flipud.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,::-1,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_fliplrud.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + ########################################## + # DONE + ########################################## + sys.exit(1) + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + #VALIDATION_STEPS = get_num_files(prms.data_val) // prms.batch_size + + ########################################## + # HOLDOUT + ########################################## + val_datagen = ImageDataGenerator(**norm_params) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout.csv", index=False) + ########################################## + # HOLDOUT FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout_fliplr.csv", index=False) + ######################################### + # VAL + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test.csv", index=False) + ######################################### + # VAL FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test_fliplr.csv", index=False) + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train.csv", index=False) + + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + train_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train_fliplr.csv", index=False) diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/inception_short.py b/image_classifiers/e8e71fc090141d7c6fb334359152d295/inception_short.py new file mode 120000 index 0000000..0a184cd --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/inception_short.py @@ -0,0 +1 @@ +../inception_short.py \ No newline at end of file diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/predict_inc_wire-no_el-no_upw-no_ups-2.py b/image_classifiers/e8e71fc090141d7c6fb334359152d295/predict_inc_wire-no_el-no_upw-no_ups-2.py new file mode 100644 index 0000000..de57f31 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/predict_inc_wire-no_el-no_upw-no_ups-2.py @@ -0,0 +1,398 @@ +import sys +import pandas as pd +sys.path.append('../..') +sys.path.append("/data/dlituiev/kerastrainutils/") + +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from _image import ImageDataGenerator +#from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger +from shutil import copy2 +from losses import acc_0, acc_1, acc_2, acc_3, acc_4 + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +import sys +import os +import yaml +import numpy as np +import keras +from hashlib import md5 +os.environ["PYTHONHASHSEED"]='0' +os.environ['KERAS_BACKEND'] = 'tensorflow' +os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' +os.environ["CUDA_VISIBLE_DEVICES"]="3" + +prms = AttrDict( + dropout=0.5, + base_trainable=False, + horizontal_flip = True, + vertical_flip = False, + zoom_range = [0.8, 1.2], + rotation_range = 30, + fill_mode='reflect', + ndense=0, + batch_size = 16, + init_epoch=0, + nb_epoch = 500, + data_augmentation = True, + rescale = 1, #2**-8, + #contrast = 0.9, + truncate_quantile = None,#0.001, + ztransform = True, + oversampling = False, + #sampling_factor = [1, 4], + seed=2, + width_shift_range = 0.125, + height_shift_range = 0.125, + class_mode = 'categorical', # 'binary', # + n_classes = 2, + final_activation = "softmax", # 'sigmoid', + lr = 1e-3, + samplewise_center = False, #True + target_side = 299, + #weights = None, + weightfile = "model.147-0.000774.hdf5", + data_train = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_train/', + data_val = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_test/', + data_holdout = "/data/UCSF_MAMMO/2018-02-png/each_class_augm_xw_4189_val/", + data_everything = "/media/exx/tron/2017-07-png-jae/", + classes = ["normal", "wire"], + class_weights=[1, 1], + ReduceLROnPlateau = dict( + monitor='val_loss', + factor=1/2, + patience=32*2, + verbose=0, + mode='auto', epsilon=0.001, + cooldown=8, + min_lr=1e-12, + ), +) + + +paramhash = md5(str(prms).encode()).hexdigest() + +prms["target_size"] = [ prms.target_side ]*2 + +CHECKPOINT_DIR = "checkpoints/" + paramhash + "/" +os.makedirs(CHECKPOINT_DIR, exist_ok=True) +print("SAVING TO:\t%s" % CHECKPOINT_DIR) +# copy the script to the checkpoint directory +copy2(os.path.abspath(__file__), CHECKPOINT_DIR) +with open(os.path.join(CHECKPOINT_DIR, "checkpoint.info"), "w+") as outfh: + yaml.dump(dict(prms), outfh, default_flow_style=False) +# w_categorical_crossentropy +CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + +SAMPLES_PER_EPOCH = get_num_files(prms.data_train) +STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + +print('='*50) +print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) +print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) +print('='*50) +######################################### +checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=True, save_weights_only=False, mode='auto', period=1) + +csv_path = os.path.join(CHECKPOINT_DIR, "progresslog.csv") +csv_callback = CSVWallClockLogger(csv_path, separator=',', append=False) + +prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) + +callback_list = [checkpoint, csv_callback] + + +if ("ReduceLROnPlateau" in prms) and prms["ReduceLROnPlateau"]: + callback_list.append(ReduceLROnPlateau(**prms["ReduceLROnPlateau"])) + +######################################### +model = get_model(n_classes=prms.n_classes, + final_activation=prms.final_activation, + ndense=prms.ndense, + #weights = prms.weights, + dropout=prms.dropout, + base_trainable=prms.base_trainable) + + +#from keras.utils import plot_model +#plot_model(model, to_file='model.png') +if __name__ == '__main__': + model.compile(optimizer=Adam(lr=prms.lr), loss=prms.loss, + metrics=['accuracy', acc_0, acc_1,# acc_2, acc_3, acc_4 + ], + ) + ######################################### + if prms.weightfile: + print("loading weights from:\t%s" % prms.weightfile) + model.load_weights(prms.weightfile) + + ######################################### + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + norm_params = dict( + rescale=prms.rescale, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + z_transform = prms.ztransform, + ) + + def _ztransform(x): + return (x-np.mean(x)) / np.std(x) + + if 'preprocessing_function' in prms: + if prms.preprocessing_function=='ztransform': + preprocessing_function = _ztransform + elif prms.preprocessing_function=='m1p1': + preprocessing_function = lambda x: x/128.0 - 1 + else: + raise ValueError("unknown preprocessing_function") + else: + preprocessing_function = lambda x: x + + if prms.data_augmentation: + + print('Using real-time data augmentation.') + train_datagen = ImageDataGenerator( + zoom_range=prms.zoom_range, + fill_mode=prms.fill_mode, + rotation_range = prms.rotation_range, + width_shift_range = prms.width_shift_range, + height_shift_range = prms.height_shift_range, + horizontal_flip=prms.horizontal_flip, + vertical_flip=prms.vertical_flip, + #contrast = prms.contrast if "contrast" in prms else None, + #truncate_quantile = prms.truncate_quantile, + #histeq_alpha=prms.histeq_alpha, + **norm_params) + else: + train_datagen = ImageDataGenerator(**norm_params) + ########################################## + # Everything + ########################################## + + val_datagen = ImageDataGenerator(**norm_params) + flowfromdir_params['classes'] = [os.path.basename(prms.data_everything.rstrip('/'))] + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_fliplr.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,:,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_flipud.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + + ########################################## + val_datagen.preprocessing_function = lambda x: x[...,::-1,::-1,:] + + datagen_val_output = val_datagen.flow_from_directory( + os.path.dirname(prms.data_everything.rstrip('/')), + shuffle=False, **flowfromdir_params) + + VALIDATION_STEPS = len(datagen_val_output) + pred_fn = "predictions_everything_fliplrud.csv" + with open(pred_fn, 'w+') as fh: + print("files", *["scores_%d"%ii for ii in range(2)], sep=',', file=fh) + for ii, batch in enumerate(datagen_val_output): + if ii> VALIDATION_STEPS: + break + yhat = model.predict_on_batch(batch[0]) + filenames = datagen_val_output.filenames[ii*prms.batch_size:(ii+1)*prms.batch_size] + for fnimg, yhat_ in zip(filenames, yhat): + print(fnimg, *yhat_, sep=',', file = fh) + ########################################## + # DONE + ########################################## + sys.exit(1) + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + #VALIDATION_STEPS = get_num_files(prms.data_val) // prms.batch_size + + ########################################## + # HOLDOUT + ########################################## + val_datagen = ImageDataGenerator(**norm_params) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout.csv", index=False) + ########################################## + # HOLDOUT FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_holdout, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_holdout_fliplr.csv", index=False) + ######################################### + # VAL + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test.csv", index=False) + ######################################### + # VAL FLIPPED + ########################################## + val_datagen = ImageDataGenerator(**norm_params, ) + val_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + VALIDATION_STEPS = int(np.ceil(len(datagen_val_output.filenames)/prms['batch_size'])) + print("validation steps", VALIDATION_STEPS) + + yhat = model.predict_generator(datagen_val_output, + steps=VALIDATION_STEPS, + verbose=1,) + + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({ "files":datagen_val_output.filenames, "label": datagen_val_output.classes}) + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_test_fliplr.csv", index=False) + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train.csv", index=False) + + ######################################### + SAMPLES_PER_EPOCH = len(datagen_train_output.filenames) + STEPS_PER_EPOCH = int(np.ceil(SAMPLES_PER_EPOCH / prms.batch_size)) + + print('='*50) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + train_datagen.preprocessing_function = lambda x: x[...,::-1,:] + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + shuffle=False, **flowfromdir_params) + + yhat = model.predict_generator(datagen_train_output, + steps=STEPS_PER_EPOCH, + verbose=1,) + + dfdict = {"scores_%d"%nn : yy for nn, yy in enumerate(yhat.T)} + dfdict.update({"files":datagen_train_output.filenames, "label": datagen_train_output.classes}) + ##ipdb.set_trace() + dfres = pd.DataFrame(dfdict) + dfres.to_csv("predictions_train_fliplr.csv", index=False) diff --git a/image_classifiers/e8e71fc090141d7c6fb334359152d295/trainer_inc_wire-no_el-no_upw-no_ups-2.py b/image_classifiers/e8e71fc090141d7c6fb334359152d295/trainer_inc_wire-no_el-no_upw-no_ups-2.py new file mode 100644 index 0000000..a2bc3f8 --- /dev/null +++ b/image_classifiers/e8e71fc090141d7c6fb334359152d295/trainer_inc_wire-no_el-no_upw-no_ups-2.py @@ -0,0 +1,224 @@ +from inception_short import get_model, get_num_files, get_class_weights +from keras.optimizers import Adam +from image import ImageDataGenerator +#from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping, ReduceLROnPlateau +from checkpoint_utils import CSVWallClockLogger +from shutil import copy2 + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + +import sys +import os +import yaml +import numpy as np +import keras +from hashlib import md5 +os.environ["PYTHONHASHSEED"]='0' +os.environ['KERAS_BACKEND'] = 'tensorflow' +os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' +os.environ["CUDA_VISIBLE_DEVICES"]="1" + +prms = AttrDict( + dropout=0.5, + base_trainable=False, + horizontal_flip = True, + vertical_flip = False, + zoom_range = [0.8, 1.2], + rotation_range = 30, + fill_mode='reflect', + ndense=0, + batch_size = 16, + init_epoch=0, + nb_epoch = 500, + data_augmentation = True, + rescale = 1, #2**-8, + #contrast = 0.9, + truncate_quantile = None,#0.001, + ztransform = True, + oversampling = False, + #sampling_factor = [1, 4], + seed=1, + width_shift_range = 0.125, + height_shift_range = 0.125, + class_mode = 'categorical', # 'binary', # + n_classes = 2, + final_activation = "softmax", # 'sigmoid', + lr = 1e-3, + samplewise_center = False, #True + target_side = 299, + #weights = None, + weightfile = None, #"checkpoints/6a1a17e4bcaabe458c145fd64dec0322/model.31-1.290145.hdf5", + #"checkpoints/6a1a17e4bcaabe458c145fd64dec0322/model.59-1.676424.hdf5", + data_train = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_train/', + data_val = '/data/UCSF_MAMMO/2018-02-png/each_class_4189_test/', + classes = ["normal", "wire"], + class_weights=[1, 1], + ReduceLROnPlateau = dict( + monitor='val_loss', + factor=1/2, + patience=32*2, + verbose=0, + mode='auto', epsilon=0.001, + cooldown=8, + min_lr=1e-12, + ), +) + + +paramhash = md5(str(prms).encode()).hexdigest() + +prms["target_size"] = [ prms.target_side ]*2 + +CHECKPOINT_DIR = "checkpoints/" + paramhash + "/" +os.makedirs(CHECKPOINT_DIR, exist_ok=True) +print("SAVING TO:\t%s" % CHECKPOINT_DIR) +# copy the script to the checkpoint directory +copy2(os.path.abspath(__file__), CHECKPOINT_DIR) +with open(os.path.join(CHECKPOINT_DIR, "checkpoint.info"), "w+") as outfh: + yaml.dump(dict(prms), outfh, default_flow_style=False) +prms["loss"] = '{}_crossentropy'.format( prms.class_mode ) + +CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, 'model.{epoch:02d}-{val_loss:2f}.hdf5') + +SAMPLES_PER_EPOCH = get_num_files(prms.data_train) +STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // prms.batch_size + +print('='*50) +print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) +print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) +print('='*50) +######################################### +checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=True, save_weights_only=False, mode='auto', period=1) + +csv_path = os.path.join(CHECKPOINT_DIR, "progresslog.csv") +csv_callback = CSVWallClockLogger(csv_path, separator=',', append=False) + + +callback_list = [checkpoint, csv_callback] + + +if ("ReduceLROnPlateau" in prms) and prms["ReduceLROnPlateau"]: + callback_list.append(ReduceLROnPlateau(**prms["ReduceLROnPlateau"])) + +######################################### +model = get_model(n_classes=prms.n_classes, + final_activation=prms.final_activation, + ndense=prms.ndense, + #weights = prms.weights, + dropout=prms.dropout, + base_trainable=prms.base_trainable) + + +#from keras.utils import plot_model +#plot_model(model, to_file='model.png') + +if __name__ == '__main__': + model.compile(optimizer=Adam(lr=prms.lr), loss=prms.loss, + metrics=['accuracy', #acc_0, acc_1,# acc_2, acc_3, acc_4 + ], + ) + ######################################### + if prms.weightfile: + print("loading weights from:\t%s" % prms.weightfile) + model.load_weights(prms.weightfile) + + ######################################### + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=prms.target_size, + batch_size=prms.batch_size, + class_mode=prms.class_mode, + classes=prms.classes, + seed=prms.seed) + norm_params = dict( + rescale=prms.rescale, + samplewise_center=prms.samplewise_center, + samplewise_std_normalization=prms.samplewise_center, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + z_transform = prms.ztransform, + ) + + def _ztransform(x): + return (x-np.mean(x)) / np.std(x) + + if 'preprocessing_function' in prms: + if prms.preprocessing_function=='ztransform': + preprocessing_function = _ztransform + elif prms.preprocessing_function=='m1p1': + preprocessing_function = lambda x: x/128.0 - 1 + else: + raise ValueError("unknown preprocessing_function") + else: + preprocessing_function = lambda x: x + + + if prms.data_augmentation: + + print('Using real-time data augmentation.') + train_datagen = ImageDataGenerator( + zoom_range=prms.zoom_range, + fill_mode=prms.fill_mode, + rotation_range = prms.rotation_range, + width_shift_range = prms.width_shift_range, + height_shift_range = prms.height_shift_range, + horizontal_flip=prms.horizontal_flip, + vertical_flip=prms.vertical_flip, + contrast = prms.contrast if "contrast" in prms else None, + truncate_quantile = prms.truncate_quantile, + #histeq_alpha=prms.histeq_alpha, + **norm_params) + else: + train_datagen = ImageDataGenerator(**norm_params) + + val_datagen = ImageDataGenerator(**norm_params) + + datagen_train_output = train_datagen.flow_from_directory( + prms.data_train, + stratify = prms.oversampling, + sampling_factor=prms.sampling_factor if prms.oversampling else None, + oversampling=prms.oversampling, + shuffle=True, **flowfromdir_params) + + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + + #VALIDATION_STEPS = get_num_files(prms.data_val) // prms.batch_size + VALIDATION_STEPS = np.ceil(len(datagen_val_output.filenames)/prms['batch_size']) + print("validation steps", VALIDATION_STEPS) + ######################################### + if prms.class_weights == 'auto': + class_weights = get_class_weights(datagen_val_output) + else: + class_weights = prms.class_weights + + model.fit_generator(datagen_train_output, + steps_per_epoch=STEPS_PER_EPOCH, + epochs=prms.nb_epoch, verbose=1, + validation_data=datagen_val_output, + validation_steps=VALIDATION_STEPS, + #class_weight='auto', + class_weight=class_weights, + callbacks=callback_list, + initial_epoch=prms.init_epoch) + + datagen_val_output = val_datagen.flow_from_directory( + prms.data_val, shuffle=False, **flowfromdir_params) + + print("""loss\t%.4f + accuracy\t%.4f\n""" % + tuple(model.evaluate_generator(datagen_val_output, + steps=VALIDATION_STEPS, + workers=1, + pickle_safe=True))) + + + #model.predict() diff --git a/image_classifiers/image.py b/image_classifiers/image.py new file mode 100644 index 0000000..fe44687 --- /dev/null +++ b/image_classifiers/image.py @@ -0,0 +1,2207 @@ +"""Fairly basic set of tools for real-time data augmentation on image data. +Can easily be extended to include new transformations, +new preprocessing methods, etc... +""" +from __future__ import absolute_import +from __future__ import print_function + +import sys +import numpy as np +import re +from scipy import linalg +import scipy.ndimage as ndi +from six.moves import range +import os +import threading +import warnings +import multiprocessing.pool +from functools import partial +from collections import Counter + +from keras import backend as K +from keras.utils.data_utils import Sequence + +from histeq import histeq, ztransform +try: + from PIL import ImageEnhance + from PIL import Image as pil_image +except ImportError: + pil_image = None + +if pil_image is not None: + _PIL_INTERPOLATION_METHODS = { + 'nearest': pil_image.NEAREST, + 'bilinear': pil_image.BILINEAR, + 'bicubic': pil_image.BICUBIC, + } + # These methods were only introduced in version 3.4.0 (2016). + if hasattr(pil_image, 'HAMMING'): + _PIL_INTERPOLATION_METHODS['hamming'] = pil_image.HAMMING + if hasattr(pil_image, 'BOX'): + _PIL_INTERPOLATION_METHODS['box'] = pil_image.BOX + # This method is new in version 1.1.3 (2013). + if hasattr(pil_image, 'LANCZOS'): + _PIL_INTERPOLATION_METHODS['lanczos'] = pil_image.LANCZOS + + +import cv2 + +_OPENCV_INTERPOLATION_METHODS = { + "nearest":cv2.INTER_NEAREST, + "bilinear":cv2.INTER_LINEAR, + "linear":cv2.INTER_LINEAR, + "area":cv2.INTER_AREA, + "bicubic":cv2.INTER_CUBIC, + "cubic":cv2.INTER_CUBIC, + "lanczos":cv2.INTER_LANCZOS4, + "lanczos4":cv2.INTER_LANCZOS4, +} + +import json +from croppad import crop_pad_center +from pycocotools.mask import encode, decode + + +def random_rotation(x, rg, row_axis=1, col_axis=2, channel_axis=0, + fill_mode='nearest', cval=0.): + """Performs a random rotation of a Numpy image tensor. + + # Arguments + x: Input tensor. Must be 3D. + rg: Rotation range, in degrees. + row_axis: Index of axis for rows in the input tensor. + col_axis: Index of axis for columns in the input tensor. + channel_axis: Index of axis for channels in the input tensor. + fill_mode: Points outside the boundaries of the input + are filled according to the given mode + (one of `{'constant', 'nearest', 'reflect', 'wrap'}`). + cval: Value used for points outside the boundaries + of the input if `mode='constant'`. + + # Returns + Rotated Numpy image tensor. + """ + theta = np.pi / 180 * np.random.uniform(-rg, rg) + rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0], + [np.sin(theta), np.cos(theta), 0], + [0, 0, 1]]) + + h, w = x.shape[row_axis], x.shape[col_axis] + transform_matrix = transform_matrix_offset_center(rotation_matrix, h, w) + x = apply_affine_transform(x, transform_matrix, channel_axis, fill_mode, cval) + return x + + +def random_shift(x, wrg, hrg, row_axis=1, col_axis=2, channel_axis=0, + fill_mode='nearest', cval=0.): + """Performs a random spatial shift of a Numpy image tensor. + + # Arguments + x: Input tensor. Must be 3D. + wrg: Width shift range, as a float fraction of the width. + hrg: Height shift range, as a float fraction of the height. + row_axis: Index of axis for rows in the input tensor. + col_axis: Index of axis for columns in the input tensor. + channel_axis: Index of axis for channels in the input tensor. + fill_mode: Points outside the boundaries of the input + are filled according to the given mode + (one of `{'constant', 'nearest', 'reflect', 'wrap'}`). + cval: Value used for points outside the boundaries + of the input if `mode='constant'`. + + # Returns + Shifted Numpy image tensor. + """ + h, w = x.shape[row_axis], x.shape[col_axis] + tx = np.random.uniform(-hrg, hrg) * h + ty = np.random.uniform(-wrg, wrg) * w + translation_matrix = np.array([[1, 0, tx], + [0, 1, ty], + [0, 0, 1]]) + + transform_matrix = translation_matrix # no need to do offset + x = apply_affine_transform(x, transform_matrix, channel_axis, fill_mode, cval) + return x + + +def random_shear(x, intensity, row_axis=1, col_axis=2, channel_axis=0, + fill_mode='nearest', cval=0.): + """Performs a random spatial shear of a Numpy image tensor. + + # Arguments + x: Input tensor. Must be 3D. + intensity: Transformation intensity. + row_axis: Index of axis for rows in the input tensor. + col_axis: Index of axis for columns in the input tensor. + channel_axis: Index of axis for channels in the input tensor. + fill_mode: Points outside the boundaries of the input + are filled according to the given mode + (one of `{'constant', 'nearest', 'reflect', 'wrap'}`). + cval: Value used for points outside the boundaries + of the input if `mode='constant'`. + + # Returns + Sheared Numpy image tensor. + """ + shear = np.random.uniform(-intensity, intensity) + shear_matrix = np.array([[1, -np.sin(shear), 0], + [0, np.cos(shear), 0], + [0, 0, 1]]) + + h, w = x.shape[row_axis], x.shape[col_axis] + transform_matrix = transform_matrix_offset_center(shear_matrix, h, w) + x = apply_affine_transform(x, transform_matrix, channel_axis, fill_mode, cval) + return x + + +def random_zoom(x, zoom_range, row_axis=1, col_axis=2, channel_axis=0, + fill_mode='nearest', cval=0.): + """Performs a random spatial zoom of a Numpy image tensor. + + # Arguments + x: Input tensor. Must be 3D. + zoom_range: Tuple of floats; zoom range for width and height. + row_axis: Index of axis for rows in the input tensor. + col_axis: Index of axis for columns in the input tensor. + channel_axis: Index of axis for channels in the input tensor. + fill_mode: Points outside the boundaries of the input + are filled according to the given mode + (one of `{'constant', 'nearest', 'reflect', 'wrap'}`). + cval: Value used for points outside the boundaries + of the input if `mode='constant'`. + + # Returns + Zoomed Numpy image tensor. + + # Raises + ValueError: if `zoom_range` isn't a tuple. + """ + if len(zoom_range) != 2: + raise ValueError('`zoom_range` should be a tuple or list of two floats. ' + 'Received arg: ', zoom_range) + + if zoom_range[0] == 1 and zoom_range[1] == 1: + zx, zy = 1, 1 + else: + zx, zy = np.random.uniform(zoom_range[0], zoom_range[1], 2) + zoom_matrix = np.array([[zx, 0, 0], + [0, zy, 0], + [0, 0, 1]]) + + h, w = x.shape[row_axis], x.shape[col_axis] + transform_matrix = transform_matrix_offset_center(zoom_matrix, h, w) + x = apply_affine_transform(x, transform_matrix, channel_axis, fill_mode, cval) + return x + + +def random_channel_shift(x, intensity, channel_axis=0): + x = np.rollaxis(x, channel_axis, 0) + min_x, max_x = np.min(x), np.max(x) + channel_images = [np.clip(x_channel + np.random.uniform(-intensity, intensity), min_x, max_x) + for x_channel in x] + x = np.stack(channel_images, axis=0) + x = np.rollaxis(x, 0, channel_axis + 1) + return x + + +def transform_matrix_offset_center(matrix, x, y): + o_x = float(x) / 2 + 0.5 + o_y = float(y) / 2 + 0.5 + offset_matrix = np.array([[1, 0, o_x], [0, 1, o_y], [0, 0, 1]]) + reset_matrix = np.array([[1, 0, -o_x], [0, 1, -o_y], [0, 0, 1]]) + transform_matrix = np.dot(np.dot(offset_matrix, matrix), reset_matrix) + return transform_matrix + + +def apply_affine_transform(x, + transform_matrix, + channel_axis=0, + fill_mode='nearest', + cval=0., + borderMode = cv2.BORDER_TRANSPARENT, + interp = cv2.INTER_NEAREST, + use_opencv=False): + """Apply the image transformation specified by a matrix. + + # Arguments + x: 2D numpy array, single image. + transform_matrix: Numpy array specifying the geometric transformation. + channel_axis: Index of axis for channels in the input tensor. + use_opencv: + fill_mode: Points outside the boundaries of the input + are filled according to the given mode + (one of `{'constant', 'nearest', 'reflect', 'wrap'}`). + cval: Value used for points outside the boundaries + of the input if `mode='constant'`. + borderMode: + cv2.BORDER_TRANSPARENT + cv2.BORDER_CONSTANT + BORDER_REPLICATE + BORDER_REFLECT + BORDER_REFLECT101 + BORDER_WRAP + interp: + cv2.INTER_NEAREST + cv2.INTER_LINEAR + cv2.INTER_AREA + cv2.INTER_CUBIC + cv2.INTER_LANCZOS4 + + # Returns + The transformed version of the input. + """ + final_affine_matrix = transform_matrix[:2, :2] + final_offset = transform_matrix[:2, 2] + + if use_opencv: + dsize=x.shape[:2] + init_shape = x.shape + #dest = np.ones_like(x) * cval + x = cv2.warpAffine(x, transform_matrix[:2,:], + dsize, + #dest, + borderValue=cval, + borderMode = borderMode, + flags=interp, + ) + if len(x.shape) < len(init_shape): + x = x[..., np.newaxis] + #x = dest + elif len(x.shape)>2 and channel_axis is not None: + x = np.rollaxis(x, channel_axis, 0) + channel_images = [ndi.interpolation.affine_transform( + x_channel, + final_affine_matrix, + final_offset, + order=0, + mode=fill_mode, + cval=cval) for x_channel in x] + + x = np.stack(channel_images, axis=0) + x = np.rollaxis(x, 0, channel_axis + 1) + else: + x = ndi.interpolation.affine_transform( + x, + final_affine_matrix, + final_offset, + order=0, + mode=fill_mode, + cval=cval) + return x + + +def flip_axis(x, axis): + x = np.asarray(x).swapaxes(axis, 0) + x = x[::-1, ...] + x = x.swapaxes(0, axis) + return x + + +def array_to_img(x, data_format=None, scale=True): + """Converts a 3D Numpy array to a PIL Image instance. + + # Arguments + x: Input Numpy array. + data_format: Image data format. + scale: Whether to rescale image values + to be within [0, 255]. + + # Returns + A PIL Image instance. + + # Raises + ImportError: if PIL is not available. + ValueError: if invalid `x` or `data_format` is passed. + """ + if pil_image is None: + raise ImportError('Could not import PIL.Image. ' + 'The use of `array_to_img` requires PIL.') + x = np.asarray(x, dtype=K.floatx()) + if x.ndim != 3: + raise ValueError('Expected image array to have rank 3 (single image). ' + 'Got array with shape:', x.shape) + + if data_format is None: + data_format = K.image_data_format() + if data_format not in {'channels_first', 'channels_last'}: + raise ValueError('Invalid data_format:', data_format) + + # Original Numpy array x has format (height, width, channel) + # or (channel, height, width) + # but target PIL image has format (width, height, channel) + if data_format == 'channels_first': + x = x.transpose(1, 2, 0) + if scale: + x = x + max(-np.min(x), 0) + x_max = np.max(x) + if x_max != 0: + x /= x_max + x *= 255 + if x.shape[2] == 3: + # RGB + return pil_image.fromarray(x.astype('uint8'), 'RGB') + elif x.shape[2] == 1: + # grayscale + return pil_image.fromarray(x[:, :, 0].astype('uint8'), 'L') + else: + raise ValueError('Unsupported channel number: ', x.shape[2]) + + +def img_to_array(img, data_format=None): + """Converts a PIL Image instance to a Numpy array. + + # Arguments + img: PIL Image instance. + data_format: Image data format. + + # Returns + A 3D Numpy array. + + # Raises + ValueError: if invalid `img` or `data_format` is passed. + """ + if data_format is None: + data_format = K.image_data_format() + if data_format not in {'channels_first', 'channels_last'}: + raise ValueError('Unknown data_format: ', data_format) + # Numpy array x has format (height, width, channel) + # or (channel, height, width) + # but original PIL image has format (width, height, channel) + x = np.asarray(img, dtype=K.floatx()) + if len(x.shape) == 3: + if data_format == 'channels_first': + x = x.transpose(2, 0, 1) + elif len(x.shape) == 2: + if data_format == 'channels_first': + x = x.reshape((1, x.shape[0], x.shape[1])) + else: + x = x.reshape((x.shape[0], x.shape[1], 1)) + else: + raise ValueError('Unsupported image shape: ', x.shape) + return x + + +def load_img(path, grayscale=False, color_mode='rgb', target_size=None, + interpolation='nearest', driver='opencv'): + """Loads an image using a defined module + # Arguments + path: Path to image file. + color_mode: One of "grayscale", "rbg", "rgba", "bgr", "bgra". Default: "rgb". + The desired image format. + target_size: Either `None` (default to original size) + or tuple of ints `(img_height, img_width)`. + interpolation: Interpolation method used to resample the image if the + target size is different from that of the loaded image. + Supported methods are "nearest", "bilinear", and "bicubic". + Driver-dependent options are "lanczos", "area", "box" and + "hamming". For details, refer to documentation of `load_img_pil()` + and `load_img_opencv()`. By default, "nearest" is used. + """ + if driver.lower() in ('cv2','opencv'): + img = load_img_opencv(path, grayscale=grayscale, color_mode=color_mode, + target_size=target_size, interpolation=interpolation) + elif driver.lower() in ('pil', 'pillow'): + img = load_img_pil(path, grayscale=grayscale, color_mode=color_mode, + target_size=target_size, interpolation=interpolation) + return img + + +def load_img_opencv(path, grayscale=False, color_mode='rgb', target_size=None, + interpolation='nearest'): + """Loads an image using opencv format. + # Arguments + path: Path to image file. + color_mode: One of "grayscale", "rbg", "rgba", "bgr", "bgra". Default: "rgb". + The desired image format. + target_size: Either `None` (default to original size) + or tuple of ints `(img_height, img_width)`. + interpolation: Interpolation method used to resample the image if the + target size is different from that of the loaded image. + Supported methods are "nearest", "bilinear", "bicubic", "lanczos", "area". + By default, "nearest" is used. + # Returns + A numpy array instance. + # Raises + ImportError: if PIL is not available. + ValueError: if interpolation method is not supported. + """ + if grayscale is True: + warnings.warn('grayscale is deprecated. Please use ' + 'color_mode = "grayscale"') + color_mode = 'grayscale' + + img = cv2.imread(path, cv2.IMREAD_ANYDEPTH) + + if len(img.shape)==2: + img_mode = 'grayscale' + elif len(img.shape) == 3: + if img.shape[-1]==3: + img_mode = 'bgr' + elif img.shape[-1]==4: + img_mode = 'bgra' + + if img_mode != color_mode: + if color_mode.startswith('gray'): + if img_mode == 'bgr': + img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + elif img_mode == 'bgra': + img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY) + elif color_mode == 'rgba': + if img_mode == 'bgr': + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA) + elif img_mode == 'grayscale': + img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGBA) + elif color_mode == 'rgb': + if img_mode == 'bgr': + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + elif img_mode == 'bgra': + img = cv2.cvtColor(img, cv2.COLOR_BGRA2RGB) + elif img_mode == 'grayscale': + img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) + else: + raise ValueError('color_mode must be "grayscale", "rbg", or "rgba"') + + if target_size is not None: + width_height_tuple = (target_size[1], target_size[0]) + if img.shape[:2][::-1] != width_height_tuple: + if interpolation not in _PIL_INTERPOLATION_METHODS: + raise ValueError( + 'Invalid interpolation method {} specified. Supported ' + 'methods are {}'.format( + interpolation, + ", ".join(_OPENCV_INTERPOLATION_METHODS.keys()))) + resample = _OPENCV_INTERPOLATION_METHODS[interpolation] + img = cv2.resize(img, width_height_tuple, resample) + return img + + +def load_img_pil(path, grayscale=False, color_mode='rgb', target_size=None, + interpolation='nearest'): + """Loads an image into PIL format. + # Arguments + path: Path to image file. + color_mode: One of "grayscale", "rbg", "rgba". Default: "rgb". + The desired image format. + target_size: Either `None` (default to original size) + or tuple of ints `(img_height, img_width)`. + interpolation: Interpolation method used to resample the image if the + target size is different from that of the loaded image. + Supported methods are "nearest", "bilinear", and "bicubic". + If PIL version 1.1.3 or newer is installed, "lanczos" is also + supported. If PIL version 3.4.0 or newer is installed, "box" and + "hamming" are also supported. By default, "nearest" is used. + # Returns + A PIL Image instance. + # Raises + ImportError: if PIL is not available. + ValueError: if interpolation method is not supported. + """ + if grayscale is True: + warnings.warn('grayscale is deprecated. Please use ' + 'color_mode = "grayscale"') + color_mode = 'grayscale' + if pil_image is None: + raise ImportError('Could not import PIL.Image. ' + 'The use of `array_to_img` requires PIL.') + img = pil_image.open(path) + + if color_mode == 'grayscale': + if img.mode not in ('L', 'I;16'): + img = img.convert('L') + elif color_mode == 'rgba': + if img.mode != 'RGBA': + img = img.convert('RGBA') + elif color_mode == 'rgb': + if img.mode != 'RGB': + if img.mode not in ('I;16'): + img = img.convert('RGB') + else: + img = np.asarray(img) + img = img * (255.0/ max(1.0, img.max())) + img = np.stack([img.astype('uint8')]*3, axis=-1) + img = array_to_img(img) + else: + raise ValueError('color_mode must be "grayscale", "rbg", or "rgba"') + if target_size is not None: + width_height_tuple = (target_size[1], target_size[0]) + if img.size != width_height_tuple: + if interpolation not in _PIL_INTERPOLATION_METHODS: + raise ValueError( + 'Invalid interpolation method {} specified. Supported ' + 'methods are {}'.format( + interpolation, + ", ".join(_PIL_INTERPOLATION_METHODS.keys()))) + resample = _PIL_INTERPOLATION_METHODS[interpolation] + img = img.resize(width_height_tuple, resample) + return img + + +def array_to_img(x, data_format=None, scale=True): + """Converts a 3D Numpy array to a PIL Image instance. + # Arguments + x: Input Numpy array. + data_format: Image data format. + either "channels_first" or "channels_last". + scale: Whether to rescale image values + to be within `[0, 255]`. + # Returns + A PIL Image instance. + # Raises + ImportError: if PIL is not available. + ValueError: if invalid `x` or `data_format` is passed. + """ + if pil_image is None: + raise ImportError('Could not import PIL.Image. ' + 'The use of `array_to_img` requires PIL.') + x = np.asarray(x, dtype=K.floatx()) + if x.ndim != 3: + raise ValueError('Expected image array to have rank 3 (single image). ' + 'Got array with shape:', x.shape) + + if data_format is None: + data_format = K.image_data_format() + if data_format not in {'channels_first', 'channels_last'}: + raise ValueError('Invalid data_format:', data_format) + + # Original Numpy array x has format (height, width, channel) + # or (channel, height, width) + # but target PIL image has format (width, height, channel) + if data_format == 'channels_first': + x = x.transpose(1, 2, 0) + if scale: + x = x + max(-np.min(x), 0) + x_max = np.max(x) + if x_max != 0: + x /= x_max + x *= 255 + if x.shape[2] == 4: + # RGBA + return pil_image.fromarray(x.astype('uint8'), 'RGBA') + elif x.shape[2] == 3: + # RGB + return pil_image.fromarray(x.astype('uint8'), 'RGB') + elif x.shape[2] == 1: + # grayscale + if np.all(x < 255): + return pil_image.fromarray(x[:, :, 0].astype('uint8'), 'L') + else: + return pil_image.fromarray(x[:, :, 0].astype('uint16'), 'I;16') + else: + raise ValueError('Unsupported channel number: ', x.shape[2]) + + +def list_pictures(directory, ext='jpg|jpeg|bmp|png|ppm'): + return [os.path.join(root, f) + for root, _, files in os.walk(directory) for f in files + if re.match(r'([\w]+\.(?:' + ext + '))', f)] + + +class ImageDataGenerator(object): + """Generate minibatches of image data with real-time data augmentation. + + # Arguments + featurewise_center: set input mean to 0 over the dataset. + samplewise_center: set each sample mean to 0. + featurewise_std_normalization: divide inputs by std of the dataset. + samplewise_std_normalization: divide each input by its std. + zca_whitening: apply ZCA whitening. + zca_epsilon: epsilon for ZCA whitening. Default is 1e-6. + rotation_range: degrees (0 to 180). + width_shift_range: fraction of total width. + height_shift_range: fraction of total height. + shear_range: shear intensity (shear angle in radians). + zoom_range: amount of zoom. if scalar z, zoom will be randomly picked + in the range [1-z, 1+z]. A sequence of two can be passed instead + to select this range. + channel_shift_range: shift range for each channel. + fill_mode: points outside the boundaries are filled according to the + given mode ('constant', 'nearest', 'reflect' or 'wrap'). Default + is 'nearest'. + cval: value used for points outside the boundaries when fill_mode is + 'constant'. Default is 0. + horizontal_flip: whether to randomly flip images horizontally. + vertical_flip: whether to randomly flip images vertically. + rescale: rescaling factor. If None or 0, no rescaling is applied, + otherwise we multiply the data by the value provided. This is + applied after the `preprocessing_function` (if any provided) + but before any other transformation. + preprocessing_function: function that will be implied on each input. + The function will run before any other modification on it. + The function should take one argument: + one image (Numpy tensor with rank 3), + and should output a Numpy tensor with the same shape. + data_format: 'channels_first' or 'channels_last'. In 'channels_first' mode, the channels dimension + (the depth) is at index 1, in 'channels_last' mode it is at index 3. + It defaults to the `image_data_format` value found in your + Keras config file at `~/.keras/keras.json`. + If you never set it, then it will be "channels_last". + """ + + def __init__(self, + featurewise_center=False, + samplewise_center=False, + featurewise_std_normalization=False, + samplewise_std_normalization=False, + zca_whitening=False, + zca_epsilon=1e-6, + rotation_range=0., + width_shift_range=0., + height_shift_range=0., + shear_range=0., + zoom_range=0., + channel_shift_range=0., + fill_mode='nearest', + cval=0., + horizontal_flip=False, + vertical_flip=False, + rescale=None, + preprocessing_function=None, + postprocessing_function=None, + histeq_alpha = False, + contrast_exp = 1.2, + contrast = None, + truncate_quantile = None, + z_transform = None, + #noise=None + data_format=None): + if data_format is None: + data_format = K.image_data_format() + self.featurewise_center = featurewise_center + self.samplewise_center = samplewise_center + self.featurewise_std_normalization = featurewise_std_normalization + self.samplewise_std_normalization = samplewise_std_normalization + self.zca_whitening = zca_whitening + self.zca_epsilon = zca_epsilon + self.rotation_range = rotation_range + self.width_shift_range = width_shift_range + self.height_shift_range = height_shift_range + self.shear_range = shear_range + self.zoom_range = zoom_range + self.channel_shift_range = channel_shift_range + self.fill_mode = fill_mode + self.cval = cval + self.horizontal_flip = horizontal_flip + self.vertical_flip = vertical_flip + self.rescale = rescale + + self.histeq_alpha = histeq_alpha + self.contrast = contrast + self.contrast_exp = contrast_exp + self.ztransform = z_transform + self.truncate_quantile = truncate_quantile + + #self.noise_specs = {} if noise is None else noise + #self.intensity_gain = intensity_gain + + self.preprocessing_function = preprocessing_function + self.postprocessing_function = postprocessing_function + + if data_format not in {'channels_last', 'channels_first'}: + raise ValueError('`data_format` should be `"channels_last"` (channel after row and ' + 'column) or `"channels_first"` (channel before row and column). ' + 'Received arg: ', data_format) + self.data_format = data_format + if data_format == 'channels_first': + self.channel_axis = 1 + self.row_axis = 2 + self.col_axis = 3 + if data_format == 'channels_last': + self.channel_axis = 3 + self.row_axis = 1 + self.col_axis = 2 + + self.mean = None + self.std = None + self.principal_components = None + + if np.isscalar(zoom_range): + self.zoom_range = [1 - zoom_range, 1 + zoom_range] + elif len(zoom_range) == 2: + self.zoom_range = [zoom_range[0], zoom_range[1]] + else: + raise ValueError('`zoom_range` should be a float or ' + 'a tuple or list of two floats. ' + 'Received arg: ', zoom_range) + + def flow(self, x, y=None, batch_size=32, shuffle=True, seed=None, + save_to_dir=None, save_prefix='', save_format='png', color_mode='rgb'): + return NumpyArrayIterator( + x, y, self, + batch_size=batch_size, + shuffle=shuffle, + seed=seed, + data_format=self.data_format, + save_to_dir=save_to_dir, + save_prefix=save_prefix, + save_format=save_format, + postprocessing_function=self.postprocessing_function, + color_mode=color_mode) + + def flow_from_directory(self, directory, + target_size=(256, 256), color_mode='rgb', + classes=None, class_mode='categorical', + batch_size=32, shuffle=True, seed=None, + save_to_dir=None, + save_prefix='', + save_format='png', + follow_links=False, + stratify=None, + oversampling=False, + subsample_factor= None, + subsample_num = None, + ): + return DirectoryIterator( + directory, self, + target_size=target_size, color_mode=color_mode, + classes=classes, class_mode=class_mode, + data_format=self.data_format, + batch_size=batch_size, shuffle=shuffle, seed=seed, + save_to_dir=save_to_dir, + save_prefix=save_prefix, + save_format=save_format, + postprocessing_function=self.postprocessing_function, + follow_links=follow_links, + stratify=stratify, + oversampling=oversampling, + subsample_factor=subsample_factor, + subsample_num=subsample_num, + ) + + + def flow_patches(self, fn_img, fn_pnt, + point_sampler, + target_size=(256, 256), + color_mode='grayscale', + batch_size=4, + patches_per_image=1, + shuffle=True, + seed=0, + dtype='uint16', + fill_mode = 'reflect', + label_freq={1:5, 2:10}, + postprocessing_functions = [None, None], + output_indices=False, + ): + + return PatchIterator(fn_img, fn_pnt, + point_sampler, + image_data_generator = self, + batch_size=batch_size, + patches_per_image=patches_per_image, + shuffle=shuffle, + color_mode=color_mode, + seed=seed, + patch_size = target_size, + dtype=dtype, + mode = self.fill_mode if fill_mode is None else fill_mode, + label_freq=label_freq, + augmentation=True, + postprocessing_functions=postprocessing_functions, + output_indices=output_indices, + ) + + def flow_memmap(self, + root_dir, csv_file, + classes = ["Control", "Case",], + binary=True, + postprocessing_functions=None, + nsamples = None, + batch_size = 1, + shuffle = False, + seed = None, + postprocessing_function=None, + stratify=None, + oversampling=False, + subsample_factor=None, + subsample_num=None, + batch_rate=1, + dtype = K.floatx(), + color_mode=None, + label_col = "label", + filename_col = "filename", + encode_label=None, + ): + return MemMapIterator(root_dir, csv_file, + classes = classes, + image_data_generator = self, + data_format = self.data_format, + binary=binary, + transform=postprocessing_functions, + nsamples = None, + batch_size = batch_size, + shuffle = shuffle, + seed = seed, + stratify=stratify, + oversampling=oversampling, + subsample_factor=subsample_factor, + subsample_num=subsample_num, + batch_rate=batch_rate, + dtype = dtype, + color_mode=color_mode, + label_col = label_col, + filename_col = filename_col, + encode_label=encode_label, + ) + def standardize(self, x): + """Apply the normalization configuration to a batch of inputs. + + # Arguments + x: batch of inputs to be normalized. + + # Returns + The inputs, normalized. + """ + if self.histeq_alpha: + alpha=np.random.random() + if hasattr(self.histeq_alpha, '__len__'): + #print("self.histeq_alpha,", self.histeq_alpha,) + for ii,aa in enumerate(self.histeq_alpha): + if aa: + x[:,:,ii] = histeq(x[:,:,ii], bitdepth=16, mask=None, alpha=alpha) + else: + x = histeq(x, bitdepth=16, mask=None, alpha=alpha) + if self.ztransform: + mask = x>0 + mask &= x0) * max(self.class_size.values()) + elif (subsample_factor is not None) or (subsample_num is not None): + if subsample_num is None: + self.final_num = int(self.n/subsample_factor) + else: + print("subsample_num", subsample_num) + self.final_num = subsample_num + self.orig_index_array = np.random.randint(0, self.n, size=self.final_num) + else: + self.orig_index_array = np.arange(self.n) + + def _prep_stratified(self): + self.uniq_classes = np.unique(self.stratify) + #self.class_size = np.bincount(self.stratify) + self.class_size = Counter(self.stratify) + + self.class_inds = {} + for cc in self.uniq_classes: + mask = np.asarray(self.stratify) == cc + self.class_inds[cc] = np.where(mask)[0] + + #ex_per_class = max(self.class_size) + ex_per_class = max(self.class_size.values()) + self.orig_index_array = [] + #for cc,ss in enumerate(self.class_size): + for cc in self.uniq_classes: + ss = self.class_size[cc] + if ss==0: + continue + self.orig_index_array.append( + np.random.choice(self.class_inds[cc], + size=ex_per_class, + replace=ss= len(self): + raise ValueError('Asked to retrieve element {idx}, ' + 'but the Sequence ' + 'has length {length}'.format(idx=idx, + length=len(self))) + if self.seed is not None: + np.random.seed(self.seed + self.total_batches_seen) + self.total_batches_seen += 1 + if self.index_array is None: + self._set_index_array() + _batch_size = self.batch_size // self.batch_rate + index_array = self.index_array[_batch_size * idx: + _batch_size * (idx + 1)] + return self._get_batches_of_transformed_samples(index_array) + + def __len__(self): + if hasattr(self, "batch_rate"): + _batch_size = self.batch_size // self.batch_rate + else: + _batch_size = self.batch_size + return int(np.ceil(self.n / float(_batch_size))) + + def on_epoch_end(self): + self._set_index_array() + + def reset(self): + self.batch_index = 0 + + def _flow_index(self): + # Ensure self.batch_index is 0. + self.reset() + if hasattr(self, "batch_rate"): + _batch_size = self.batch_size // self.batch_rate + else: + _batch_size = self.batch_size + + while 1: + if self.seed is not None: + np.random.seed(self.seed + self.total_batches_seen) + if self.batch_index == 0: + self._set_index_array() + + self.batch_index = self.total_batches_seen % self.__len__() + current_index = (self.batch_index * _batch_size) % self.final_num + self.total_batches_seen += 1 + yield self.index_array[current_index: + current_index + _batch_size] + + def __iter__(self): + # Needed if we want to do something like: + # for x, y in data_gen.flow(...): + return self + + def __next__(self, *args, **kwargs): + return self.next(*args, **kwargs) + + +class NumpyArrayIterator(Iterator): + """Iterator yielding data from a Numpy array. + + # Arguments + x: Numpy array of input data. + y: Numpy array of targets data. + image_data_generator: Instance of `ImageDataGenerator` + to use for random transformations and normalization. + batch_size: Integer, size of a batch. + shuffle: Boolean, whether to shuffle the data between epochs. + seed: Random seed for data shuffling. + data_format: String, one of `channels_first`, `channels_last`. + save_to_dir: Optional directory where to save the pictures + being yielded, in a viewable format. This is useful + for visualizing the random transformations being + applied, for debugging purposes. + save_prefix: String prefix to use for saving sample + images (if `save_to_dir` is set). + save_format: Format to use for saving sample images + (if `save_to_dir` is set). + """ + + def __init__(self, x, y, image_data_generator, + batch_size=32, shuffle=False, seed=None, + data_format=None, + save_to_dir=None, save_prefix='', save_format='png', + postprocessing_function=None, + color_mode=None, + stratify=None, + oversampling=True + ): + channels_axis = 3 if data_format == 'channels_last' else 1 + self.channels_axis = channels_axis + if y is not None and len(x) != len(y): + raise ValueError('X (images tensor) and y (labels) ' + 'should have the same length. ' + 'Found: X.shape = %s, y.shape = %s' % + (np.asarray(x).shape, np.asarray(y).shape)) + + if data_format is None: + data_format = K.image_data_format() + self.x = np.asarray(x, dtype=K.floatx()) + + if self.x.ndim != 4: + warnings.warn('Input data in `NumpyArrayIterator` ' + 'should have rank 4. You passed an array ' + 'with shape\t%s' % str(self.x.shape)) + else: + if self.x.shape[channels_axis] not in {1, 3, 4}: + warnings.warn('NumpyArrayIterator is set to use the ' + 'data format convention "' + data_format + '" ' + '(channels on axis ' + str(channels_axis) + '), i.e. expected ' + 'either 1, 3 or 4 channels on axis ' + str(channels_axis) + '. ' + 'However, it was passed an array with shape ' + str(self.x.shape) + + ' (' + str(self.x.shape[channels_axis]) + ' channels).') + if y is not None: + self.y = np.asarray(y) + else: + self.y = None + self.image_data_generator = image_data_generator + self.data_format = data_format + self.save_to_dir = save_to_dir + self.save_prefix = save_prefix + self.save_format = save_format + self.color_mode=color_mode + super(NumpyArrayIterator, self).__init__(x.shape[0], batch_size, shuffle, seed, + stratify=stratify, oversampling=oversampling, + postprocessing_function=postprocessing_function) + print("self.color_mode", self.color_mode) + + + def _get_batches_of_transformed_samples(self, index_array): + print("self.batch_index", self.batch_index,) + print("==", index_array) + batch_x = np.zeros(tuple([len(index_array)] + list(self.x.shape)[1:]), + dtype=K.floatx()) + if len(batch_x.shape)==3: + batch_x = batch_x.reshape(batch_x.shape + (1,)) + for i, j in enumerate(index_array): + x = self.x[j] + if len(x.shape)==2: + x = x.reshape(x.shape + (1,)) + x = self.image_data_generator.random_transform(x.astype(K.floatx())) + x = self.image_data_generator.standardize(x) + batch_x[i] = x + if self.save_to_dir: + for i, j in enumerate(index_array): + img = array_to_img(batch_x[i], self.data_format, scale=True) + fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix, + index=j, + hash=np.random.randint(1e4), + format=self.save_format) + img.save(os.path.join(self.save_to_dir, fname)) + if self.color_mode in (3,'rgb'): + if len(batch_x.shape)==3: + batch_x = np.stack([ batch_x ]*3, axis=-1) + if batch_x.shape[self.channels_axis]==1: + batch_x = np.concatenate([ batch_x ]*3, axis=3) + #print("batch_x", batch_x.shape) + #raise Exception("test!!!") + if self.postprocessing_function is not None: + batch_x = self.postprocessing_function(batch_x) + + if self.y is None: + return batch_x + batch_y = self.y[index_array] + return batch_x, batch_y + + def next(self): + """For python 2.x. + + # Returns + The next batch. + """ + # Keeps under lock only the mechanism which advances + # the indexing of each batch. + with self.lock: + index_array = next(self.index_generator) + # The transformation of images is not under thread lock + # so it can be done in parallel + return self._get_batches_of_transformed_samples(index_array) + + +def _count_valid_files_in_directory(directory, white_list_formats, follow_links): + """Count files with extension in `white_list_formats` contained in a directory. + + # Arguments + directory: absolute path to the directory containing files to be counted + white_list_formats: set of strings containing allowed extensions for + the files to be counted. + + # Returns + the count of files with extension in `white_list_formats` contained in + the directory. + """ + def _recursive_list(subpath): + return sorted(os.walk(subpath, followlinks=follow_links), key=lambda tpl: tpl[0]) + + samples = 0 + for root, _, files in _recursive_list(directory): + for fname in files: + is_valid = False + for extension in white_list_formats: + if fname.lower().endswith('.' + extension): + is_valid = True + break + if is_valid: + samples += 1 + return samples + + +def _list_valid_filenames_in_directory(directory, white_list_formats, + class_indices, follow_links): + """List paths of files in `subdir` relative from `directory` whose extensions are in `white_list_formats`. + + # Arguments + directory: absolute path to a directory containing the files to list. + The directory name is used as class label and must be a key of `class_indices`. + white_list_formats: set of strings containing allowed extensions for + the files to be counted. + class_indices: dictionary mapping a class name to its index. + + # Returns + classes: a list of class indices + filenames: the path of valid files in `directory`, relative from + `directory`'s parent (e.g., if `directory` is "dataset/class1", + the filenames will be ["class1/file1.jpg", "class1/file2.jpg", ...]). + """ + def _recursive_list(subpath): + return sorted(os.walk(subpath, followlinks=follow_links), key=lambda tpl: tpl[0]) + + classes = [] + filenames = [] + subdir = os.path.basename(directory) + basedir = os.path.dirname(directory) + for root, _, files in _recursive_list(directory): + for fname in sorted(files): + is_valid = False + for extension in white_list_formats: + if fname.lower().endswith('.' + extension): + is_valid = True + break + if is_valid: + classes.append(class_indices[subdir]) + # add filename relative to directory + absolute_path = os.path.join(root, fname) + filenames.append(os.path.relpath(absolute_path, basedir)) + return classes, filenames + + +class DirectoryIterator(Iterator): + """Iterator capable of reading images from a directory on disk. + + # Arguments + directory: Path to the directory to read images from. + Each subdirectory in this directory will be + considered to contain images from one class, + or alternatively you could specify class subdirectories + via the `classes` argument. + image_data_generator: Instance of `ImageDataGenerator` + to use for random transformations and normalization. + target_size: tuple of integers, dimensions to resize input images to. + color_mode: One of `"rgb"`, `"grayscale"`. Color mode to read images. + classes: Optional list of strings, names of subdirectories + containing images from each class (e.g. `["dogs", "cats"]`). + It will be computed automatically if not set. + class_mode: Mode for yielding the targets: + `"binary"`: binary targets (if there are only two classes), + `"categorical"`: categorical targets, + `"sparse"`: integer targets, + `"input"`: targets are images identical to input images (mainly + used to work with autoencoders), + `None`: no targets get yielded (only input images are yielded). + batch_size: Integer, size of a batch. + shuffle: Boolean, whether to shuffle the data between epochs. + seed: Random seed for data shuffling. + data_format: String, one of `channels_first`, `channels_last`. + save_to_dir: Optional directory where to save the pictures + being yielded, in a viewable format. This is useful + for visualizing the random transformations being + applied, for debugging purposes. + save_prefix: String prefix to use for saving sample + images (if `save_to_dir` is set). + save_format: Format to use for saving sample images + (if `save_to_dir` is set). + """ + + def __init__(self, directory, image_data_generator, + target_size=(256, 256), color_mode='rgb', + classes=None, class_mode='categorical', + batch_size=32, shuffle=True, seed=None, + data_format=None, + save_to_dir=None, save_prefix='', save_format='png', + postprocessing_function=None, + follow_links=False, + stratify=None, oversampling=True, + subsample_factor= None, + subsample_num = None, + output_filenames=None, + ): + + self.output_filenames=output_filenames + #self.postprocessing_function = postprocessing_function + if data_format is None: + data_format = K.image_data_format() + self.directory = directory + self.image_data_generator = image_data_generator + self.target_size = tuple(target_size) + if color_mode not in {'rgb', 'grayscale'}: + raise ValueError('Invalid color mode:', color_mode, + '; expected "rgb" or "grayscale".') + self.color_mode = color_mode + self.data_format = data_format + if self.color_mode == 'rgb': + if self.data_format == 'channels_last': + self.image_shape = self.target_size + (3,) + else: + self.image_shape = (3,) + self.target_size + else: + if self.data_format == 'channels_last': + self.image_shape = self.target_size + (1,) + else: + self.image_shape = (1,) + self.target_size + self.classes = classes + if class_mode not in {'categorical', 'binary', 'sparse', + 'input', None}: + raise ValueError('Invalid class_mode:', class_mode, + '; expected one of "categorical", ' + '"binary", "sparse", "input"' + ' or None.') + self.class_mode = class_mode + self.save_to_dir = save_to_dir + self.save_prefix = save_prefix + self.save_format = save_format + + white_list_formats = {'png', 'jpg', 'jpeg', 'bmp', 'ppm'} + + # first, count the number of samples and classes + self.samples = 0 + + if not classes: + classes = [] + for subdir in sorted(os.listdir(directory)): + if os.path.isdir(os.path.join(directory, subdir)): + classes.append(subdir) + self.num_class = len(classes) + self.class_indices = dict(zip(classes, range(len(classes)))) + + pool = multiprocessing.pool.ThreadPool() + function_partial = partial(_count_valid_files_in_directory, + white_list_formats=white_list_formats, + follow_links=follow_links) + self.samples = sum(pool.map(function_partial, + (os.path.join(directory, subdir) + for subdir in classes))) + + print('Found %d images belonging to %d classes.' % (self.samples, self.num_class)) + + # second, build an index of the images in the different class subfolders + results = [] + + self.filenames = [] + self.classes = np.zeros((self.samples,), dtype='int32') + i = 0 + for dirpath in (os.path.join(directory, subdir) for subdir in classes): + results.append(pool.apply_async(_list_valid_filenames_in_directory, + (dirpath, white_list_formats, + self.class_indices, follow_links))) + for res in results: + classes, filenames = res.get() + self.classes[i:i + len(classes)] = classes + self.filenames += filenames + i += len(classes) + pool.close() + pool.join() + super(DirectoryIterator, self).__init__(self.samples, batch_size, shuffle, seed, + stratify=self.classes if stratify else None, + oversampling=oversampling, + subsample_factor=subsample_factor, + subsample_num=subsample_num, + postprocessing_function=postprocessing_function) + + def _get_batches_of_transformed_samples(self, index_array): + batch_x = np.zeros((len(index_array),) + self.image_shape, dtype=K.floatx()) + batch_fn = [] + grayscale = self.color_mode == 'grayscale' + # build batch of image data + for i, j in enumerate(index_array): + fname = self.filenames[j] + batch_fn.append(fname) + + img = load_img(os.path.join(self.directory, fname), + grayscale=grayscale, + target_size=self.target_size) + x = img_to_array(img, data_format=self.data_format) + + x = self.image_data_generator.random_transform(x) + x = self.image_data_generator.standardize(x) + batch_x[i] = x + if self.postprocessing_function: + batch_x = self.postprocessing_function(batch_x) + # optionally save augmented images to disk for debugging purposes + if self.save_to_dir: + for i, j in enumerate(index_array): + img = array_to_img(batch_x[i], self.data_format, scale=True) + fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix, + index=j, + hash=np.random.randint(1e4), + format=self.save_format) + img.save(os.path.join(self.save_to_dir, fname)) + # build batch of labels + if self.class_mode == 'input': + batch_y = batch_x.copy() + elif self.class_mode == 'sparse': + batch_y = self.classes[index_array] + elif self.class_mode == 'binary': + batch_y = self.classes[index_array].astype(K.floatx()) + elif self.class_mode == 'categorical': + batch_y = np.zeros((len(batch_x), self.num_class), dtype=K.floatx()) + for i, label in enumerate(self.classes[index_array]): + batch_y[i, label] = 1. + else: + return batch_x + if self.output_filenames: + return batch_x, batch_y, batch_fn + return batch_x, batch_y + + def next(self): + """For python 2.x. + + # Returns + The next batch. + """ + with self.lock: + index_array = next(self.index_generator) + # The transformation of images is not under thread lock + # so it can be done in parallel + return self._get_batches_of_transformed_samples(index_array) + +# coding: utf-8 +#from keras.utils.data_utils import Sequence +#import numpy as np +from numpy.lib.format import open_memmap +def get_slice(center, size=(256,256), + target_size = (None, None), + reflect = False, + ): + size = np.asarray(size) + xy = np.asarray(center) - size//2 + end = xy + size + + margins_max = [] + margins_min = [] + slice_ = [] + for s_, e_, t_, sz in zip(xy, end, target_size, size): + if t_: + m_e = max(0, -(t_ - e_ )) + e_ = min(e_, t_) + else: + m_e = None + m_s = max(0, -s_) + s_ = max(s_,0) + if reflect and (m_s>0) or (m_e>0): + #print("before", s_,e_, m_s, m_e) + if (e_==0) and m_e > sz//2: + m_e, s_ = t_-s_, t_ - m_e + if (s_==0) and (m_e> e_): + e_, m_s = m_s, e_ + #print("after", s_,e_, m_s, m_e) + margins_max.append(m_e) + margins_min.append(m_s) + slice_.append(slice(s_, e_)) + return slice_, list(zip(margins_min, margins_max)) + + +def pad_patch(img, slc, padseq): + """if no padding required, returns a slice (pointer); + otherwise returns a padded copy of a slice + + INPUT: + - target_size [ width, height ] + """ + if any((s > 0 for s in padseq[0])) | any((s > 0 for s in padseq[1])): + patch = np.pad(img[slc], padseq, mode='constant') + else: + patch = img[slc] + return patch + +class PatchIterator(Iterator): + """ + point_sampler(filename, label=2) + """ + def __init__(self, fn_img, fn_pnt, + point_sampler, + image_data_generator = None, + batch_size = 4, + shuffle=True, + seed=0, + patch_size = (512,512), + dtype='uint16', + mode = 'reflect', + label_freq={1:5, 2:10}, + augmentation=None, + postprocessing_functions = [None, None], + color_mode = None, + output_indices = False, + patches_per_image = 1, + ): + self.fn_img = fn_img + self.fn_pnt = fn_pnt + assert batch_size % patches_per_image == 0, ( + "batch_size must be multiple of patches_per_image") + self.patches_per_image = patches_per_image + self.imgs_per_batch = batch_size // self.patches_per_image + assert len(fn_img) == len(fn_pnt) + assert len(fn_img) >0 + print("%d images supplied" % len(fn_img)) + self.point_sampler = point_sampler + nsamples = len(self.fn_img) + self.mode = mode + self.postprocessing_functions = postprocessing_functions + self.color_mode=color_mode + self._reflect = self.mode == 'reflect' + self.augmentation = augmentation + self.image_data_generator = image_data_generator + self.output_indices = output_indices + self.transforms = [] + if self.image_data_generator is not None: + self.transforms.append( self.image_data_generator.random_transform ) + self.transforms.append( self.image_data_generator.standardize ) + + _norm_const = sum(label_freq.values()) + #print(_norm_const) + self.patch_size = tuple(patch_size) + self.dtype = dtype + self.label_freq_dict = {kk:vv/_norm_const for kk,vv in label_freq.items()} + self.labels = np.asarray(list(self.label_freq_dict.keys())) + self.label_freq = list(self.label_freq_dict.values()) + self.label_cum_freq = np.cumsum(self.label_freq) + + self.index_generator = self._flow_index() + super(PatchIterator, self).__init__(nsamples, batch_size, shuffle, seed, + batch_rate = patches_per_image, +# stratify=stratify, oversampling=oversampling, +# postprocessing_function=postprocessing_function + ) + def sample_label(self, batch_size=None): + if batch_size == None: + batch_size = self.batch_size + matr = np.random.rand(batch_size, self.label_cum_freq.shape[0])>= self.label_cum_freq + label_inds = np.argmin(matr, axis=1) + return np.asarray([self.labels[x] for x in label_inds]) + + def init_indices(): + self.indices = np.random.randint(len(self.fn_img)) + + def open_npy(self): + for ff in self.fn_img: + img = open_memmap(ff, dtype=np.uint16, mode='r', shape=target_size[::-1]) + + def sample_points(self, index, labels): + fm = self.fn_pnt[index] + try: + samplegen = self.point_sampler(fm, labels) + for pt, label in zip(samplegen, labels): + yield (label, pt) + #pt = mzl.point(fm, buf=None, label=2, position=-1) + except OSError as ee: + print("error on ", fm) + raise ee + + def sample_img(self, img, pt, buffer=None, extend_dim=False, transforms=[]): + shape = img.shape + slc, padseq = get_slice(pt, size=self.patch_size, target_size=shape, reflect= self._reflect) + if buffer is None: + patch = pad_patch(img, slc, padseq) + return patch + else: + if self.mode == 'constant': + outslc = [slice(ss.start-ss.start, ss.stop-ss.start) for ss in slc] + if extend_dim: + outslc += [0] + buffer[outslc] = img[slc] + else: + outslc = [slice(None)]*len(slc) + if extend_dim: + outslc += [0] + buffer[outslc] = np.pad(img[slc], padseq, self.mode)#[:,:] + if self.augmentation and len(transforms)>0: + for tt in transforms: + if buffer is None: + print(fi, pt, tt) + buffer[:] = tt(buffer.copy())[:] + #print("finally after rescale", buffer.max()) + + def _get_batches_of_transformed_samples(self, sample_inds): + if sample_inds is None: + with self.lock: + sample_inds = next(self.index_generator) + # Repeat each image index + # sample_inds = list(itertools.chain.from_iterable(itertools.repeat(x, self.imgs_per_batch) for x in sample_inds)) + #batch_class_inds = self.sample_label() + curr_batch_size = len(sample_inds) * self.patches_per_image + pts = np.zeros((curr_batch_size, 2), dtype='uint16') + slices = [None, slice(None), slice(None)] + if self.color_mode is None: + extend_dim = False + buffer = np.zeros((curr_batch_size, ) + self.patch_size, dtype= self.dtype) + elif self.color_mode in ('grayscale', 'greyscale', 1): + extend_dim = True + buffer = np.zeros((curr_batch_size, ) + self.patch_size + (1,), dtype= self.dtype) + else: + raise ValueError("`color_mode` should be None or 'grayscale'") + + batch_class_inds = np.zeros(curr_batch_size, dtype='uint16') + for nn, (ss) in enumerate(sample_inds): + labels = self.sample_label(self.patches_per_image) + lbl_slice = slice(self.patches_per_image*nn, self.patches_per_image*(nn+1)) + batch_class_inds[lbl_slice] = labels + points = self.sample_points(ss, labels) + img = open_memmap(self.fn_img[ss], mode='r',) + for jj, (lbl, pt) in enumerate(points): + #range(self.patches_per_image): + #print("nn", nn, "jj", jj, "pt", pt) + pts[jj, :] = pt + slices[0] = nn * self.patches_per_image + jj + #print("buffer size", buffer.shape) + #print("slice", slices[0]) + self.sample_img(img, pt, buffer[slices], + transforms=self.transforms, + extend_dim=extend_dim) + + output = [buffer, batch_class_inds] + if self.output_indices: + output.append(sample_inds) + output.append(pts) + + for ii, (dd, ff) in enumerate(zip(output, self.postprocessing_functions)): + # print(ii, ff) + if ff is not None: + output[ii] = ff(dd) + return output #, pts + +# pool = multiprocessing.pool.ThreadPool() + + def next(self): + """For python 2.x. + + # Returns + The next batch. + """ + with self.lock: + index_array = next(self.index_generator) + # The transformation of images is not under thread lock + # so it can be done in parallel + return self._get_batches_of_transformed_samples(index_array)#import threading + +class MemMapDataset(): + def __init__(self, root_dir, csv_file, + classes = ["Control", "Case",], + label_col = "label", + filename_col = "filename", + binary=True, + transform=None, + nsamples = None, + encode_label = None): + import pandas as pd + self.transform = transform + self.csv_file = csv_file + self.table = pd.read_csv(csv_file) + if nsamples: + self.table = self.table[:nsamples] + self.filenames = self.table[filename_col].tolist() + self.classes = self.table[label_col].tolist() + self.root_dir = root_dir + self.label_col = label_col + self.filename_col = filename_col + for cc in classes: + if cc not in self.classes: + print("class is missing in data: %s" % cc) + #classes = np.unique(self.classes).tolist() + self.class_set = classes + if encode_label is None: + if len(classes) in (1,2) and binary: + self.onehot = MemMapDataset.encode_label_binary(self.table[label_col], self.class_set) + else: + self.onehot = MemMapDataset.encode_label_onehot(self.table[label_col], self.class_set) + else: + self.onehot = encode_label(self.table[label_col], self.class_set) + + @staticmethod + def encode_label_binary(labelvector, class_set): + onehot = np.stack([(labelvector == cc).values for cc in class_set[1:]], axis=-1) + return onehot + + @staticmethod + def encode_label_onehot(labelvector, class_set): + onehot = np.stack([(labelvector == cc).values for cc in class_set], axis=-1) + return onehot + + def __len__(self): + return len(self.table) + + def __getitem__(self, idx): + item = self.table.iloc[idx] + img_name = os.path.join(self.root_dir, item[self.filename_col]) + + image = open_memmap(img_name, mode='r') + label = self.onehot[idx] + + if self.transform: + sample = self.transform([image, label]) + else: + sample = [image, label] + + return sample + +class MemMapIterator(Iterator): + def __init__(self, root_dir, csv_file, + classes = ["Control", "Case",], + image_data_generator = None, + binary=True, + transform=None, + nsamples = None, + batch_size = 1, + shuffle = False, + seed = None, + postprocessing_function=None, + stratify=None, + oversampling=True, + subsample_factor=None, + subsample_num=None, + batch_rate=1, + dtype = K.floatx(), + color_mode=None, + data_format = 'channels_last', + label_col = "label", + filename_col = "filename", + encode_label=None, + ): + channels_axis = 3 if data_format == 'channels_last' else 1 + self.channels_axis = channels_axis + self.dtype = dtype + self.color_mode=color_mode + #self.image_data_generator = image_data_generator + self.transforms = [] + if image_data_generator is not None: + self.transforms.append( image_data_generator.random_transform ) + self.transforms.append( image_data_generator.standardize ) + + self.dataset = MemMapDataset(root_dir, csv_file, classes=classes, binary=binary, + transform=transform, nsamples=nsamples, + label_col = label_col, + filename_col = filename_col, + encode_label=encode_label, + ) + self.classes = self.dataset.classes + self.filenames = self.dataset.filenames + + super(MemMapIterator, self).__init__(len(self.dataset), batch_size, shuffle, seed, + stratify=self.classes if stratify else None, + oversampling=oversampling, + subsample_factor=subsample_factor, + subsample_num=subsample_num, + postprocessing_function=postprocessing_function, + ) + + def _get_batches_of_transformed_samples(self, index_array): + print("index_array", index_array) + batch_x = np.zeros(tuple([len(index_array)] + list(self.dataset[0][0].shape)), + dtype=self.dtype) + if len(batch_x.shape)==3: + batch_x = batch_x.reshape(batch_x.shape + (1,)) + for i, j in enumerate(index_array): + x = self.dataset[j][0] + if len(x.shape)==2: + x = x.reshape(x.shape + (1,)) + x = x.astype(self.dtype) + for tt in self.transforms: + x = tt(x) + batch_x[i] = x + if self.color_mode in (3,'rgb'): + if len(batch_x.shape)==3: + batch_x = np.stack([ batch_x ]*3, axis=-1) + if batch_x.shape[self.channels_axis]==1: + batch_x = np.concatenate([ batch_x ]*3, axis=3) + #print("batch_x", batch_x.shape) + #raise Exception("test!!!") + if self.postprocessing_function is not None: + batch_x = self.postprocessing_function(batch_x) + if len(self.dataset[0])==1: + return batch_x + batch_y = np.asarray([self.dataset[j][1] for j in index_array]) + return batch_x, batch_y + + def next(self): + """For python 2.x. + + # Returns + The next batch. + """ + # Keeps under lock only the mechanism which advances + # the indexing of each batch. + with self.lock: + index_array = next(self.index_generator) + # The transformation of images is not under thread lock + # so it can be done in parallel + return self._get_batches_of_transformed_samples(index_array) + + +def read_decode_coco(fname): + with open(fname) as fh: + coco = json.load(fh) + return decode(coco) + +class MemMapCocoDataset(): + def __init__(self, root_dir, csv_file, + binary=True, + transform=None, + nsamples = None, + mmapcol = 'memmap', + cococol = 'coco', + ): + import pandas as pd + self.transform = transform + self.table = pd.read_csv(csv_file) + if nsamples: + self.table = self.table[:nsamples] + self.root_dir = root_dir + self.mmapcol = mmapcol + self.cococol = cococol + + def __len__(self): + return len(self.table) + + def __getitem__(self, idx): + item = self.table.iloc[idx] + + img_name = os.path.join(self.root_dir, + item[self.mmapcol]) + image = open_memmap(img_name, mode='r') + + coco_name = os.path.join(self.root_dir, + item[self.cococol]) + label = read_decode_coco(coco_name) + + if self.transform: + sample = self.transform([image, label]) + else: + sample = [image, label] + + return sample + + +def resize_inputs(xx, yy, + mode='constant', + target_size = [512, 512], + constant_values_x = 255, + constant_values_y = 0, + add_const_to_label = 0, + ): + xx = (crop_pad_center(xx, target_size, pad_mode=mode, constant_values=constant_values_x)) + if add_const_to_label>0: + yy += add_const_to_label + yy = (crop_pad_center(yy, target_size, pad_mode=mode, constant_values=constant_values_y)) + if len(yy.shape) == 2: + yy= yy[..., np.newaxis] + return xx, yy + +class MemMapCocoIterator(Iterator): + def __init__(self, root_dir, csv_file, + image_data_generator = None, + binary=True, + mode='constant', + target_size = [512, 512], + constant_values_x = 255, + constant_values_y = 0, + nsamples = None, + batch_size = 1, + shuffle = False, + seed = None, + postprocessing_function=None, + stratify=None, + oversampling=True, + subsample_factor=None, + subsample_num=None, + batch_rate=1, + dtype = K.floatx(), + color_mode=None, + data_format = 'channels_last', + output_indices = False, + add_const_to_label=0, + ): + self.output_indices = output_indices + channels_axis = 3 if data_format == 'channels_last' else 1 + self.channels_axis = channels_axis + self.dtype = dtype + self.color_mode=color_mode + #self.image_data_generator = image_data_generator + #self.transforms = [] + if image_data_generator is not None: + self.get_random_transform_specs = image_data_generator.get_random_transform_specs + self.apply_geom_transform = image_data_generator.apply_transform + self.intensity_transform = image_data_generator.standardize + #self.transforms.append( image_data_generator.random_transform ) + #self.transforms.append( image_data_generator.standardize ) + if target_size is not None: + transform = lambda x : resize_inputs(x[0], x[1], + mode=mode, + target_size = target_size, + constant_values_x = constant_values_x, + constant_values_y = constant_values_y, + add_const_to_label=add_const_to_label, + ) + self.constant_values_x = constant_values_x + self.constant_values_y = constant_values_y + + self.dataset = MemMapCocoDataset(root_dir, csv_file, binary=binary, + transform=transform, nsamples=nsamples) + + super(MemMapCocoIterator, self).__init__(len(self.dataset), batch_size, shuffle, seed, + stratify=stratify, oversampling=oversampling, + subsample_factor=subsample_factor, + subsample_num=subsample_num, + postprocessing_function=postprocessing_function + ) + + def _get_batches_of_transformed_samples(self, index_array): + #import ipdb + #ipdb.set_trace() + batch_x = np.zeros(tuple([len(index_array)] + list(self.dataset[0][0].shape)), + dtype=self.dtype) + batch_y = np.zeros(tuple([len(index_array)] + list(self.dataset[0][1].shape)), + dtype=self.dtype) + if len(batch_x.shape)==3: + batch_x = batch_x.reshape(batch_x.shape + (1,)) + for i, j in enumerate(index_array): + x, y = self.dataset[j] + if len(x.shape)==2: + x = x.reshape(x.shape + (1,)) + + if hasattr(self, 'get_random_transform_specs'): + transform_matrix, horizontal_flip, vertical_flip = self.get_random_transform_specs(x) + x = self.apply_geom_transform(x, transform_matrix, horizontal_flip, vertical_flip, + interp=cv2.INTER_CUBIC, + #interp=cv2.INTER_NEAREST, + borderMode = cv2.BORDER_CONSTANT, + cval = [self.constant_values_x] *3, + use_opencv=True) + y = self.apply_geom_transform(y, transform_matrix, horizontal_flip, vertical_flip, + interp=cv2.INTER_NEAREST, + borderMode = cv2.BORDER_CONSTANT, + cval=self.constant_values_y, + use_opencv=True) + if hasattr(self, 'intensity_transform'): + x = self.intensity_transform(x) + x = x.astype(self.dtype) + batch_x[i] = x + batch_y[i] = y + if self.color_mode in (3,'rgb'): + if len(batch_x.shape)==3: + batch_x = np.stack([ batch_x ]*3, axis=-1) + if batch_x.shape[self.channels_axis]==1: + batch_x = np.concatenate([ batch_x ]*3, axis=3) + #print("batch_x", batch_x.shape) + #raise Exception("test!!!") + if self.postprocessing_function is not None: + batch_x = self.postprocessing_function(batch_x) + if self.output_indices: + if len(self.dataset[0])==1: + return batch_x, index_array + return batch_x, batch_y, index_array + else: + if len(self.dataset[0])==1: + return batch_x + return batch_x, batch_y + + def next(self): + """For python 2.x. + + # Returns + The next batch. + """ + # Keeps under lock only the mechanism which advances + # the indexing of each batch. + with self.lock: + index_array = next(self.index_generator) + # The transformation of images is not under thread lock + # so it can be done in parallel + return self._get_batches_of_transformed_samples(index_array) diff --git a/image_classifiers/inception_short.py b/image_classifiers/inception_short.py new file mode 100644 index 0000000..22bddf2 --- /dev/null +++ b/image_classifiers/inception_short.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +""" +Created on Fri Jun 9 11:00:55 2017 + +@author: dlituiev +""" + +import os +from collections import Counter +from functools import partial +from itertools import product + +import keras +from keras.applications.inception_v3 import InceptionV3 +from keras.preprocessing import image +from keras.models import Model +from keras.layers import Dense, GlobalAveragePooling2D, GaussianNoise, Input +from keras import backend as K +from keras.preprocessing.image import ImageDataGenerator +from keras.callbacks import Callback, LearningRateScheduler, ModelCheckpoint, EarlyStopping +from keras.layers import Dense, Dropout, Activation, Flatten, Lambda, BatchNormalization, Input +from keras.optimizers import Adam + +######################################### +def get_num_files(parentdir): + numfiles = 0 + for dd in os.scandir(parentdir): + dd = os.path.join(parentdir, dd) + if os.path.isdir(dd): + numfiles+= sum((1 for ff in os.scandir(dd))) + return numfiles +######################################### +######################################### +# SET UP THE NETWORK +######################################### +def get_model(n_classes, final_activation, + ndense=512, dropout=0.5, + weights='imagenet', + input_shape = [None, None, 3], + gaussian_noise_sigma = None, + input_tensor = None, + base_trainable=False): + + if input_shape: + input_tensor = Input(shape = input_shape) + if gaussian_noise_sigma is not None: + input_tensor = GaussianNoise(gaussian_noise_sigma)(input_tensor) + # create the base pre-trained model + base_model = InceptionV3(weights=weights, include_top=False, + input_tensor = input_tensor, + ) + # get third Concatenation layer and crop the network on it: + cc=0 + poptherest = False + for nn, la in enumerate(base_model.layers): + if type(la) is keras.layers.Concatenate: + if cc==3: + x = la.output + break + cc+=1 + base_model.layers = base_model.layers[:nn+1] + + #x = [la.output for la in base_model.layers if type(la) is keras.layers.Concatenate][3] + x = GlobalAveragePooling2D()(x) + # let's add a fully-connected layer + x = Dropout(dropout)(x) + + if ndense>0: + x = Dense(ndense, activation='relu')(x) + # and a logistic layer -- let's say we have 200 classes + predictions = Dense(n_classes, activation=final_activation)(x) + + # this is the model we will train + model = Model(inputs=base_model.input, outputs=predictions) + + # first: train only the top layers (which were randomly initialized) + # i.e. freeze all convolutional InceptionV3 layers + if not base_trainable: + for layer in base_model.layers: + layer.trainable = False + + last_module_index = [nn for nn,la in enumerate(model.layers) if type(la) is keras.layers.Concatenate][-2] + + for layer in model.layers[last_module_index:]: + layer.trainable = True + return model + + +def get_class_weights(datagen_val_output): + counter = Counter(datagen_val_output.classes) + print("distribution of labels in {}:\n{}".format(datagen_val_output.directory, str(counter))) + for kk,vv in counter.items(): + counter[kk] = vv+1 + + max_val = float(max(counter.values())) + + class_weights = {class_id : max_val/num_images for class_id, num_images in counter.items()} + return class_weights + + + +def w_categorical_crossentropy(weights): + def _w_categorical_crossentropy(y_true, y_pred, weights): + nb_cl = len(weights) + final_mask = K.zeros_like(y_pred[:, 0]) + y_pred_max = K.max(y_pred, axis=1) + y_pred_max = K.expand_dims(y_pred_max, 1) + y_pred_max_mat = K.equal(y_pred, y_pred_max) + for c_p, c_t in product(range(nb_cl), range(nb_cl)): + + final_mask += (K.cast(weights[c_t, c_p],K.floatx()) * + K.cast(y_pred_max_mat[:, c_p] ,K.floatx()) * + K.cast(y_true[:, c_t],K.floatx()) + ) + return K.categorical_crossentropy(y_pred, y_true) * final_mask + + ncce = partial(_w_categorical_crossentropy, weights=weights) + ncce.__name__ ='w_categorical_crossentropy' + return ncce + + +if __name__ == '__main__': + import numpy as np + import keras + #csv_path = CHECKPOINTS_BASE + ".log.csv" + #csv_callback = keras.callbacks.CSVLogger(csv_path, separator=',', append=False) + os.environ['KERAS_BACKEND'] = 'tensorflow' + os.environ['CUDA_HOME'] = '/usr/local/cuda-8.0' + os.environ["CUDA_VISIBLE_DEVICES"] = '2' + + NDENSE=256 #512 + BATCH_SIZE = 128 + NB_EPOCH = 20 + DATA_AUGMENTATION = True + SEED=0 + CLASS_MODE = 'binary' # 'categorical' + LOSS = '{}_crossentropy'.format(CLASS_MODE) + N_CLASSES = 1 + FINAL_ACTIVATION = 'sigmoid' + LR = 0.0001 + SAMPLEWISE_CENTER = False #True + + TARGET_SIDE = 99 + TARGET_SIZE = [TARGET_SIDE]*2 + + BASE_TRAINABLE=False + CHECKPOINT_DIR = "./modelstate_withx_negloglr{:d}_ndense{:d}_imsize{:d}{}/" .format( + int(-np.log10(LR)), + NDENSE, + TARGET_SIDE, + "" if not BASE_TRAINABLE else "_base_trainable" + ) + CHECKPOINT_PATH = CHECKPOINT_DIR + 'model.{epoch:02d}-{val_loss:2f}.hdf5' + + WEIGHTFILE = None # "./modelstate_withx_negloglr4_ndense256/model.39-0.060567.hdf5" # None # "./modelstate_withx/model.03-0.067136.hdf5" + # "modelstate_laplace_inv_weights_2/model.10-0.014968.hdf5" #CHECKPOINT_DIR + "model.10-0.019602.hdf5" + INIT_EPOCH=0 + # indir = "/data/dlituiev/learn_spotmag_from_images/modelstate/" + # find_min_loss_checkpoint(indir) + + + DATA_TRAIN = '/data/UCSF_MAMMO/2017-07-png/withx_valset_4000_train/' + DATA_VAL = '/data/UCSF_MAMMO/2017-07-png/withx_valset_4000_test/' + SAMPLES_PER_EPOCH = get_num_files(DATA_TRAIN) + STEPS_PER_EPOCH = SAMPLES_PER_EPOCH // BATCH_SIZE + + CLASSES = ["normal", "special"] + + VALIDATION_STEPS = get_num_files(DATA_VAL) // BATCH_SIZE + print('='*50) + print("validation steps", VALIDATION_STEPS) + print("samples per epoch in the train set: %d" % SAMPLES_PER_EPOCH) + print("steps per epoch in the train set: %d" % STEPS_PER_EPOCH) + print('='*50) + ######################################### + os.makedirs(os.path.dirname(CHECKPOINT_PATH), exist_ok=True) + checkpoint = ModelCheckpoint(CHECKPOINT_PATH, monitor='val_loss', verbose=1, + save_best_only=False, save_weights_only=False, mode='auto', period=1) + callbacks_list =[checkpoint] + + ######################################### + model = get_model(n_classes=N_CLASSES, + final_activation=FINAL_ACTIVATION, + ndense=NDENSE, + dropout=0.5, + base_trainable=BASE_TRAINABLE) + + + #from keras.utils import plot_model + #plot_model(model, to_file='model.png') + + + model.compile(optimizer=Adam(lr=LR), loss=LOSS, metrics=['accuracy'], + callbacks = [csv_callback]) + ######################################### + if WEIGHTFILE: + print("loading weights from:\t%s" % WEIGHTFILE) + model.load_weights(WEIGHTFILE) + + print('Using real-time data augmentation.') + + flowfromdir_params = dict( + #color_mode = "grayscale", + target_size=TARGET_SIZE, + batch_size=BATCH_SIZE, + class_mode=CLASS_MODE, + classes=CLASSES, + seed=SEED) + + train_datagen = ImageDataGenerator( + samplewise_center=SAMPLEWISE_CENTER, + samplewise_std_normalization=SAMPLEWISE_CENTER, + featurewise_center=False, + featurewise_std_normalization=False, + zca_whitening=False, + rotation_range=10, + width_shift_range=0.125, + height_shift_range=0.125, + horizontal_flip=True, + vertical_flip=False) + + val_datagen = ImageDataGenerator() + + datagen_train_output = train_datagen.flow_from_directory( + DATA_TRAIN, shuffle=True, **flowfromdir_params) + + datagen_val_output = val_datagen.flow_from_directory( + DATA_VAL, shuffle=False, **flowfromdir_params) + + class_weights = get_class_weights(datagen_val_output) + + model.fit_generator(datagen_train_output, + steps_per_epoch=STEPS_PER_EPOCH, + epochs=NB_EPOCH, verbose=1, + validation_data=datagen_val_output, + validation_steps=VALIDATION_STEPS, + #class_weight='auto', + class_weight=class_weights, + callbacks=callbacks_list, + initial_epoch=INIT_EPOCH) + + + + #model.predict() diff --git a/plot_auroc_difference_pvalue.ipynb b/plot_auroc_difference_pvalue.ipynb new file mode 100644 index 0000000..538c966 --- /dev/null +++ b/plot_auroc_difference_pvalue.ipynb @@ -0,0 +1,684 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 245, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib as mpl\n", + "import seaborn as sns\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 246, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "fn = \"../tables/auroc_delong_comparison-e5ce2d69b035975cb5336cec0da9a32a.csv\"\n", + "df = pd.read_csv(fn, index_col=0)\n", + "# df.drop('score_wire', axis=0, inplace=True)\n", + "# df.drop('score_wire', axis=1, inplace=True)\n", + "df.drop('wire', axis=0, inplace=True)\n", + "df.drop('wire', axis=1, inplace=True)\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 247, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "modelnamemap = {'rpart':'RPART', 'gbm':'GBM', 'glmnet':'GLMNet', 'xgb':'XGB', 'gbmt':'GBMT',\n", + " 'image':'avg(image)',\n", + " 'image_max':'max(image)',\n", + " 'wire_max': 'max(wire)',\n", + " 'max_image_wire_max': 'max(image, wire)',\n", + " 'image+gbmt': 'image+GBMT',\n", + " 'max_wire_max_image+gbmt': 'max(image+GBMT, wire)',\n", + " 'max_image_wire':'max(avg(image), avg(wire))',\n", + " 'max_wire_image+gbmt': 'max(avg(image)+GBMT, avg(wire))',\n", + "# 'avg(image)+gbmt':'avg(image)+GBMT',\n", + " 'max(max(wire), avg(image)+gbmt)':'max(wire, image+GBMT)',\n", + " 'ViewModifier':'ViewModifier',\n", + " } " + ] + }, + { + "cell_type": "code", + "execution_count": 248, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def namemap(x,n=8):\n", + " if x!=x:\n", + " return \"\"\n", + " elif x==1.0:\n", + " return \"1.0\"\n", + " elif x>0.01:\n", + " return \"%.2f\" % x\n", + " else:\n", + " return \"1e{:.0f}\".format(pd.np.log10(x))" + ] + }, + { + "cell_type": "code", + "execution_count": 249, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# df.applymap(namemap)\n", + "df[df==1] = np.nan" + ] + }, + { + "cell_type": "code", + "execution_count": 250, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ViewModifier 12\n", + "rpart 11\n", + "gbm 10\n", + "glmnet 9\n", + "xgb 8\n", + "gbmt 7\n", + "image 6\n", + "image_max 5\n", + "wire_max 0\n", + "max_image_wire_max 3\n", + "image+gbmt 3\n", + "max_wire_max_image+gbmt 1\n", + "max_image_wire 1\n", + "dtype: int64" + ] + }, + "execution_count": 250, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(~df.isnull()).sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 251, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "nbonferroni = (~df.isnull()).sum().sum()\n", + "# df_bonferroni = np.minimum(1.0, df*nbonferroni)" + ] + }, + { + "cell_type": "code", + "execution_count": 252, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.18" + ] + }, + "execution_count": 252, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "thr_bonferroni = -np.log10(0.05/nbonferroni)\n", + "round(thr_bonferroni,2)" + ] + }, + { + "cell_type": "code", + "execution_count": 253, + "metadata": {}, + "outputs": [], + "source": [ + "df = df.rename(columns=modelnamemap, index=modelnamemap)\n", + "df = df.loc[df.index.map(lambda x : 'avg(wire)' not in x).tolist(),\n", + " df.columns.map(lambda x : 'avg(wire)' not in x).tolist()]\n", + "\n", + "keep_rows = ~df.isnull().all(1)\n", + "keep_cols = ~df.isnull().all(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 254, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "RPART True\n", + "GBM True\n", + "GLMNet True\n", + "XGB True\n", + "GBMT True\n", + "avg(image) True\n", + "max(image) True\n", + "max(wire) False\n", + "max(image, wire) True\n", + "image+GBMT True\n", + "max(image+GBMT, wire) True\n", + "dtype: bool" + ] + }, + "execution_count": 254, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "~df.isnull().all(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 255, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.cm.get_cmap('viridis_r', 6) # 11 discrete colors\n", + "\n", + "fig, ax = plt.subplots(1, figsize=(7,7))\n", + "hmobj = sns.heatmap(df.loc[keep_rows, keep_cols].applymap(lambda x: -pd.np.log10(x)),\n", + " cmap=cmap, vmin=0, vmax=6,\n", + " cbar_kws={},\n", + " square=True,\n", + " annot=df.loc[keep_rows, keep_cols].applymap(lambda x: -pd.np.log10(x)), \n", + " fmt = '.2f',\n", + " ax=ax)\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\\nBonferroni-adjusted $\\\\alpha=0.05$ threshold = %.2f\" % thr_bonferroni)\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\")" + ] + }, + { + "cell_type": "code", + "execution_count": 256, + "metadata": {}, + "outputs": [], + "source": [ + "dfstr = df.applymap(lambda x: ('{n:5.{s}{c}} '.format(n=x, c='e' if x < 1e-3 else 'f',\n", + " s = 3- 2*(x < 1e-3)\n", + " ).replace('-0','-').replace('nan',''))\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 257, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ViewModifierRPARTGBMGLMNetXGBGBMTavg(image)max(image)max(wire)max(image, wire)image+GBMTmax(image+GBMT, wire)
RPART0.048
GBM0.0280.617
GLMNet8.8e-40.0990.287
XGB4.4e-40.0520.1090.513
GBMT2.1e-40.0300.0730.2600.519
avg(image)1.0e-61.7e-40.0040.0040.0100.014
max(image)1.1e-61.9e-40.0050.0050.0130.0170.168
max(wire)
max(image, wire)1.0e-61.5e-40.0020.0030.0050.0060.1000.108
image+GBMT8.1e-71.9e-40.0060.0060.0160.0230.0810.2020.034
max(image+GBMT, wire)9.4e-71.4e-40.0020.0030.0050.0060.0860.0950.3380.029
\n", + "
" + ], + "text/plain": [ + " ViewModifier RPART GBM GLMNet XGB GBMT \\\n", + "RPART 0.048 \n", + "GBM 0.028 0.617 \n", + "GLMNet 8.8e-4 0.099 0.287 \n", + "XGB 4.4e-4 0.052 0.109 0.513 \n", + "GBMT 2.1e-4 0.030 0.073 0.260 0.519 \n", + "avg(image) 1.0e-6 1.7e-4 0.004 0.004 0.010 0.014 \n", + "max(image) 1.1e-6 1.9e-4 0.005 0.005 0.013 0.017 \n", + "max(wire) \n", + "max(image, wire) 1.0e-6 1.5e-4 0.002 0.003 0.005 0.006 \n", + "image+GBMT 8.1e-7 1.9e-4 0.006 0.006 0.016 0.023 \n", + "max(image+GBMT, wire) 9.4e-7 1.4e-4 0.002 0.003 0.005 0.006 \n", + "\n", + " avg(image) max(image) max(wire) max(image, wire) \\\n", + "RPART \n", + "GBM \n", + "GLMNet \n", + "XGB \n", + "GBMT \n", + "avg(image) \n", + "max(image) 0.168 \n", + "max(wire) \n", + "max(image, wire) 0.100 0.108 \n", + "image+GBMT 0.081 0.202 0.034 \n", + "max(image+GBMT, wire) 0.086 0.095 0.338 \n", + "\n", + " image+GBMT max(image+GBMT, wire) \n", + "RPART \n", + "GBM \n", + "GLMNet \n", + "XGB \n", + "GBMT \n", + "avg(image) \n", + "max(image) \n", + "max(wire) \n", + "max(image, wire) \n", + "image+GBMT \n", + "max(image+GBMT, wire) 0.029 " + ] + }, + "execution_count": 257, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfstr" + ] + }, + { + "cell_type": "code", + "execution_count": 258, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr4AAAJaCAYAAADJUkThAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzs3Xl4VdW5x/Hvm5McSEgCSSCQADILIiIQFBQQBUVRrgPibK1WpVXRllrrVDvcOg9FRarS61CHOhYVrQMKVRFFMQIigiLIFCABAiEkgQxn3T/2gSScJEwHk7B/n+fJ49l7v3udd0HQXxbrbM05h4iIiIjIwS6mvhsQEREREfkpKPiKiIiIiC8o+IqIiIiILyj4ioiIiIgvKPiKiIiIiC8o+IqIiIiILyj4ioiIiIgvKPiKiIiIiC8o+IqIiIiILyj4ioiIiIgvxNZ3A9K4ZGdnuylxd9R3G/tsdNmtAGRlZdVzJ/suOzsbaPxzaMz9g+bQEBwsfxZAc6hvB8scsrKyrL77aOi04isiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr4QW98NyMFp3dxC5j21DheCTsNb0OOsVhE1FWUh5kzMYdOybQSTAgwc345m6cGd14vXl/Le+KX0PLcV3U9vCcD3b21g+fTNYND8kCb0v7otgaB+fhMREZHdU2JogMyswszmmdk3ZvammbUIn+9oZiXha9+a2WNmFlPlvvFmts3Mmlc5d7yZFZjZXDNbbGb3h89fFh5nnpmVmtmC8Ou797d/V+GY+8RaBt/agZMndGHVrAK2rNoWUbd8xmaCiQFGPtKNQ0elseC53GrX5/9zHW36Ju48LtlYxg9v5zP87s6M+FtXXAhWzSrY33ZFRETEJxR8G6YS51wf51wvIB+4psq1pc65PkBvoCdwZpVrFwBzgLN2GW+mc64v0BcYZWaDnHNPhd+jD7AGOCF8fNP+Np//QwmJbYIktg4SExdD+0HNWfNlYUTdmjlb6DC0BQBtByaT900RzjkAcr7YQrP0IMntm1S7x4UcFaUhQhWO8u0hmqbG7W+7IiIi4hMKvg3fZ0DbXU8658qBT4GuAGbWBUgE/oAXgCM450qAeTWNF00l+WXEp1UG0vjUOEo2ltdQV058S68uJmDEJcRQWlhB+bYQ372+gZ7nVN8eEZ8Wx6H/05L/XLWEt678jriEAG2OTIwYV0RERKQmCr4NmJkFgOHA1BquJYSvLQifugB4AZgJdDez9BruSQG6AR8fqJ5rZTWcczXXLXw5j26j0oiND1S7VLq1gjVzCjl1UjdGTe5OxfYQKz7efEDaFRERkYOPPtzWMMWb2TygI5ANvF/lWpfwNQe84Zx7J3z+fOAs51zIzKYA5wCTwteGmNnXQHfgbufcur1pxszGAmMBbrnlFjhvN82nxlGysWzncUl+GfGpkd9q8WmxlGwoIyEtjlCFo6w4RDAxQP6SEnJmb2HBc7mUFVWAGYE4o2mLWJqlx9GkuTdW2wHJbPyumA7Htdib6YiIiIhPKfg2TCXOuT7hD6m9hbfH9+HwtR17fHcys954K7nvmxlAEFhGZfCd6ZwbZWaHAp+Y2WvOuXl72oxzbjIwGSA7O9tN4Y4661O6xrN1bSlFuaXEp8ayalYBR/+6XURdRv8kVny0mbTuCeTM3kJ6r2aYGSf8tdPOmoUv5xHbNIauI9PYuKSY/CUllG8PEQgaeQu2ktIlfk+nISIiIj6n4NuAOecKzOw64A0ze7SO0guAPzvn7tpxwsx+NLMOu4z3vZndBdxILfuAoyEmYPS5PIOZd6zAhRwdT0ihefumACx8MY+ULk3JPCqZTsNS+GJiDu+MW0IwMcCA8ZHhuKq0bgm0HZjM9N8vxQJGi45N6XRiyoGahoiIiBxkFHwbOOfcXDObj7eVYWYtZecDI3c591r4/Oe7nH8M+J2ZdXLO/RjVZqvI6JdERr+kiPOHn1+59TgQjOGY69vXOc7h51bfqnz4eekcfl7E9mURERGR3VLwbYCcc4m7HP9PlcNeNdR3quHcb6scfljlfAm7PNXBOddxH1sVERERaTT0VAcRERER8QUFXxERERHxBQVfEREREfEFBV8RERER8QUFXxERERHxBQVfEREREfEFBV8RERER8QUFXxERERHxBQVfEREREfEFBV8RERER8QUFXxERERHxBQVfEREREfEFBV8RERER8QUFXxERERHxBQVfEREREfEFBV8RERER8QUFXxERERFptMyshZm9amaLzWyRmR1TW23sT9mYiIiIiEiUPQS865wbY2ZBIKG2QgVfEREREWmUzCwZOA64FMA5VwqU1lrvnPtpOpODQnZ2tr5hREREGqCsrCyr7x4AToo5J2pZ4QP36i+BsVVOTXbOTd5xYGZ9gMnAt8CRQDbwa+dcUU3jacVX9tqUuDvqu4V9NrrsVgD6tr2gnjvZd3NzXgAgKyurnjvZd9nZ2Y26f9AcGoLs7Gyg8f9ZAM2hvh1MczjYhEPu5DpKYoF+wLXOuc/N7CHgJuC2mor14TYRERERaaxWA6udc5+Hj1/FC8I1UvAVERERkUbJObcOWGVm3cOnhuNte6iRtjqIiIiISGN2LfB8+IkOy4DLaitU8BURERGRRss5Nw/ovye12uogIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivqDgKyIiIiK+oOArIiIiIr6g4CsiIiIivhBb3w3IwWnd3ELmPbUOF4JOw1vQ46xWETUVZSHmTMxh07JtBJMCDBzfjmbpQXLnb2XB87mEyh0xsUbvn7Um/YhEAFZ+UsDiKesxg6YpcRx9XVuaJEf/23jm53DnRAiFYMxpcOVFNde9MwMmPQ0Y9OgC9//RO3/lDTD/W+h3BDx2d2X9xeOgqMR7vXET9D4MHrkj6u2LiIhIDRR8GzEzaw1MAAYCm4BS4N7w6zeAH/FW9fOAC51zeWZ2KfAUcKJzbnp4nLOAKcA5zrlX97cvV+GY+8RahtzWkYTUWKbfvIzM/kkkt29arW75jM0EEwOMfKQbq2YVsOC5XAb+tj3B5ACDbjqE+NQ4ClZuY+btKxg1uTuhCsf8p9YyYkJXmiTH8vWz6/jh3XwOPzd9f1uupqIC/vogPPEAtG4F5/4SThgEXTtWr1u+Gv7xPDw/CZoneUF2h1+cD9u2wUtvVr/nuUcqX193GwwbFNXWRUREpA7a6tBImZkBrwMfO+c6O+eygPOBduGSmc65Ps653sAc4Joqty8ALqhyfD4wP1q95f9QQmKbIImtg8TExdB+UHPWfFkYUbdmzhY6DG0BQNuByeR9U4RzjpRO8cSnxgGQ3L4JoTJHRVkIHDgH5dtDOOcoLwkRnxL9n92+XgSHtIX2mRCMg1OHwYxPIuteeRMuOMsLvQBpKZXXjsmCZgm1v0dRMXz+FZw4JLq9i4iISO204tt4DQNKnXOP7TjhnFsBTDSz43ecCwfkJOCHKvfOBIaYWRzQBOgKzItWYyX5ZcSnxe08jk+NI39JSQ115cS39OpiAkZcQgylhRXVti7kzN5Ci05NCcR5P6P1uzKD969fSmyTGBIzgvS9PCNabe+UtwHaVFlEbt3KC8O7WrHa++eF10BFCMZdCkMG7Nl7vP8xDMyCxGb73a6IiIjsIa34Nl6HA1/VcX2Imc0DVgInAk9WueaAD4CTgTOAqQeqyZ2shnOu7rqCVdtY8Hwu/cZmAhAqdyydtokT7+3CaZMPpfkhTVn8+oaot+pq6Kum9ssrvPD7z4fggT/CbffBlsiF7Rq9PR1OG75fbYqIiMheUvA9SJjZJDObb2Zzwqd2bHVoj7en995dbnkRb4vD+cALuxl7rJl9aWZfTpkyZbe9xKfGUbKxbOdxSX4Z8amRf7kQnxZLyQavLlThKCsOEUwMAFC8sYzP7lvFUePakdgmCMDm5dsASGwTxMxod2wyG78r3m0/e6t1K1iXV3mcux7SW0bWtWkFwwdDXCy0y4BO7StXgeuyqQC+XgxDB0avZxEREdk9Bd/GayHQb8eBc+4aYDgQ+fgEb0X3uKonnHNfAL2Als657+t6I+fcZOdcf+dc/9GjR++2sZSu8WxdW0pRbimhshCrZhWQ0T8poi6jfxIrPtoMeFsa0ns1w8woLapg1l0r6HVha1r2qNwoG58aS+Hq7WwvKAcg9+utJLVtstt+9tYRPbwAu3otlJbB2zO8D7ftavhg+Hyu93rTZli+Ctpl7n789z6E44+BJtFvXUREROqgPb6N1wzgTjO7yjn3aPhcbR+nGgwsreH8zcC2aDcWEzD6XJ7BzDtW4EKOjiek0Dz8RIeFL+aR0qUpmUcl02lYCl9MzOGdcUsIJgYYMN77XN7Sd/PZuq6URa+uZ9Gr6wEYclsH4lPjOOycVnz4px+JCRgJreLof03baLdPbCz84Tdwxe+8x5mNPhW6dfKuPfwE9OrhPY1h8NEwaw6MugRiYuB3V0FKc6/u4nGwbCUUl8DxY+D233v14AXpKy+MetsiIiKyGwq+jZRzzpnZmcAEM/s9sB4oAm4Ml+zY42tAAXBFDWO8c6D6y+iXREa/yFXew8+v/NRYIBjDMde3j6g57OxWHHZ2TQvX0GVEKl1GpEav0VoMHVjzVoTrLq98bQY3jav5/qqPLdvVMw/tX28iIiKybxR8GzHn3Fq8Pbo1aV7LPU8DT9dw/tJo9SUiIiLSEGmPr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4gjnn6rsHaUSys7P1DSMiItIAZWVlWX33AHBSzDlRywrvh16J6pxiozmY+MMlr35c3y3ss2fGHAfAlLg76rmTfTe67FYA+ra9oJ472Xdzc14gKyurvtvYL9nZ2ZpDPcvOzgbQHOqZ5tAw7JiD1E1bHURERETEFxR8RURERMQXFHxFRERExBcUfEVERETEFxR8RURERMQXFHxFRERExBcUfEVERETEFxR8RURERMQXFHxFRERExBcUfEVERETEFxR8RURERMQXYuu7ARERERGRfWVmy4FCoAIod871r61WwVdEREREGrsTnHMbdlekrQ4iIiIi4gsKviIiIiLSmDlgmpllm9nYugq11UFEREREoqZieFbUxgoH2aphdrJzbvIuZYOcc2vMLB1438wWO+c+rmk8BV8RERERaZDCIXfXoLtrzZrwP/PM7DXgaKDG4KutDiIiIiLSKJlZMzNL2vEaGAF8U1u9Vnwlqi4Z1JezjzoC5xxLcjdw66vTKC2vqFaT0TyJO885maT4JsSYMeG9T5j53fK9fq8Rvbox4aJRnPvIv1iYkxulGXjWzS1k3lPrcCHoNLwFPc5qFVFTURZizsQcNi3bRjApwMDx7WiWHiRUFiJ78lo2LS3BYuDIyzJIP7wZAKtmFbB4ynpcCNr0S6T3z9pEte+qZn4Od06EUAjGnAZXXhRZ8/RL8Op/IBCA1BZw+43QNtzSfY/CR7PBheDY/nDLdVBcAhdfW3n/uvXwPyfBLddGji0iIvITaA28Zmbg5dp/Oefera1YK771yMxam9m/zGxZeEP2Z2Z2lpkdb2Zv1VD/oZmttPDvbvjc62a2Nfy6o5k5M7u2yvVHzOzS3fRxppn13N/5pCc346Jj+3LuI89z5kPPEmMxnNq7e0TdL4cN4N0F3zNm4vPc8OLb3HbGsL1+r4RgHBcd24f5K9fub9sRXIVj7hNrGXxrB06e0IVVswrYsmpbRN3yGZsJJgYY+Ug3Dh2VxoLnvPC9bPomAEb8rStDbuvI1/9chws5theW8/WzuRz3x46MmNCV7QXl5C7YGvX+ASoq4K8PwuR74c1/wn+mww/LI+sO6wavTIY3noIRQ+H+x7zzc7/xvt54EqY+DQsWw5x50CwBXnui8iuzNZx03AGZgoiIyG4555Y5544Mfx3unLujrnoF33oSDq+vAx875zo757KA84F2u7l1MzAoPEYLIGOX63nAr80suBftnAnsd/AFCMTE0DQulkCM0TQYS15hZLBzzpHYxGsvsWkT8rYUARBjxvUjh/DSNRcw5bqLOefoI2p9n+tGHMuTH3/J9vLyaLRdTf4PJSS2CZLYOkhMXAztBzVnzZeFEXVr5myhw9AWALQdmEzeN0U45yhcvZ30I7wV3qbNY4lrFmDT0hKKcstIygzSpLn3Fy3pRySSM3tL1PsH+HoRHNIW2mdCMA5OHQYzPomsG9AP4pt6r4/sCbnrK69tL4Wycigtg/IKSEupfu/y1ZC/Cfr3PiBTEBERiToF3/ozDCh1zj2244RzboVzbuJu7nsRLyADjAam7HJ9PTAd+PmuN5pZFzN7N7y6PNPMepjZscDpwH1mNs/MuuzrhPK2FPH0zGw+uPEKPrx5LFu3befTJSsj6iZNn82ovocx/aYrePTSM7lz6n8BOLt/L7Zu2855k17gvEkvMOaoI2ibkhxxf4+MVrRpnsRHi3/c11brVJJfRnxa3M7j+NQ4SjZGBuyS/HLiW3p1MQEjLiGG0sIKmndoypo5hYQqHEW5pWxeVkLxxnIS2wQpzNlOUV4poQrHmjlbKNlYdkDmkLcB2qRXHrduBbm7eaz3v9+GIQO81317wYC+cNxo72vwUdClY/X6/3wAI4dB5d8/iIiINGza41t/Dge+2of7pgP/MLMAXgAeC9y2S83dwDtm9uQu5ycDv3LOLTGzAcDfnXPDzGwq8JZz7tV96Gen5KZNGNazMyPue5LCku387cLTGNWnB2/NW1yt7rQju/N69kL++clXHHlIBnefewpnPPQMx3brwKEZLRnRqxvgrQZ3aNmCnE2Vq6JmcOOoodz6yrT9aXXv1RTuXM11HYelsCVnO9NvXEZCqzjSuicQE4BgYoC+V2Yye8JqzCCtewJFuaUHpF1XQ2915dOp0+Cb7+DZh7zjFath6Qr47yve8eXXw5z5cNSRlfe8MwPuuTVqLYuIiBxwCr4NhJlNAgYDpcANdZRWAJ8A5wHxzrnltsuSm3PuRzP7AriwyviJwLHAK1Xqm+xhbzufoXfLLbcALWusG9j1EFbnb2FTUQkAHyz8gb4dMiOC7+j+vfjlU95C9fyVawnGxZKSEI8Z3Dn1v8xasqJa/XUjjmVo904A/HzyK3Rr3ZKnx44BoGViMx655HTGPTM1ah9w81Z4K1diS/LLiE+N/KMSnxZLyYYyEtLiCFU4yopDBBMDmBl9Lq3cgTLj1mUktvG2dmT2TyKzfxIAy97Pxw7Q37m0bgXr8iqPc9dDes2/bXz6JTz+LDzzMATDG2Q+mOltfWiW4B0PGQDzF1YG38U/eNsfDo/cwi0iItJgaatD/VkI9Ntx4Jy7BhgORD4+INKLwETg5Tpq7gRupPL3OAbY7JzrU+XrsD1p1Dk32TnX3znXf/To0bXWrS0o5MhDMmga54XEgV0PYWlefmTd5i0M7HIIAJ1bpdIkNkB+UQmzvl/BeQN6ExvjtdyhZQvi42J5eNqnnD3xec6e+Dxbt5cy+PbHGHHvk4y490nmr1ob1dALkNI1nq1rSynKLSVUFmLVrAIywmG1qoz+Saz4aDMAObO3kN6rGWZG+fYQ5dtCAOTO30pMwEhu722k3VbgbZko3VrB0vc20Wl4SsS40XBED2/VdvVab4/u2zPghEGRdd9+D39+ACbdVX0Pb0Zrb4W3vNzb5/vlfOjSofL6f6bDacMPSOsiIiIHjFZ8688M4E4zu8o592j4XMIe3jsTuAt4obYC59xiM/sWGAV84ZzbYmY/mtk5zrlXwh+u6+2cmw8UApHJbi8tWLWOad8s4ZVxF1ERCrFo7Xpe+WIBAONOPIaFObn8d9Ey7nv7Y/5y1klcMrgfzjluffU9AF79cgGZKcm8cu1FGLCpqIRrn526v23ttZiA0efyDGbesQIXcnQ8IYXm4eC68MU8Uro0JfOoZDoNS+GLiTm8M24JwcQAA8Z7n0vcXlDOzNtXYDHe6vFR17bdOfb8p9ayefl2AHqe04qkzD1adN9rsbHwh9/AFb/zHmc2+lTo5i2a8/AT0KsHDBsE9z3mPaJs/J+8axnp8Pe74OSh8PlXcMZl3vaSwUdXD87v/hcev+eAtC4iInLAKPjWE+ecM7MzgQlm9nu8D6UV4a3SAgw3s9VVbjmn6r3A/XvwNncAc6scXwQ8amZ/AOLwVo7nh//5DzO7DhjjnFu6j9Ni0gefMemDzyLOP1Ll3NK8fC5+/KWIGufgoWmzeGjarD1+v8v+sV/bkmuV0S+JjH6RPwscfn7lJ8YCwRiOub59RE2z9CCnPNytxnEH/Cay/kAZOtD72tV1l1e+fupvNd8bCMBfflf72O+/uH+9iYiI1AcF33rknFtL5RMadhVfw7njaxknMfzP5UCvKufnU2U7i3PuR+CUGu6fRZQeZyYiIiLSUGmPr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+IKCr4iIiIj4goKviIiIiPiCgq+IiIiI+II55+q7B2lEsrOz9Q0jIiLSAGVlZVl99wAw7KS7o5YVZrx/U1TnpBVfEREREfGF2PpuQBqfS179uL5b2GfPjDkOgClxd9RzJ/tudNmtAPRte0E9d7Lv5ua80Kj7B28OWVlZ9d3GfsnOzm7Uc8jOzgbQHOqZ5tAw7JiD1E0rviIiIiLiCwq+IiIiIuILCr4iIiIi4gsKviIiIiLiCwq+IiIiIuILCr4iIiIi4gsKviIiIiLiCwq+IiIiIuILCr4iIiIi4gsKviIiIiLiCwq+IiIiIuILCr4iIiIi4gsKviIiIiLiCwq+IiIiIuILCr4iIiIi4gsKviIiIiLiCwq+IiIiIuILCr4iIiIi4gux9d2AHHxizHh53IXkbtnKNf98o9a6Eb26MeGiUZz7yL9YmJO71++zv/fXZd3cQuY9tQ4Xgk7DW9DjrFYRNRVlIeZMzGHTsm0EkwIMHN+OZulBivJKee83P5CU2QSAtEPj6Tc2k/LtIWY/sIqi3FIsxsjISuKIi1tHte+qZn4Od06EUAjGnAZXXhRZM2c+3DURvl8GD/wRTj6+8trr78Kjz3ivr7oEzjzFe/32DHj8WagIwdCBcMNVB2wKezSH196B+x6F1uHfogvPgnNGea+vvAHmfwv9joDH7q6859Z7YOF34Bx0bA933gTNEg7cPEREpGFQ8G3kzKw98DGQ5ZzLN7MU4CvgeCAITAAOAzYDW4A/Oec+NrNLgfuAHCAOWARc4pwr3t+efjaoL8vy8mnWNFhrTUIwjouO7cP8lWv36T329/66uArH3CfWMuS2jiSkxjL95mVk9k8iuX3TanXLZ2wmmBhg5CPdWDWrgAXP5TLwt+0BSGwT5KT7u0SMfejpLUnv1YxQWYiP/ncFa+cWktE3KepzqKiAvz4ITzzgBcJzfwknDIKuHavXZabDXTfDky9WP795C0x6Gl6ZDGYw5krv/lAI7n8UXv0HpLaAm+6Ez7LhmKyoT2GP5wAwchjc9pvI8784H7Ztg5ferH7+5nGQ2Mx7ffcj8K/Xag7VIiJycNFWh0bOObcKeBTYsZ51NzAZyAX+A0x2znVxzmUB1wKdq9z+knOuj3PucKAUOG9/+2mdnMhx3Tvx7znf1Fl33YhjefLjL9leXr7zXIwZ148cwkvXXMCU6y7mnKOP2Kv7oyX/hxIS2wRJbB0kJi6G9oOas+bLwoi6NXO20GFoCwDaDkwm75sinHO1jhvbJIb0Xl7aiomLIaVTU0o2lkW9f4CvF8EhbaF9JgTj4NRhMOOTyLq2GdC9C8Ts8m+CWV/Asf2hRTI0T/Jef/I5rF4DHdp7oRe8wDvtowMyhT2eQ12Oyap5JXdH6HUOtm0HbL/bFRGRRkDB9+AwARhoZr8BBgMPABcBnznnpu4ocs5945x7etebzSwWaAZs2t9Gbhp1PA+8M5NQHQGwR0Yr2jRP4qPFP1Y7f3b/Xmzdtp3zJr3AeZNeYMxRR9A2JXmP74+Wkvwy4tPidh7Hp8ZRsjEyYJfklxPf0quLCRhxCTGUFlYAUJRXygc3LOXDP/7I+kVFEfeWFlWwNruQ9CMSD8gc8jZAm/TK49atIHfDnt+fW8v9h7SDH1dCzlooL4fpn8C6vOj1XdXezGHaR3DGZfDrP8LaPeznlrtgyFnefC4evf/9iohIw6etDgcB51yZmd0AvAuMcM6VmtnheFse6nKemQ0GMoDvgTd3U1+noT06kV9UzLdr8jiqU7saa8zgxlFDufWVaRHXju3WgUMzWjKiVzcAEps2oUPLFuRs2rJH9x9QNa0I1pTtDZqmxHLqo4fSJCmWTUtL+PS+lYz4W1fiEgIAhCocnz+4mq6nppHYuvbtIPujpp879mZRs8b7zVv9/dN4+O1fvOO+vWDVmn1uc+97qKHu+GPhtOEQDMKLb8DNd8LTD+5+/Dtv9rZT3P4QvDMDRp+63y2LiEgDp+B78BgJrAV6Ae/vetHMXgO6Ad8753asb73knBtnZgZMAm6gcstE1XvHAmMBbrnlFqBljQ307ZDJ8Yd1Zkj3jjSJjaVZkyB3n3sKN7387s6aZsEg3Vq35OmxYwBomdiMRy45nXHPTMUM7pz6X2YtWVFt3OtGHMvQ7p1mMeNvAAAgAElEQVQA+PnkV2q9P1ofcPNWeCu3IJTklxGfGvlHJT4tlpINZSSkxRGqcJQVhwgmBjAzAnHeX6akdImnWesghWtLSe0SD8BXj68hKSNIt9PSotJvTVq3qr4Sm7se0mv+batRm1bwxbzq9x/dx3t9wiDvC+DlqZHbJKJlT+eQ0rzy9Tmj4IHH9/w9AgFvf/CTLyr4ioj4gYLvQcDM+gAnAQOBT8zsRWAhcNyOGufcWWbWH7h/1/udc87M3sTbAxwRfJ1zk/H2DZOdne1ef/XjGvt48L1ZPPjeLACO6tSOS4/LqhZ6AbZuL2Xw7Y/tPH7qyjHc//ZMFubkMuv7FZw3oDefL11FeShEh5YtyCvYysPTPuXhaZ/uvKe2+6MlpWs8W9eWUpRbSnxqLKtmFXD0ryNXsDP6J7Hio82kdU8gZ/YW0ns1w8zYXlDuBeCAsTW3lK1rS0lM97ZEfPNCLmXFFWT9KjNq/dbkiB6wYjWsXuuFxbdnwH237fn9g46GCf+AgvDW5llzYPxY7/XGTZCW4l174Q3425+j3j6w53PI2wjp4Z8hZsyCzh3qHtc5WJkDHdp5rz/8FDofEv3+RUSk4VHwbeTCq7WPAr9xzq00s/vwwu0VwM1mdnqVfb51PbBpMLD0QPU57sRjWJiTy38XLau15tUvF5CZkswr116EAZuKSrj22am11h8oMQGjz+UZzLxjBS7k6HhCCs3DT3RY+GIeKV2aknlUMp2GpfDFxBzeGbeEYGKAAeO9cLx+UTHfvpSHBcBijH5jMwkmxVK8sYzFUzaQ1DbIB7/3fh26jkyl0/CUqM8hNhb+8Bu44nfekxhGnwrdvEVzHn4CevWAYYNgwSK49jbYUgj//RQmPgVv/dP7UNtVl3hPUgC4+ufeOYA7H4bvwt8pV/0cOrWPevt7NYfn/u0F3tiAtxXjrpsqx7h4HCxbCcUlcPwYuP333gf1br4LthZ5u1V6dIE//fbAzEFERBoWq+tT6NLwhbchDHfOnRc+DgBfAL/Fe7LD34Ae4deFwL3OuQ92eZxZDLAauNQ5V+dHg7Kzs90ltaz4NgbPjPEWwafE3VHPney70WW3AtC37QX13Mm+m5vzQqPuH7w5ZGUdgOe4/YSys7Mb9Ryys7MBNId6pjk0DOE/zw3iGTXDTro7auFyxvs3RXVOWvFt5KpuQwgfVwBV/+TWuHMx/HSHpw9kbyIiIiI/hfDC35dAjnNuVG11epyZiIiIiDR2v8b7n3HVScFXRERERBotM2sHnAb83+5qFXxFREREpDF7EPg9ENpdofb4ioiIiEjU5PZvErWxqv6/BMImhz/ftOP6KCDPOZdtZsfvbjwFXxERERFpkHb9EH8NBgGnm9mpQFMg2cyec85dXFOxtjqIiIiISKPknLvZOdfOOdcROB+YUVvoBQVfEREREfEJbXUQERERkUbPOfch8GFdNVrxFRERERFfUPAVEREREV9Q8BURERERX1DwFRERERFfUPAVEREREV9Q8BURERERX1DwFRERERFfUPAVEREREV9Q8BURERERX1DwFRERERFfMOdcffcgjUh2dra+YURERBqgrKwsq+8eAA6/eULUssLCu8ZHdU5a8RURERERX4it7wak8bnk1Y/ru4V99syY4wCYEndHPXey70aX3Qo0/jn0bXtBfbexX+bmvHBQzCErK6u+29hn2dnZAJpDPdMcGoYdc5C6acVXRERERHxBwVdEREREfEHBV0RERER8QcFXRERERHxBwVdEREREfEHBV0RERER8QcFXRERERHxBwVdEREREfEHBV0RERER8QcFXRERERHxBwVdEREREfEHBV0RERER8QcFXRERERHxBwVdEREREfEHBV0RERER8QcFXRERERHxBwVdEREREfEHBV0RERER8Iba+G5CDR5vmidx1zimkJSXgHLzyxQKe+3RuRF2nVincPmYEPTPTeWjapzw9M3uf3i+jeRJTx1/CpOmz93mMuqybW8i8p9bhQtBpeAt6nNUqoqaiLMSciTlsWraNYFKAgePb0Sw9SP6SYrIfXxuucvQ8J522A5L3eNz6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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.cm.get_cmap('viridis_r', 6) # 11 discrete colors\n", + "\n", + "fig, ax = plt.subplots(1, figsize=(12,9))\n", + "hmobj = sns.heatmap(df.loc[keep_rows, keep_cols].applymap(lambda x: -pd.np.log10(x)),\n", + " cmap=cmap, vmin=0, vmax=6,\n", + " cbar_kws={\"shrink\": 0.8},\n", + " linewidths=0.8,\n", + " linecolor=[0.8]*3,\n", + " square=True,\n", + " annot=dfstr.loc[keep_rows, keep_cols], \n", + " annot_kws = {'horizontalalignment':'center',},\n", + " fmt = 's',\n", + " ax=ax)\n", + "plt.yticks(rotation=0)\n", + "# plt.xticks(rotation=90)\n", + "pass\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\\nBonferroni-adjusted $\\\\alpha=0.05$ threshold = %.2f\" % thr_bonferroni)\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\")" + ] + }, + { + "cell_type": "code", + "execution_count": 265, + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"../tables/auroc_mcnemar_comparison-e5ce2d69b035975cb5336cec0da9a32a.csv\"\n", + "df = pd.read_csv(fn, index_col=0)\n", + "# df.drop('score_wire', axis=0, inplace=True)\n", + "# df.drop('score_wire', axis=1, inplace=True)\n", + "# df.drop('wire', axis=0, inplace=True)\n", + "# df.drop('wire', axis=1, inplace=True)\n", + "\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 266, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(10, 11)" + ] + }, + "execution_count": 266, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = df.rename(columns=modelnamemap, index=modelnamemap)\n", + "\n", + "df = df.loc[df.index.map(lambda x : 'avg(wire)' not in x).tolist(),\n", + " df.columns.map(lambda x : 'avg(wire)' not in x).tolist()]\n", + "\n", + "keep_rows = ~df.isnull().all(1)\n", + "keep_cols = ~df.isnull().all(0)\n", + "df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 267, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(10, 11)" + ] + }, + "execution_count": 267, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfstr = df.applymap(lambda x: ('{n:5.{s}{c}} '.format(n=x, c='e' if x < 1e-3 else 'f',\n", + " s = 3- 2*(x < 1e-3)\n", + " ).replace('-0','-').replace('nan',''))\n", + ")\n", + "dfstr.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 275, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# df\n", + "cmap = mpl.cm.get_cmap('viridis_r', 8) # 11 discrete colors\n", + "\n", + "fig, ax = plt.subplots(1, figsize=(12,9))\n", + "hmobj = sns.heatmap(df.loc[keep_rows, keep_cols].applymap(lambda x: -pd.np.log10(x)),\n", + " cmap=cmap, vmin=0, vmax=4,\n", + " cbar_kws={\"shrink\": 0.8, \"ticks\":np.arange(0,4.01)},\n", + " linewidths=0.8,\n", + " linecolor=[0.8]*3,\n", + " square=True,\n", + " annot=dfstr.loc[keep_rows, keep_cols], \n", + " annot_kws = {'horizontalalignment':'center',},\n", + " fmt = 's',\n", + " ax=ax)\n", + "plt.yticks(rotation=0)\n", + "# plt.xticks(rotation=90)\n", + "pass\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\\nBonferroni-adjusted $\\\\alpha=0.05$ threshold = %.2f\" % thr_bonferroni)\n", + "# ax.set_title(\"$-\\\\rm{log_{10}}$ p-value\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:anaconda3]", + "language": "python", + "name": "conda-env-anaconda3-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5ecf525 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,23 @@ +Cython==0.27.3 +h5py==2.7.0 +imgaug==0.2.5 +Keras==2.0.8 +-e git+https://github.com/raghakot/keras-vis@40b27dfa3ecb84cdde5ec6b44251923c3266cc40#egg=keras_vis +lime==0.1.1.29 +matplotlib==2.0.2 +mudicom==0.1.2 +numpy==1.14.0 +opencv-python==3.3.0.10 +pandas==0.20.2 +Pillow==4.1.1 +pyaml==17.7.2 +-e git+https://github.com/cocodataset/cocoapi/@727b546dd9fa4e4bb113213c98a3925829fac0bf#egg=pycocotools&subdirectory=PythonAPI +pydicom==0.9.9 +PyYAML==3.12 +scikit-image==0.13.0 +scikit-learn==0.18.1 +scipy==0.19.1 +seaborn==0.7.1 +sklearn==0.0 +tensorflow-gpu==1.4.1 +tensorflow-tensorboard==0.4.0rc3 diff --git a/visualize_predictions_hdr_and_img.ipynb b/visualize_predictions_hdr_and_img.ipynb new file mode 100644 index 0000000..d6317e9 --- /dev/null +++ b/visualize_predictions_hdr_and_img.ipynb @@ -0,0 +1,4772 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n", + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n", + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n", + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import os\n", + "from functools import partial\n", + "from matplotlib import pyplot as plt\n", + "import seaborn as sns\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from matplotlib.ticker import LogFormatter \n", + "from matplotlib.colors import LogNorm\n", + "from matplotlib import gridspec" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n", + "/Applications/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n", + " return f(*args, **kwds)\n" + ] + } + ], + "source": [ + "from sklearn.metrics import (auc, confusion_matrix, f1_score, accuracy_score, average_precision_score,\n", + " precision_score, roc_curve, precision_recall_curve, recall_score)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "tag = 'e5ce2d69b035975cb5336cec0da9a32a'\n", + "dfpred = pd.read_table(f'../tables/all_predictions_with_images-{tag}.tab')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "772423" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(dfpred)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "pred_cols = dfpred.columns.map(lambda x: x.startswith('score')).tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4189" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(~dfpred.view.isnull()).sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "eps = 0\n", + "dfpred[\"score_ViewModifier\"] = 1-( eps + (1-2*eps)*dfpred.ViewModifier.isnull().astype(float))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# dfpred" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0 692365\n", + "1.0 80058\n", + "Name: score_ViewModifier, dtype: int64" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[\"score_ViewModifier\"].map(str).value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idscore_gbmscore_xgbscore_rpartscore_gbmtViewModifiersetlabelviewscore_image...score_image*glmnetscore_image*gbmtscore_max_image_wirescore_max_image_wire_maxscore_max_image_wire+gbmtscore_max_image_wire_max+gbmtscore_max_wire_image+gbmtscore_max_wire_max_image+gbmtscore_max(image;wire_max;gbmt)score_ViewModifier
01000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0022260.0068820.045568NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455680.0
11000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0022260.0068820.045573NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227860.0227860.00.00.0455730.0
21000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0018410.0068820.045569NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455690.0
31000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0018410.0068820.045568NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455680.0
41000047594_1.2.840.113654.2.70.1.1921731705635...0.0014020.0038480.0068820.045498NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227490.0227490.00.00.0454980.0
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " id score_gbm score_xgb \\\n", + "0 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.002226 \n", + "1 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.002226 \n", + "2 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.001841 \n", + "3 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.001841 \n", + "4 1000047594_1.2.840.113654.2.70.1.1921731705635... 0.001402 0.003848 \n", + "\n", + " score_rpart score_gbmt ViewModifier set label view score_image \\\n", + "0 0.006882 0.045568 NaN NaN NaN NaN NaN \n", + "1 0.006882 0.045573 NaN NaN NaN NaN NaN \n", + "2 0.006882 0.045569 NaN NaN NaN NaN NaN \n", + "3 0.006882 0.045568 NaN NaN NaN NaN NaN \n", + "4 0.006882 0.045498 NaN NaN NaN NaN NaN \n", + "\n", + " ... score_image*glmnet score_image*gbmt \\\n", + "0 ... NaN NaN \n", + "1 ... NaN NaN \n", + "2 ... NaN NaN \n", + "3 ... NaN NaN \n", + "4 ... NaN NaN \n", + "\n", + " score_max_image_wire score_max_image_wire_max score_max_image_wire+gbmt \\\n", + "0 0.0 0.0 0.022784 \n", + "1 0.0 0.0 0.022786 \n", + "2 0.0 0.0 0.022784 \n", + "3 0.0 0.0 0.022784 \n", + "4 0.0 0.0 0.022749 \n", + "\n", + " score_max_image_wire_max+gbmt score_max_wire_image+gbmt \\\n", + "0 0.022784 0.0 \n", + "1 0.022786 0.0 \n", + "2 0.022784 0.0 \n", + "3 0.022784 0.0 \n", + "4 0.022749 0.0 \n", + "\n", + " score_max_wire_max_image+gbmt score_max(image;wire_max;gbmt) \\\n", + "0 0.0 0.045568 \n", + "1 0.0 0.045573 \n", + "2 0.0 0.045569 \n", + "3 0.0 0.045568 \n", + "4 0.0 0.045498 \n", + "\n", + " score_ViewModifier \n", + "0 0.0 \n", + "1 0.0 \n", + "2 0.0 \n", + "3 0.0 \n", + "4 0.0 \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "dfpredthr = dfpred.iloc[:,pred_cols] > 0.5\n", + "dfpredthr[\"label\"] = dfpred[\"label\"] == \"special\"\n", + "dfpredthr[\"set\"] = dfpred[\"set\"]\n", + "dfpredthr[\"view\"] = dfpred[\"view\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def bool_to_sn(x):\n", + " return {True:\"special\", False:\"normal\"}[x]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# dfpred['score_image_glmnet']\n", + "# pd.crosstab(dfpred['label'][mask], \n", + "# vv[mask].map(lambda x: {True:\"special\", False:\"normal\"}[x])\n", + "# ))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==============================\n", + "score_gbm normal special\n", + "label \n", + "normal 2309 1\n", + "special 42 396\n", + "==============================\n", + "score_xgb normal special\n", + "label \n", + "normal 2309 1\n", + "special 47 391\n", + "==============================\n", + "score_rpart normal special\n", + "label \n", + "normal 2309 1\n", + "special 49 389\n", + "==============================\n", + "score_gbmt normal special\n", + "label \n", + "normal 2309 1\n", + "special 43 395\n", + "==============================\n", + "score_image normal special\n", + "label \n", + "normal 2310 0\n", + "special 5 433\n", + "==============================\n", + "score_image_max normal special\n", + "label \n", + "normal 2310 0\n", + "special 3 435\n", + "==============================\n", + "score_glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 43 395\n", + "==============================\n", + "score_wire normal special\n", + "label \n", + "normal 2310 0\n", + "special 401 37\n", + "==============================\n", + "score_wire_max normal special\n", + "label \n", + "normal 2307 3\n", + "special 401 37\n", + "==============================\n", + "score_image+glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 33 405\n", + "==============================\n", + "score_image+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 27 411\n", + "==============================\n", + "score_max(image;gbmt) normal special\n", + "label \n", + "normal 2309 1\n", + "special 5 433\n", + "==============================\n", + "score_image*glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 43 395\n", + "==============================\n", + "score_image*gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 42 396\n", + "==============================\n", + "score_max_image_wire normal special\n", + "label \n", + "normal 2310 0\n", + "special 0 438\n", + "==============================\n", + "score_max_image_wire_max normal special\n", + "label \n", + "normal 2307 3\n", + "special 0 438\n", + "==============================\n", + "score_max_image_wire+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 3 435\n", + "==============================\n", + "score_max_image_wire_max+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 2 436\n", + "==============================\n", + "score_max_wire_image+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 2 436\n", + "==============================\n", + "score_max_wire_max_image+gbmt normal special\n", + "label \n", + "normal 2307 3\n", + "special 2 436\n", + "==============================\n", + "score_max(image;wire_max;gbmt) normal special\n", + "label \n", + "normal 2306 4\n", + "special 0 438\n" + ] + } + ], + "source": [ + "for cc,vv in dfpredthr.items():\n", + " mask = dfpred['set'] == 'train'\n", + " if cc in (\"label\", \"view\", \"set\"):\n", + " continue\n", + " print('='*30)\n", + " print(pd.crosstab(dfpred['label'][mask], vv[mask].map(lambda x: {True:\"special\", False:\"normal\"}[x])))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# dfpredthr" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:2: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " from ipykernel import kernelapp as app\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idscore_gbmscore_xgbscore_rpartscore_gbmtViewModifiersetlabelviewscore_image...score_image*glmnetscore_image*gbmtscore_max_image_wirescore_max_image_wire_maxscore_max_image_wire+gbmtscore_max_image_wire_max+gbmtscore_max_wire_image+gbmtscore_max_wire_max_image+gbmtscore_max(image;wire_max;gbmt)score_ViewModifier
2238161889161318_1.2.840.113654.2.70.1.1381752400528...0.5856680.8733590.9565220.806164spot compressiontrainnormalN0.000013...0.0020660.0032590.0000130.0000130.4030890.4030890.4030890.4030890.8061641.0
\n", + "

1 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " id score_gbm \\\n", + "223816 1889161318_1.2.840.113654.2.70.1.1381752400528... 0.585668 \n", + "\n", + " score_xgb score_rpart score_gbmt ViewModifier set label \\\n", + "223816 0.873359 0.956522 0.806164 spot compression train normal \n", + "\n", + " view score_image ... score_image*glmnet \\\n", + "223816 N 0.000013 ... 0.002066 \n", + "\n", + " score_image*gbmt score_max_image_wire score_max_image_wire_max \\\n", + "223816 0.003259 0.000013 0.000013 \n", + "\n", + " score_max_image_wire+gbmt score_max_image_wire_max+gbmt \\\n", + "223816 0.403089 0.403089 \n", + "\n", + " score_max_wire_image+gbmt score_max_wire_max_image+gbmt \\\n", + "223816 0.403089 0.403089 \n", + "\n", + " score_max(image;wire_max;gbmt) score_ViewModifier \n", + "223816 0.806164 1.0 \n", + "\n", + "[1 rows x 28 columns]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[((dfpredthr['label'] != dfpredthr['score_gbm']) & \n", + " (~dfpredthr['label']))][mask]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# dfpred[((dfpredthr['label'] != dfpredthr['score_gbm']) & \n", + "# (dfpredthr['label']))][mask]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==============================\n", + "TEST\n", + "==============================\n", + "score_gbm normal special\n", + "label \n", + "normal 612 0\n", + "special 13 101\n", + "==============================\n", + "score_xgb normal special\n", + "label \n", + "normal 612 0\n", + "special 13 101\n", + "==============================\n", + "score_rpart normal special\n", + "label \n", + "normal 612 0\n", + "special 13 101\n", + "==============================\n", + "score_gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 13 101\n", + "==============================\n", + "score_image normal special\n", + "label \n", + "normal 610 2\n", + "special 7 107\n", + "==============================\n", + "score_image_max normal special\n", + "label \n", + "normal 609 3\n", + "special 7 107\n", + "==============================\n", + "score_glmnet normal special\n", + "label \n", + "normal 612 0\n", + "special 13 101\n", + "==============================\n", + "score_wire normal special\n", + "label \n", + "normal 612 0\n", + "special 104 10\n", + "==============================\n", + "score_wire_max normal special\n", + "label \n", + "normal 612 0\n", + "special 103 11\n", + "==============================\n", + "score_image+glmnet normal special\n", + "label \n", + "normal 612 0\n", + "special 11 103\n", + "==============================\n", + "score_image+gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 10 104\n", + "==============================\n", + "score_max(image;gbmt) normal special\n", + "label \n", + "normal 610 2\n", + "special 6 108\n", + "==============================\n", + "score_image*glmnet normal special\n", + "label \n", + "normal 612 0\n", + "special 14 100\n", + "==============================\n", + "score_image*gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 12 102\n", + "==============================\n", + "score_max_image_wire normal special\n", + "label \n", + "normal 610 2\n", + "special 1 113\n", + "==============================\n", + "score_max_image_wire_max normal special\n", + "label \n", + "normal 610 2\n", + "special 1 113\n", + "==============================\n", + "score_max_image_wire+gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 4 110\n", + "==============================\n", + "score_max_image_wire_max+gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 2 112\n", + "==============================\n", + "score_max_wire_image+gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 2 112\n", + "==============================\n", + "score_max_wire_max_image+gbmt normal special\n", + "label \n", + "normal 612 0\n", + "special 2 112\n", + "==============================\n", + "score_max(image;wire_max;gbmt) normal special\n", + "label \n", + "normal 610 2\n", + "special 0 114\n" + ] + } + ], + "source": [ + "print('='*30)\n", + "print(\"TEST\")\n", + "for cc,vv in dfpredthr.items():\n", + " if cc in (\"label\", \"view\", \"set\"):\n", + " continue\n", + " mask = dfpred['set'] == 'test'\n", + " print('='*30)\n", + " print(pd.crosstab(dfpred['label'][mask], vv[mask].map(lambda x: {True:\"special\", False:\"normal\"}[x])))" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==============================\n", + "VAL\n", + "==============================\n", + "score_gbm normal special\n", + "label \n", + "normal 604 0\n", + "special 13 98\n", + "==============================\n", + "score_xgb normal special\n", + "label \n", + "normal 604 0\n", + "special 14 97\n", + "==============================\n", + "score_rpart normal special\n", + "label \n", + "normal 604 0\n", + "special 14 97\n", + "==============================\n", + "score_gbmt normal special\n", + "label \n", + "normal 604 0\n", + "special 13 98\n", + "==============================\n", + "score_image normal special\n", + "label \n", + "normal 603 1\n", + "special 11 100\n", + "==============================\n", + "score_image_max normal special\n", + "label \n", + "normal 603 1\n", + "special 11 100\n", + "==============================\n", + "score_glmnet normal special\n", + "label \n", + "normal 604 0\n", + "special 13 98\n", + "==============================\n", + "score_wire normal special\n", + "label \n", + "normal 603 1\n", + "special 103 8\n", + "==============================\n", + "score_wire_max normal special\n", + "label \n", + "normal 603 1\n", + "special 103 8\n", + "==============================\n", + "score_image+glmnet normal special\n", + "label \n", + "normal 603 1\n", + "special 11 100\n", + "==============================\n", + "score_image+gbmt normal special\n", + "label \n", + "normal 603 1\n", + "special 11 100\n", + "==============================\n", + "score_max(image;gbmt) normal special\n", + "label \n", + "normal 603 1\n", + "special 10 101\n", + "==============================\n", + "score_image*glmnet normal special\n", + "label \n", + "normal 604 0\n", + "special 14 97\n", + "==============================\n", + "score_image*gbmt normal special\n", + "label \n", + "normal 604 0\n", + "special 14 97\n", + "==============================\n", + "score_max_image_wire normal special\n", + "label \n", + "normal 602 2\n", + "special 3 108\n", + "==============================\n", + "score_max_image_wire_max normal special\n", + "label \n", + "normal 602 2\n", + "special 3 108\n", + "==============================\n", + "score_max_image_wire+gbmt normal special\n", + "label \n", + "normal 603 1\n", + "special 3 108\n", + "==============================\n", + "score_max_image_wire_max+gbmt normal special\n", + "label \n", + "normal 602 2\n", + "special 3 108\n", + "==============================\n", + "score_max_wire_image+gbmt normal special\n", + "label \n", + "normal 602 2\n", + "special 3 108\n", + "==============================\n", + "score_max_wire_max_image+gbmt normal special\n", + "label \n", + "normal 602 2\n", + "special 3 108\n", + "==============================\n", + "score_max(image;wire_max;gbmt) normal special\n", + "label \n", + "normal 602 2\n", + "special 2 109\n" + ] + } + ], + "source": [ + "print('='*30)\n", + "print(\"VAL\")\n", + "for cc,vv in dfpredthr.items():\n", + " if cc in (\"label\", \"view\", \"set\"):\n", + " continue\n", + " mask = dfpred['set'] == 'val'\n", + " print('='*30)\n", + " print(pd.crosstab(dfpred['label'][mask], vv[mask].map(lambda x: {True:\"special\", False:\"normal\"}[x])))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
score_xgbnormalspecial
score_image
normal6131
special596
\n", + "
" + ], + "text/plain": [ + "score_xgb normal special\n", + "score_image \n", + "normal 613 1\n", + "special 5 96" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpredthr['score_image'][mask].map(bool_to_sn),\n", + " dfpredthr['score_xgb'][mask].map(bool_to_sn))" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
score_glmnetnormalspecial
score_image
normal6131
special497
\n", + "
" + ], + "text/plain": [ + "score_glmnet normal special\n", + "score_image \n", + "normal 613 1\n", + "special 4 97" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpredthr['score_image'][mask].map(bool_to_sn),\n", + " dfpredthr['score_glmnet'][mask].map(bool_to_sn))" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "THR = 0.5\n", + "# dfpred[(dfpred['score_image']>THR) != (dfpred['label']==\"special\")][dfpred[\"set\"] == \"test\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==============================\n", + "score_gbm normal special\n", + "label \n", + "normal 2309 1\n", + "special 42 396\n", + "==============================\n", + "score_xgb normal special\n", + "label \n", + "normal 2309 1\n", + "special 47 391\n", + "==============================\n", + "score_rpart normal special\n", + "label \n", + "normal 2309 1\n", + "special 49 389\n", + "==============================\n", + "score_gbmt normal special\n", + "label \n", + "normal 2309 1\n", + "special 43 395\n", + "==============================\n", + "score_image normal special\n", + "label \n", + "normal 2310 0\n", + "special 5 433\n", + "==============================\n", + "score_image_max normal special\n", + "label \n", + "normal 2310 0\n", + "special 3 435\n", + "==============================\n", + "score_glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 43 395\n", + "==============================\n", + "score_wire normal special\n", + "label \n", + "normal 2310 0\n", + "special 401 37\n", + "==============================\n", + "score_wire_max normal special\n", + "label \n", + "normal 2307 3\n", + "special 401 37\n", + "==============================\n", + "score_image+glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 33 405\n", + "==============================\n", + "score_image+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 27 411\n", + "==============================\n", + "score_max(image;gbmt) normal special\n", + "label \n", + "normal 2309 1\n", + "special 5 433\n", + "==============================\n", + "score_image*glmnet normal special\n", + "label \n", + "normal 2310 0\n", + "special 43 395\n", + "==============================\n", + "score_image*gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 42 396\n", + "==============================\n", + "score_max_image_wire normal special\n", + "label \n", + "normal 2310 0\n", + "special 0 438\n", + "==============================\n", + "score_max_image_wire_max normal special\n", + "label \n", + "normal 2307 3\n", + "special 0 438\n", + "==============================\n", + "score_max_image_wire+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 3 435\n", + "==============================\n", + "score_max_image_wire_max+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 2 436\n", + "==============================\n", + "score_max_wire_image+gbmt normal special\n", + "label \n", + "normal 2310 0\n", + "special 2 436\n", + "==============================\n", + "score_max_wire_max_image+gbmt normal special\n", + "label \n", + "normal 2307 3\n", + "special 2 436\n", + "==============================\n", + "score_max(image;wire_max;gbmt) normal special\n", + "label \n", + "normal 2306 4\n", + "special 0 438\n" + ] + } + ], + "source": [ + "for cc,vv in dfpredthr.items():\n", + " if cc in ('label', \"set\", 'view'):\n", + " continue\n", + " mask = dfpred['set'] == 'train'\n", + " print('='*30)\n", + " print(pd.crosstab(dfpred['label'][mask], vv[mask].map(lambda x: {True:\"special\", False:\"normal\"}[x])))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def colordictmap(x):\n", + " if x is np.nan:\n", + " return [0.5]*3\n", + " if x=='special':\n", + " return 'orange'\n", + " elif x=='normal':\n", + " return 'b'\n", + " else:\n", + " return 'k'" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGDCAYAAADEegxVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzs3Xl4G/d94P/3B4PBDMBLEihREiSRlixbliw5liUzlu3EztGmzdHdtL9uvb27bdptuz3StE12k7o52mzztGn7bNMj3fRIm7RN223j5mguK45TxzQlWZYiW7YuUiIkUSIogiQwAAaD7+8PHCLFCzpAiuLn9Tx8SMx8Z+YD2JoPvueIMQallFIKILTQASillLp5aFJQSilVo0lBKaVUjSYFpZRSNZoUlFJK1WhSUEopVaNJQd10RKRLRIyIhCuvvygiP3oN59kgIuMiYt34KBcXEfkrEfnQQsehbn6aFNQ1EZE+EfEqN91BEflLEWluxLWMMd9ljPnrOmN6w4TjThtjmo0xQSPiUupWpElBXY+3GmOagZ3AbuC9VxaQMv3/bJ5Ua1dKXSv9x6qumzEmCXwRuBtARL4uIr8lIv8BZIGNItImIp8QkXMikhSRD1WbdUTEEpHfFZEhETkJvHni+Svn+8kJr39KRF4SkTEReVFEdorI3wAbgH+r1F5+bZpmqLUi8oSIDIvIcRH5qQnn/E0R+YyIfLJy3iMismum9ywi20TkK5VzDYrI/6xsd0TkD0TkbOXnD0TEqex7REQGRORXRORC5bP48QnnjIrI74lIv4ikReSbIhKt7HtbJaaRyudx14Tj+kTk10XkEJARkbCI3CsiByrv5R8Ad0L55SLyORG5KCKXKn+vu+Lz/qCI/Efl+C+LSPuE/Q+JyDOVWM6IyI9NeO+/KyKnK5/Jn1bjV4uHJgV13URkPfDdwPMTNv8w8A6gBegH/hooArcD9wLfAVRv9D8FvKWyfRfwfbNc6/8DfhP4EaAVeBuQMsb8MHCaSu3FGPORaQ7/O2AAWFu5xm+LyOsn7H8b8PfAMuAJ4I9miKEF+Crw75Vz3Q58rbL7fwGvBl4F3APcz+Qa1GqgDUgA/w34mIgsr+z7XeA+YA+wAvg1oCQid1Ri/yVgJfAFyskvMuG8j1FOpsso/7v+V+BvKuf5R+B7J5QNAX8JdFJOpN407/W/Aj8OrAIiwLsq730D5S8A/6cSy6uAg5Vjfge4o7Lt9sp7/I3pPkN1EzPG6I/+XPUP0AeMAyOUb/p/DEQr+74OfGBC2Q4gX91f2fYYsLfy95PAz0zY9x2AAcITzveTlb+/BPziLDG9YcLrrup5gPVAALRM2P9h4K8qf/8m8NUJ+7YC3gzXeQx4foZ9J4DvnvD6O4G+yt+PUL4Bhyfsv0A5iYQq++6Z5pzvAz4z4XUISAKPTHjfPzFh/2uAs4BM2PYM8KEZYn4VcGnC668D753w+meBf6/8/R7gX6Y5hwAZYNOEbQ8Apxb6/1X9ubofbX9U1+M/GWO+OsO+MxP+7gRs4JyIVLeFJpRZe0X5/lmuuZ7yjfdqrQWGjTFjV1xnYhPR+Ql/ZwFXRMLGmOJVxLCWyfH3V7ZVpa44XxZoBtopN/FMd95J5zTGlETkDOVv4lVnriifNJU784Q4ABCRGPD7wJuAai2lRUQsc7lT/srPojqIYKb3vhKIAfsn/DcWYMmP/FpstPlINcrEG9IZyjWFdmPMsspPqzFmW2X/Oco3m6oNs5z3DLCpjmte6SywotL0M/E6yVmOuZYYzlJOghOvcbaOcw4BuRnOO+mcUr7rrmdy7BPf+zkgIRPuzkz+TH8FuBPoNsa0Uq5ZQPkmPpeZ3vsQ5ZrOtgn/jdtMeSCCWkQ0KaiGM8acA74M/J6ItIpISEQ2ichrK0U+A/yCiKyrtK+/e5bT/V/gXSJyX3lgk9wuItUb5iCwcYYYzlBuQvmwiLgisoNym/6nruEtfQ5YLSK/VOlcbRGR7sq+vwPeKyIrK52zvwH87VwnNMaUgL8APlrpELdE5IFKJ/VngDeLyOtFxKZ8U89X3s90vkW5/+YXKp3Ob6fct1HVQvkGPiIiK4DHr+K9fwp4g4h8f+XccRF5VSX+Pwd+X0RWAYhIQkS+8yrOrW4CmhTUfPkRyh2WLwKXgH8C1lT2/TnlvoIXgAPA/5vpJMaYfwR+C/g0MEa5Q3VFZfeHKd+QR0TkXdMc/hjlfoazwL8AjxtjvnK1b6TSBPVG4K2Um1mOAY9Wdn8I2AccAg5X3k+9k8beVTmmFxim3HEbMsa8DPwQ5c7docp132qMKcwQXwF4O/BjlD/r/8Lkz/QPgGjlXM9S7jCvizHmNOVBBb9SifEg5Q51gF8HjgPPisgo5c74O+s9t7o5yORmR6WUUkuZ1hSUUkrVaFJQSilVo0lBKaVUjSYFpZRSNZoUlFJK1Sy6Gc3t7e2mq6trocNQSqlFZf/+/UPGmJVzlVt0SaGrq4t9+/YtdBhKKbWoiMhsy8fUaPORUkqpGk0KSimlajQpKKWUqtGkoJRSqkaTglJKqRpNCkoppWo0KSillKrRpKCUUqpGk4JSSqkaTQpKKaVqNCkopZSq0aSglFI3m2Kxvm0N0LAF8UTkL4C3ABeMMXdPs1+AP6T8EPAs8GPGmAONikcpdfPIZrOkUilyuRyu6xKPx4nFYtdcbtHLXYRiBoDgidswRfiT02/El7sJU+Bn138MgPDuF+CuHQ0NpZGrpP4V8EfAJ2fY/13A5spPN/Anld9KqVtYNpslmUxi2zaxWAzf90kmkyQSiUk3/HrLNUSQg1AEZEJjStEDyyXredeUqLLZLKmL58kVgtpxtm3z8tFvkzz0r5BNcmfpE6yPgQj8bOdX+NyFAd6y6qXaOT7wme/iNx5PNuId1zQsKRhjviEiXbMU+R7gk8YYAzwrIstEZI0x5lyjYlJKLbxUKoVt2ziOA1D7nUqlJt1c6y03l2ptI51Ok06n8X0fx3Fob2/nwIEDHD16tFY2FAqxaWMXr9mc48xgmi8fGANC2JLn7pVDdG55gK8eGGZ8fLx2TEdHB5s3b+bChQsEQUAsFkNEKJVKlEolisUi6XSaUvoV2iNDnMp2kiuWb70rIxdoC6fp8zr56ZWfoMmZHPvEhFAqgeEddb/va7WQz1NIAGcmvB6obJuSFETkHVD+NDZs2DAvwSmlGiOXy025qdu2TTabvaZys6nWNkqlEkNDQ4yOjhIKhbBtmy9/+csMDQ1NKl8qlejrP0P67DDtodOsd1sYLKyiM9pPNmP44jdfJl+KTjpmcHCQwcFBotEohUKBIAgAsCwLy7IIgoAgCHBCEVZYPuudE/QFXSyz06yMXGTEX8Yvrvttovbs7+V/97237vd9PRYyKcg028x0BY0xHwc+DrBr165pyyil6uP7PtlsFt/3a00ztj3zHalafmxsjNHRUUSE5ubmWZtNfN/npZde4oUXXiCXy9Ha2squXbvYtGkTruvWvq0DjI+Pk0wm8X0f3/dJJBK0tbVNKVc9r+u6db/Xam1jZGSEbDZLsVis/YwOD7DaGSYwFpmgiWzQjBvyaJNzmCJckmUst0doCY9RMiFOeV1TEsJEpVKplhCAWjKo7bda6fM66Yr2s7npOAAj/jLO5tfyl2e+j/9+2z8h090VAWMgzGEK3Fv3e79WC5kUBoD1E16vA84uUCxKLQm+75NOp7Esi0gkQhAEpNNp2trapk0M1fK+7zM0NIRlWYgI+Xx+xvZ93/c5fPgwvb29uK5Lc3Mz2WyWvXv3ArBmzRqSyXK7eD6fp6+vj1AoREdHB0EQcOzYMTZv3kw8Hq+Vs227ljRWrVo16XrV5qGLFy9y4cIFwuEwbW1tbNy4kVwux8DAAPv27ZtSw1huZ1lhp2gOjzPqtzJY6GBVZIjW8AheECPlr6iVDYxFvnRF284VCoXCnJ9/vhQlG8RoCY8BcLHQDggFq5PPX9zDW1Y9M+1xIvCrt32W3zoVmfMa12shh6Q+AfyIlL0aSGt/glKNlc1msSyLcDiMiBAOh7Esa8YmmWr50dFRIpEI0WgU27YplUrYtk0qlZr2mBdffJFoNEpLSwuO49Da2opt2xw4cIBYLEYikcCyLJLJJK7rsnbtWmKxGNFoFMdxSCaTk8pV45ipM/rSpUsMDAxQLBYpFArkcjkOHTrEyy+/TE9Pz7Tv75K/gvP5NWSLTbRHhtjZeoBVkfPkSlGG/eU0hzMExuKSvxw75LPeHQBKM3625e7RmRWLRVZGLtASHsMLXAJj0RXrw5Y8beE06WATpZlPXzF90riRGjkk9e+AR4B2ERkAHgdsAGPMnwJfoDwc9TjlIak/3qhYlFJlvu8TiUz+tmlZ1ozfcqvlc7kc0Wi56SQUClEsFmds3/d9H8/zaG1tnbQ9EonUOmhjsRixWIwLFy7Q3NyMZVmzlptJtXmov78f13VxHIcgCCgWi7iuy4EDs49yH/bbiYZyAKx1zzJSXE6m2EST5RHC0Od1ki9FyZVc1jjnWOOc41w+Mes5q6r9CVUrwhdrfQhn82txQjm6ov10xfo4mb2NX+/8bUKzfE0vleDxxwfquvb1aOToo8fm2G+An2vU9ZVSU9m2TRAEhMOX/+kHQTBjn0K1vOu6FItFIpEIpVIJy7JmbN+3bZtoNEo+n5903kKhQHNz86Sy1c7ZasKplpv4ejbVzuiJSUtE8H2fZcuWUSgUcByHfD4/7fFuyKM5PE5reBSAtnAavxTmkr+CkeKyWh/CJX8FJSN4QX2jnkSklhBaW1splUqMZfJYUuRCoQMQ8qUofV4nreExfnnd5IRwfhw6mpjUx/A7/e/lfXVd/frojGallpBYLFb7Jm2MoVgs1oZRzla+tbWVQqGA53n4vk8oFML3feLx+LTHbN26Fc/zGBsbI5/PMzo6iu/77Ny5c1LZRCJBPp/H8zyCIMDzPPL5PIlEfd/Gq53RruvWbsLGGGzbrs0jCM3w9dsNeXRG+2kNjzAWtHAq28WIv4xWe5Tl9jCWBJPKp4vLKZjZ+xWqJjYljY6OMj4+TsE4XCisZuIYm3wpysXCKn7vzE9SLJYnLZ8fj/J/L/wmf3Lq+2rbTqWX8b7HP1jXta+XzNUOdrPZtWuX2bdv30KHodSitdCjj66UTqdJJpN4nkc0Gq2NPqpHtU/B87xah3UoFKKlpYVisYjjOHzrW9+aNK+gqi18iVWRQUBIF9u4UFjNCnuIeCSFMXDJj5Py2+uKo1GamprYsmULb3nLW677XCKy3xiza65yCzn6SCm1AGzbrvumO7H81R6zY8cOduyYe0mGqz33RNXO6FQqRbFYrI0+cl2XjRs3Eo/HaW5u5plnnmFwcHDSsUVnHfe86Sf453/+Z0yl0WTYb+eSv4JVq1aRujA03SXnjeu6rFixgo6Ojnm9riYFpdSiVu2MXr9+/bT750pO2+6eum///v0cPny4NtoK4MiRI5Qqw4NEZM7RRtfLsixaWlrYuHFjQ69zJU0KSqlFq9r0dPz4cc6cOVPr/9i9ezfbtm3D931OnDjBt7/9bQYHB2tNVGvWrOGee+4hHA7zxS9+cVItorOzk66uLvr7+2e8bjUhREI5CqXJne3TbZuJJUUCE56yLRSOsnr1avbs2TNtv00jaVJQSi1K6XSaY8eOceHCBV555RXC4TChUIhCocDevXsJggAR4fnnnyeTyZBOpwmFQmQyGc6fP8+5c+dqk/Mm6u/vnzUhVLVYo6yPnuFsbi0jxeUAtEcusDJykb7sbXil2UcqRUNZOqP9nM2vZbRYbj5bEfW4e02W9rseZdPWVy/IirCaFJRSi1IymcRxHPr6+nAch2g0WksEjuPw3HPPsXLlSkKhUG3IqmVZFIvF2hDV0dHRq7yqqfyEGA+aGS82s9ZNQs4QDvmsigwx4i/DK0WBIuUBnhNHPxWp3nZzJYdiqIXNK4Zp2vAqOrtuI26Ogb2cWNersZ2FWSJch6QqpRYlz/OIRCLk8/na5LdQKFSbV5HJZPA8DyjPxQiFQogIIlIbknu11jjnWO+eAUoYQpzJrcMNeWxveYG7m49gDJzNr+GO2It8z6p/YUfzQZaFLwGGu5tf4G2rPkcsVF7iwmBxYmwNVrQDhnpwRvdToJlS+4Nkc/6N+piumiYFpdSiVJ34Vp3FDNQm1uVyOZqammoT2izLolQqYYzBGFNb5gMgLFNnc0+3DcALXFrC46x3zyCUWOueZYU9jBvKUTQWbeFL3NvyPE3WOKsiQ9zbdpBWa5jXr/gK21sOkw3cSWsoGSyy1mqCoEjJGAr2Giy7PPdioWhSUEotStWJb11dXeTzecbHx8nn8xhjyOfz3H///WzcuJF8Pl9eFXV0lEuXLjE2NkYul6NYLNIaHuH22HGarLHaedvti9weO0GksvzFRCPFFZzNraElPM5dzS+xzh0gMBZeqYlsEMUJ5dkUO84dzSfo99ZTCMJ8x8qv0hXrI1VYzt7U6wi4vMxIizXK8tJxSlYLJtyK671Iabx/1nkjjaZJQSm1KLW1tbF582a6urq44447ajfSSCTCo48+yo4dO1i1ahUtLS21hfmqWltbueuuuxgvNlMwDhuiZ2iyxmi3L7LKucBosYXCDKuiVjuVo6EsbeE0L2fu5Oj4FnKl8sN17FCBfBAhW2qhYFwMQjaIcmB016SEEA1lWBc9w1g+jLX2DeSX7cGKdhAa7q01MS0E7WhWSi1a1YlvW7dunXb/6dOnWb9+PVu2bOHEiRO1JiTLstiwYQP79++nL9tJV6yfzuhpAEb8Ns7mE8z0yJeEW16ULl1sIyQlLAkY8uOsds4TosRYsZUz+XVsbXqJtnCaYX85IDy84mmeHHod6aC8JLdXipIqtHPP1rezJrGBaDSKOA8TDfqxm9Y04NOqjyYFpdQtK5vN1lZrLRQKuK6LMaa2KmwoFKJUCpMpNuFGys1F5eGh0z/tJuEkaQuPMpjvIOW3syw8zFr3LDtbnqfNHiEkJQbzHdzmnmK5PUyhFOFkdiPnc6vpXt7D69qf5CtDb2Q8aKOlpQ2JrWHPQ6+94irzOy/hStp8pJS6ZVVXUIVys1L1qWvVpqZoNEq7fZF4JMVYsZlcyWF9pSlpOmNBcy0hQLmPwS+FCUmR8/nV7E/vBBEKxuaMt56vDL2BbKmJmJ3j2UvdXMivJFtZabVUKtHd3T0Pn8LV0ZqCUuqWtXHjRg4dOgTAypUrOXnyJABdXV1kMhk2xEtYIymG8+UmoxABXbF+NkTPcC63GkOIdHFZ7XyBCWPM5O/SQ/5K0sXlXCh0EJYCg/nVnPHW4xublL8SW/Kscc5z3k+QHOkCoKOjg+7ubu69t/GP17xamhSUUreseDzOjh07OHnyJIVCgc7OToDasNQH3/hf6D8c5/TRNOTHKBFmJHIP9925gs7iCOMXX+Hw2Uuki8tpssa5N5GhY/2dpN37iDgOK1euJJFILOhooRtNk4JS6pYWj8dnXT9o+YrHWLNlkHQ6TTgcpr29nXg8zmj6Emdf+Ede3XQSE2sjsbyNcHQ5F2UrnSvX0NLSMuey44uRJgWl1IKp99kOV/sMiKsRi8W47bbbpmyPt68iu/nNdLR9vnatXPsjtPnlCXDXutz3zU47mpVSC6K6GF2pVKo95jOdTk+ZzVtvuYbEOH4Oa8KjS638YO2pbrcqTQpKqQWRzWaxLKu25EQ4HMayLLLZ7DWVu+G8QVrzh/CJkYu/gVJkJfbYQczYqWmfTX2r0KSglFoQvu/XFrKrsixr2ppCPeVuuEwfzcvXMhbdSb4YItdyHznaIHOK+IoVjb32AtI+BaXUgrBtmyAICE9ongmCYEpfQb3lbrj4btzlRRL5IqlUiqyXw13eTXzFCmJNTY299gLSpKCUWhCxWKz2gBvLsgiCgCAIaG5uvqZyN5yEwIoQi0UW5GE3C0WTglJqQdi2TVtbG9lslkKhgG3bNDc3T1tTqKfcopUdgAvfhCAPnY9BOALjp+BiD1CEzh+A0PzdqjUpKKUWTPWGf6PKLUrn98KpT3L61Eu8kvkkL47fxQPLv8U6d4ChQjtfTz3L//hffzRv4ci1PH1oIe3atcvs27dvocNQStUhmUxy+PBhRkdHERHWr19PIpEgHo9P2yTz9NNP09PTQz6fx3Ecuru7efjhhyeVOXLkCL29vWQyGZqamti9ezfbtm2br7d045WKfP4P38bW5iM4oRwlLCwJGPGX8c1LD3E2vwGAxx9//LouIyL7jTG75iqno4+UUg2RTCZ55plnKBQKtZVJX3nlFQYHB0kmk1OGlD799NM89dRTFItFHMehWCzy1FNP8fTTT9fKHDlyhL179+L7Pq2trfi+z969ezly5Mh8v70bJxRm3+guTnudBISJhjzGi808O/JALSHMazjzfkWl1K0t/SL4Yxw+fLj8OExjWBkZZEWrQzQa5fTp09i2TWrwNDz/bki/AkBPTw/RcIE3xL/KcneMpqYmwuEwzz/3dRj4Nxj8Br29vTiOQ3tLiC7rIJ3NgziOw8HevdD/zzDUC6XKUNXcRTjzL3DhWbj4LKQOQKn82E6CHAztg+GDYEoL8zlN0BYepSk8TqTyGFA3lGe9e4YQxXmPRfsUlFoiTpw4wYEDBzh+/HjteQIAO3fu5K1vfeuU8l/84hd57rnnZj2n4zi8+93vrr3+0Afey6ZYeSXSvmwXBRNhjXOO5fYlzuc7GJe1rF+/Htu2eeqfPsJDzU9Q6P1HPn/huyiUmnnLys8RDw2TLMQ4OHYfTU1N2IXT7HviXwlLETN6L8OFDtZnDhKPnmEgt5azIw+ybdUYz33urwlJiaPjd3E+38HOtgO0R4YYzK/ijW98E3u/+gX6vU6S+bXcFu0j4SZJ+XHe/vN/wZ/95T9w/vz52vtYvXo1P/3TP329H3l9xk/x4PKnSbhJhv0VDBdWsNY9yx1NLwPwrZE9lObxVq19CkotASdOnOCpp55ieHiYTCYzZf+ViaGehFBVTQzvf//7AYiEcnRF+wFDoeQQs7JcLLRzsdBRKx+JRBgbG+P26Es8HP8mxVKYognTZGU5PLadnvSrudyQYVjjJLmvdT+OlccLojRZWc7m1tAz8mqKRADDbdGT3NX8InbIRzCEKDGQS/BSZhsWJW5vOkazNU7RWNhSZNhfwbHsHWSD6ecczFtiOPVpXvryBygBz1x6kLP5BLta97G56Ri5ksNTqUcZLrZrn4JS6sY5cOAAjuNMmxCq+yfav39/3efO5/OTXhdKLn1eJ2EJiFlZRouttYRQLT82Vn6IzXHvLnpG7scJ5WmyMpzyuq5ICADCuXyCI+NbscWnNTzKWLF5QkIolznlbaQv20VQsnBDOc7l1vBK5i7Gim2MFJfTl70NL4gSszxGiss4nr19xoQATKo5NFTnD3DXjz7Nv114W6UPwWLf6C7+5fx/5vMX33xDEsLV0OYjpZaA8fHxqxrSGQTBdVzNELeHa69iVpaI5CkYZ0pJWzzujL1Se706cp5lVoqRYOWkcm7IY1XkYu21E8qz1k1yOnd5ddNoKEM8ksK1yklqRWSYeGGI0WIrIiWW28PErHLndos1Rrs9RDZowiz0d+NQCNyVvPt9H1nYOCq0pqDUEtDc3IzneXWXv3KtofqZWh/CxUI7x7ObAOiK9RGRyTUKW7xyH0JkmMNjO3gq9RoiVoE3r/oiy6zLCcANZbmn5SAbomc4463nmUsPEhiLe1ufZ4N7CoBoaJxdbftojwxx2lvHobHtGIQtzS+xKfYKm6LHa232h0e3ky3F6Iz2s8HtR1j4juabiSYFpZaAnTt3ks/naZphzZ6dO3dOen3ffffVfW7HuVwDsKRIszVe60OoNiUBNIXHgfIjMtvb21kZuUirPVrrQzjmbeXp1EPYIZ/10YHaOVvC47SF07U+hNO5TvaP3ke+5LDGOQeUWGFfwgnlOJNbx0uZbbw4vp2XxrdSKEWI2yna7JFaH8K5QoLjmc2MB800h8eIhApMZ/Xq1XV/BrcS7WhWaomYj9FH73//+wlRnDJaprpt48aN/PAP/zAAH/vYxxgb6iNPjInfT13GyNEMCI8//jif+MQnODtwihBmQh+CIYQPCCVsHn/8cX7r/f+TEtaEaxvC+JQI8b73vo8PfuiDk+KqDvd83+Mf5M/+7M8WbvTRPKm3o1mTglJKzaE6M7s6i3r79u184xvf4JVXLveHtLe3A+XnP8RiMbq7u9m1a8578LypNyloR7NSSs2iOjM7Go2ybNkyPM/jb//2b6c8fW1oaAiAlStXUigUePLJJwFuqsRQD+1TUEqpWVRnZre0tBAOh2lpaaklBBFBRCaVj0QiNDc3E4lE6OnpWYiQr4smBaWUmkUmkykv13GVIpFI4x8Z2gDafKQWlWw2SyqVIpfL4brujKttKnWjNDU14XkeLS0tV3VcoVBYlP9vak1BLRrZbJZkMkkQBMRiMYIgmHa1TaVupO3bt+N5HmNjYxSLRcbGxnBdFwBjDFcO1ikUCoyPj1MoFOju7l6IkK+LJgW1aKRSKWzbxnEcQqEQjuOUV9tMpRY6NHULSyQS7Nmzh3A4zMjICOFwmB/6oR/ijjvumFSuvb2d9vZ2MpkMtm3zute9btF1MoM2H6lFJJfLTamO27atNQXVcIlEgkQiMWnbY489tkDRNJbWFNSi4bouvu9P2ub7fq0qr5S6fpoU1KIRj8fxfZ98Pk+pVCKfz+P7PvF4fKFDU+qWoUlBLRqxWIxEIoFlWWSzWSzLIpFILMoRHkrdrLRPQS0qsVhMk4BSDaQ1BaWUUjWaFJRSStU0NCmIyJtE5GUROS4i755m/wYR2Ssiz4vIIRH57kbGo5RSanYNSwoiYgEfA74L2Ao8JiJbryj2XuAzxph7gR8A/rhR8SillJpbI2sK9wPHjTEnjTEF4O+B77mijAFaK3+3AWcbGI9SSqk5NHL0UQI4M+H1AHDlQiC/CXxZRP4H0AS8oYHxKKWUmkMjawoyzbYrH/P2GPBXxph1wHcDfyMiU2ISkXeIyD4R2Xfx4sUrdyullLpBGpkUBoD1E16vY2rz0H8DPgNgjPkW4ALtV57IGPNxY8wuY8wyd1DgAAAgAElEQVSulStXNihcpZRSjUwKvcBmEblNRCKUO5KfuKLMaeD1ACJyF+WkoFUBpdStwRgwpWm2VRpNrtw307Z51LA+BWNMUUR+HvgSYAF/YYw5IiIfAPYZY54AfgX4cxH5ZcpNSz9mrlycXCmlFplsNkt/fz/jp7/OxfMD9PaFKX8HN6xzBzBGGA+aaI8M0e91UTQ2ACvsIZbZaba//ud51c77FyT2hi5zYYz5AvCFK7b9xoS/XwQebGQMS04hDcUMxNZe3pZPQakI0Y6Fi0upJSKbzfLKK68wODhI9kKG4tAx1rstDOTWkXCTtIZHOZ/voFBysKVIV7SPPq+L1nCa1c4go8VWPvtvn8eIzb333jvv8evaRzexI0eO0NvbSyaToampid27d7Nt2zYAPvrRjzI2NlYr29LSwjvf+U4YOQy587yQjPHNA6co5S6yqeUst9+5gzte83Mg0/X/K6VulFQqxcjICLFYjINnA6LBGtY457ir+SUAzuc7GPbLXaf9Xied0X7uaHoFgNFiKwO5BBCip6dnQZKCLnNxkzpy5Ah79+7F931aW1vxfZ+9e/dy5MiRKQkBYGxsjI9+9KPQ3s3LfRc5te/TtJb6ub31HIWi8LmeNPv271+gd6PU0pHL5fB9H8uyKBaLXPKXT9o/7K+o/e2VYowHzbXX5/MdVG/LC/XwKE0KN6ne3l4cx6G1tZVIJEJrayuO49Db2zslIVSNjY1ByObJwz52OMza5lEiYeFS5B5CkSZ6enrm+V0otfS4rott2wRBQDhssc4dAKBQigCw3h0Ayp3JK+whWsOj+CZMyQhd0X7CUn6Q1EKtBqxJ4SaVyWSmPFHMdV0ymcycxxZzw4TDl1sGHckQiUT0sZVKzYN4PM6yZcvIZrPsWOvV+hCOZzdzLr+GlvAY690BltvDtT6EY5nN9HtdhCt9DCGKdHdfOdd3fmifwk2qqamJXC5HJBKpbcvlcjQ1NTE0NDTzgfkUm1rO4vkWadlGe6iPVaGTZIodxGI6x0OpRovFYtxxxx04jsOl0DBeEGW4Pw/ApUrTkTGCV3K55C/nXH41EMIrxej3Ommz07zlrf95QfoTQJPCTWv37t3s3buX0dFRXNcll8uRz+fZs2cPw8PD0zYhtbS0wOjL3H7nNj7XM04oEuBFumg3R2k1STbd/+YFeCdKLT2xWIy77roL7roLgLcvcDxXQ5PCTao6yqi3t5fR0VGamprYs2cP27ZtY9u2bTOPPioF3PHgvbym6Qg9PT2MZbKY2J3c/8Au7tu9e6HejlJqkZDFNlds165dZt++fQsdhlJKLSoist8Ys2uuctrRrJRSqkabjxokm82SSqXI5XK4rks8HgeYsk0fQq+UuploTaEBstksyWSSIAiIxWIEQcCJEyc4ceLEpG3JZFKHiSqlbiqaFBoglUph2zaO4xAKhXAcB8/zyOVyk7bZtk0qlVrocJVSqkaTQgPkcjls2560rVgsUiwWJ22zbZtcLjefoSml1Kw0KTSA67r4vj9pWzgcnjTLGMD3/SmzlpVSaiFpUmiAeDyO7/vk83lKpRL5fJ5oNIrrupO2+b5f64BWSqmbgSaFBojFYiQSCSzLIpvNYlkWmzZtYtOmTZO2JRIJHX2klLqp6JDUBonFYtPe8DUJKDWDfAosF8JNl7flLkK4GcLRhYtridGkoJRqmM9//vPs37+f6soJ69at44EHHiCRSNDW1na5oCnBUA+f/vSn6PO68E2EJmuc9e5p9rz+e6H9gdq8nt/5nd+ZNEDDdV3e+c53ks1m8X0f27aJxWK1wR7TzRnSL2cz0+YjpVRDfP7zn2ffvn1MXEpnYGCA3t5ejh07RjqdvlxYQvzvv/gGISnRFe1jWXiY9e5pCibCX//b4dq8ng9/+MNTRuzlcjk+8pGPUCqViEQilEol0uk0vu9PO2dI5wfNTpOCUqoh9lee9Gfbdu0HoK+vD8dxSCaTk8rnS1H6vE7skM9a9xwg9HtdBCZcm9dTKBSmvVaxWCQcDiMihMPhWt/ddHOGdH7Q7DQpKKUaolpDmG7RzUgkgud5U7aHJZh4BkKVJ5QBU+b+zMayLHzfn3bOkM4Pmp0mBaVUQ4jIpN8TFQoFotHJncfVPoRcyaHf68QQoivahy3l2sGVc39mEwQBtm1PO2dI5wfNTpOCUqoh7rvvPqB8E67+AHR1dZHP50kkEpcLmxJrnLMUTIR+r4tM0Eyf10lISnQ4g7V5PROfRDhROBymWCxijKFYLNb6EKabM6Tzg2anSUEp1RBvfvOb2bVr16Sawrp169i9ezebN2+ePPpIQvzgL/1prQ8Byn0Mp7wuXvOf3lmb1/Oe97xn2meX/9qv/RqhUIhCoUAoFKKtra02CunKOUM6P2h2+pCdRUCH1Cmlrpc+ZOcWoUPqlFLzSZPCTU6H1Cml5pPOaL7J5XK5KU1Ftm1rTUEtGel0mmQyied5RKPRqbOhK6qT1aab1VzPflWmNYWbnA6pU0tZOp3m2LFjBEFAc3MzQRBMnQ1N+d9EOp2edlZzPfvVZZoUbnI6pE4tZclkEsdxiEajWJZFNBqddjZ0dWTRdLOa69mvLtOkcJPTIXVqKfM8b8rchOlmQ/u+j2VZk7ZVZzXXs19dpn0Ki8BMy3ArdauLRqNTZj9PNxvatm2CIJj0dMPqrOZ69qvLtKaglLppJRIJ8vk8nucRBAGe502dDQ214drTzWquZ7+6TJOCUuqm1dbWxubNm7Esi/HxcSzLmjobmnJNoK2tbdpZzfXsV5dp85FS6qbW1tY27RDUK1Vv/Ne6X5VpTUEppVSNJgWllFI12nx0E+vp6aGnp6c2k7O7u5vu7m4ABgcHOXr0KJlMhqamJrZs2UJHR8cCR6yUWuy0pnCT6unpYe/evfi+TzQaxfd99u7dS09PD4ODg/T29lIsFlm2bBnFYpHe3l4GBwcXOmyl1CKnNYWbVE9PD7Zt09zcDIDjOIyPj9PT00MulyMajdb2VX8fPXpUawtKqeuiNYWblOd50z5b1vM8MpnMlMk70WiUTCYznyEqpW5BmhRuUtUmo4mqTUlNTU1Tpvl7nkdTU9N8hqiUugXNmhREJCQi3z9fwajLuru78X2f8fFx8vk84+Pj+L5Pd3c3W7ZswfM8xsfHCYKA8fFxPM9jy5YtCx22UmqRmzUpGGNKwM/PUyxqgu7ubh599NFak5Ft2zz66KN0d3fT0dHB7t27CYfDjIyMEA6H2b17t/YnKKWu25zPaBaR9wEe8A9ArdHaGDPc2NCmtxSf0ayUUter3mc01zP66Ccqv39uwjYDbLyWwJRSSt285kwKxpjb5iMQpZRSC2/O0UciEhOR94rIxyuvN4vIWxofmlJKqflWz5DUvwQKwJ7K6wHgQw2LSCml1IKpJylsMsZ8BPABjDEeIPWcXETeJCIvi8hxEXn3DGW+X0ReFJEjIvLpuiNXSil1w9XT0VwQkSjlzmVEZBOQn+sgEbGAjwFvpFy76BWRJ4wxL04osxl4D/CgMeaSiKy6hvfQUOl0mmQyWV6UzrVJrG6nLb62vLOQhnAMSn75d3VbRNdsV0otTvUkhceBfwfWi8ingAeBH6vjuPuB48aYkwAi8vfA9wAvTijzU8DHjDGXAIwxF+oPvfHS6TTHjh3DcRyam5uxRnoZ2J/k71+xSF+6yMbYCWzxGQtaOJHdxLLwCHeuHGf7636GrFmG67rE43F95J9SatGYs/nIGPMV4O2UE8HfAbuMMV+v49wJ4MyE1wOVbRPdAdwhIv8hIs+KyJvqCXq+JJNJHMchGo1iWRaefRsvH32JltwBDBANeax0LuKXwiwLj7DWPcfZS4Z//NzTtWfCJpNJstnsQr8VpZSqy4w1BRHZecWmc5XfG0RkgzHmwBznnq7f4cqZcmFgM/AIsA54WkTuNsaMXBHLO4B3AGzYsGGOy944nufVViAFuDiS5+X0GjbFTrIxdopsKcal7DKaw1maw1nGis2cya2H3BihUAjHcQBIpVJaW1BKLQqzNR/9XuW3C+wCXqB8o98B9AAPzXHuAWD9hNfrgLPTlHnWGOMDp0TkZcpJondiIWPMx4GPQ3lG8xzXvWGi0SiFQqG2Imk+n6dYsjFGEDGAMOa34jgpAHIllysrX7Zta01BKbVozNh8ZIx51BjzKNAP7DTG7DLG3AfcCxyv49y9wGYRuU1EIsAPAE9cUeZfgUcBRKSdcnPSyat/G42RSCTI5/N4nkcQBIQI6Iz2I2IYzK/CCXnc3XqYXOCQLrayMjJEe2Ryt4jv+7iuu0DvQCmlrk49Q1K3GGMOV18YY74NvGqug4wxRcqL6X0JeAn4jDHmiIh8QETeVin2JSAlIi8Ce4FfNcakrvZNNEpbWxubN2/GsizGx8fZ0HyBeIvFGW8d2SBGYMLkSi4hKZHMrWXEX8aqyEXWLjeUSiXy+Ty+7xOPxxf6rSilVF3qWRDv7ygvhPe3lPsEfghoNsY81vjwplrQBfH8cUaHk3z6X/YyODjIsvAw2VKUsARkg2bAsHGV8Mibf5xcPq+jj5RSN416F8SrJym4wH8HXlPZ9A3gT4wxueuO8hroKqlKKXX1btgqqZWb/+9XfpRSSt3C5kwKlVnHHwa2Uh6JBIAxRpfOVkqpW0y9C+L9CVCkPFLok8DfNDIopZRSC6OepBA1xnyNcv9DvzHmN4HXNTYspZRSC6GetY9yIhICjonIzwNJ4KZbuE4ppdT1q6em8EtADPgF4D7KQ1J/tJFBKaWUWhj1jD7qBRARY4z58caHpJRSaqHU8zjOByozjl+qvL5HRP644ZEppZSad/U0H/0B8J1ACsAY8wKXJ7IppZS6hdSTFDDGnLliU9CAWJRSSi2wepLCGRHZAxgRiYjIu6g0JakGKXqQHbhiWwayV648rpRSN1Y9Q1J/BvhDyk9NGwC+DPxcI4NaSnzfJ5vN4vs+tm0Ti8Wwx16E8ZOwYjc0d5UTwuDXwZTAXQWhev6zKaXU1atn9NEQ8IPzEMuS4/s+6XQay7KIRCIEQUA6naatdRt2MQPDveWEkOkDU4RVr9WEoJRqqHrWPloJ/BTQNbG8MeYnGhfW0pDNZrEsi3C4/LFWf2e9PG3tD8L5L8Poi+XCq98IkWULFapSaomo52vnZ4Gnga+iHcw3lO/7RCKRSdssy6JQKEApByX/8o7CiCaFpcY7D2KBu/LytuwAhJsgsnzh4lK3tHqSQswY8+sNj2QJsm2bIAhqNQSAIAiwpQCDPYCBjtdB+ki5KQnKfQxq3qXTaZLJJJ7nEY1GSSQStLW11XXs4OAgR48e5fz581y6dIlIJEI8HudVr3oVnZ2d0x9kDIwc5sK5kzzzSojTFzxarBG2dYxz+/aHWXHnW2e95vPPP09PTw/ZbJZYLEZ3dzf33nvv1b5ttQTVM/rocyLy3Q2PZAmKxWIEQUCxWMQYQ7FYJAgCYsHA5T4EJw7tD4LbAelvQ6m40GEvOel0mmPHjhEEAc3NzQRBwLFjx0in03MeOzg4SG9vL8PDw5w/fx7f98lkMoyPj/P000/T398//YEi9Oc2cOCFo9gjz7LGOc+ayGnOXMjy5f1pBgcHZ7zm888/z9e+9jV836e5uRnf9/na177G888/f60fgVpCZkwKIjImIqPAL1JODJ6IjE7Yrq6Tbdu0tbURCoUoFAqEQiHa2tqwV+6Cjtdfbi4KWeXE0PGodjQvgGQyieM4RKNRLMsiGo3iOA7JZHLOY48ePUo0GiWVShGNRmlpacF1XTzPw3VdDh48OOOxBw8dpd/rwomEaXfTOBGH4fA2hkdGOXr06IzH9fT04DgOLS0tRCIRWlpacByHnp6ea3r/ammZ8Q5jjGmZz0CWqmpimLqjefLrkAWhpvkJSk3ieR7NzZP/e0QiEcbHx+c8NpPJsGzZMnK5HI7jABAKhfB9n2g0ysjIyIzHjo+PY5dGKC9SXOaKh1cMk8lkZjwum81OiddxnLriVaquGc1KLWXRaLTc+T9BoVAgGo3OeWxTU1OtVlB9HnqpVCIcDk+bbCZqj3msdc7glWIkzXZ8XDpCr9BsezQ1zfwFIRaLkc/nJ23L5/PEYrE541VqybZFpFIp9u3bx5kzZyiVSnR0dLBr1y4SicRCh6ZuMolEgmPHjgHlGkKhUCCfz7N58+Y5j92yZQu9vb3E43FOnz5du1mvWLGCXC7H7t27pz/QGF61Mcb+keWcGltL2DZkzAZW8RLrluXYsmXLjNfs7u7ma1/7GlCuIeTzefL5PA899NBVvnO1FEn128tisWvXLrNv377rOkcqleKb3/wmZ8+erX2D832fpqYmHn30UU0Maop5H30EEBToP3OGZ3v2MTg4iIjQuW413Q88SMfqtbNeU0cfqSuJyH5jzK45y11NUhCRdxhjPn5dkV2nG5EUent7OXz4MKFQqNYE4Ps+hUKBtWvX8qY3velGhKqUUjeNepPC1fYp/Mw1xnNTyWazU+YHhMNhSqXSrB14Sil1q7vapCANiWKexWIxLMuiWLw85r9YLBIKhWbtwFNKqVvd1SaF2adRLhIbN24kHo/jeR7ZbJZMJkMmkyESibB9+/aFDk8ppRbMVY0+MsYMzF3q5hePx3nooYcmjT5avXq1jj5SdbmeTudDhw7x3HPPkclkcByH7du3c/fdd5eXTLftaY+pLq9+8eJFnnrqKQYGyv8MI5EIDzzwAI888siM1/N9n+eee46DBw/WhsDO1emczWZJpVLkcjlc1yUej+tw1iVkSY4+UupaVZe8cBxnyvDUuRLDoUOHePLJJ4lEIrUJbIVCgT179tSOvzIxVJdXHxsb4ytf+Qrnzp2bct7Xvva10yYG3/d55plneO6554hEIoTDYQqFAkEQ8PrXv37axJDNZkkmk9i2jW3b+L6P7/skEglNDIvcDetoFhGnnm2LXX9/P5/97Gf51Kc+xWc/+9mZ16RRS9r1LHnx3HPP4TgOsVgM13VpaWkhGo3ywgsvYFkW2Wx2yjHV5dWTyWQtITiOU/upnnc62WyWb3/72ziOQ1NTU23pC9u2Z1zyIpVKYds2juMQCoVwHAfbtkmlUvV+RGqRq6dP4Vt1blu0+vv7efrpp/F9n2XLluH7/uyLlakly/O8KcudRyIRPM+b89hqk9HE2nl1ZrNlWfi+P+UY3/exLGvWUXFXzl6eeKzneZNG2QEzJiCAXC43pbZi2za5XG7G66tby4x9CiKymvIjOKMici+XRx61ArdUPfLgwYO4rktraytA7R/FwYMHZ59cpJac6pIXE5e4uJolL/L5/KSyxWKRaDRaXjJ9mj6F6vLqs42Kq9YYpjs2Go1SLBYnJbIgCGZsCnJdF9/3J53T931c153z/albw2w1he8EfhdYB3wU+L3Kzy8D/7Pxoc2f8fHxKf+oo9GoLiCmpkgkEuTzeTzPIwgCPM8jn8/XNUDh/vvvJ5/Pk81myeVyjI2N4Xke99xzz4w36ury6olEgjVr1gDUlq2o1hDuv//+aa8Xi8W4++67yefzZDIZ8vk8Y2Nj+L5Pd3f3tMfE43F83yefz1Mqlcjn8/i+Tzwer/cjUovcbKuk/jXw1yLyvcaYf57HmOZdc3MznudN+qY212Jlamlqa2tj8+bNJJPJ2peJejqZAXbs2AEwafTRzp072bp164yjj6qr6Nq2zete97qrGn1k2zZ79uwhHA7XPfooFouRSCRIpVJks1lc12XVqlXaybyEzDn6qNKM9FvAWmPMd4nIVuABY8wn5iPAKzVi9FG1T8F1XaLRKJ7nkcvlePjhh7X5SCl1S7iRy1z8JfAloLoC1yvAL11HbDedzs5OHn74YWzbZmRkBNu2NSEopZakeiavtRtjPiMi7wEwxhRFJGhwXPOus7NTk4BSasmrp6aQEZE4YABE5NXA3A+nVUoptejUU1N4J/AEsElE/gNYCXxfQ6OaJ6lUipMnT9bWnK+uiVRVne5/7NgxTp48SbFYpKWlhe3bt7N8+XJdBkApdcuZs6ZgjDkAvBbYA/w0sM0Yc6jRgTVaKpXi0KFDFItFWltbKRaLHDp0qDZzszrd/9SpUxw5cgTf9wmFQmQyGZ588klOnTpVGy6YTCZnnAyklFKLSb2rpN4P3APsBB4TkR9pXEjz4+TJk7iuS1NTE5Zl0dTUhOu6nDx5Erg83b+6zk11SQIoTxY6duyYLgOglLrlzNl8JCJ/A2wCDgLVDmYDfLKBcTVcNputzWCucl2X0dFRoDzdPxaL4XlerWlIRCgWi7iuO6lmYNu21hSUUreEevoUdgFbzWJbTnUOsViMXC43afmAaiKAy9P9Jy4TYIwhHA5PWapAlwFQSt0q6mk++jawutGBzLeNGzeSy+XIZDIEQUAmkyGXy7Fx40bg8nT/zZs315YHqC56Vl0qWZcBUErdauqapwC8KCLPAbXlGI0xb2tYVPMgHo+zY8cOTp48yejoKLFYjB07dtRu7tXp/q7rUiwWJ40+evWrX83y5ct1GQCl1C2nnmUuXjvddmPMUw2JaA76kB2llLp69S5zMWdNoXrzF5HWesorpZRavOoZffQO4IOAB5QoP1fBABsbG5pSSqn5Vs83/1+lPGFtqNHBKKWUWlj1jD46AVzTIHwReZOIvCwix0Xk3bOU+z4RMSIyZ3uXUkqpxqmnpvAe4BkR6WHy6KNfmO0gEbGAjwFvBAaAXhF5whjz4hXlWoBfAKZ/krhSSql5U09N4c+AJ4Fngf0TfuZyP3DcGHPSGFMA/h74nmnKfRD4CDBvTwa/cAHGxiZvO3cOdFKyUmqpq6emUDTGvPMazp0Azkx4PQBMejCsiNwLrDfGfE5E3nUN17hqpRL09kI6PYptP8OpU4cYHAxz5sw6EokSP/Ijd874qEKllLrV1ZMU9lZGIP0bk5uPhuc4TqbZVpsUISIh4PeBH5srgMr13wGwYcOGuSOeRSgEW7cO86d/+hJnz47Q1hbjwoVVRKMeLS2n+dKX+gA0MSillqR6mo/+K5V+BS43HdUze2wAWD/h9Trg7ITXLcDdwNdFpA94NfDEdJ3NxpiPG2N2GWN2rVy5so5Lz25o6AQdHUfJ5y0uXOggEhE2bTqLbUOhUKCnR7s3lFJLUz2T1267xnP3AptF5DYgCfwA5QRTPW+a8hIaAIjI14F3GWMaPl05m80yNnZ5JrcxQrEYJhz2McboiqdKqSVrxqQgIm+f7UBjzP+bY39RRH4e+BJgAX9hjDkiIh8A9hljnriWgG+E8fE2BgbWE42eZ/XqQc6evY1TpzbQ2dlHJJLXdYyUUkvWbDWFt86yzwCzJgUAY8wXgC9cse03Zij7yFznuxFKJRgb28jatWlCoSTgs27dCfr6OhkcXMGmTSm6u7vnPI9SSt2KZkwKxpgfn89A5ksoBG99ayuPPHI3+/ePc+TIEcDjttv6aG+P8eij36mdzEqpJaueVVKnG46aBvYbYw42JKpZ6CqpSil19W7YKqmUn7y2i/KQVIA3U+5E/hkR+UdjzEeuPUyl1GKUzWZJpVLkcjlc1yUej2tf3C2iniGpcWCnMeZXjDG/QjlBrAReQx1zDJRSt5ZsNksymSQIAmKxGEEQkEwmddTeLaKepLABKEx47QOdxhiPCZPZlFJLQyqVwrZtHMchFArhOA62bZNKpRY6NHUD1NN89GngWRH5bOX1W4G/E5Em4MWZD1NK3YpyudyUpiLbtrWmcIuoZ/LaB0XkC8BDlJeu+JkJE8x+sJHBKaVuPq7r4vs+juPUtvm+j+u6CxiVulHqerymMabelVGVUre4eDxOMpkEyjUE3/fxfZ9Vq1YtcGTqRqinT0EppWpisRiJRALLsshms1iWReL/b+/eo+O47gPPf29Xv194NECAAEgQIEFSpPiQRIoULVlWpPFazo4crx1HnnUmjjObnUxm9pzNbHLmrLNrJ+PJWdtnk2zOZhxrHWc2WSd2ko03iiNHlmRZEkWKAkVRBPgECQIgGgQBNIAGuru6u6r77h+NLgIgAII0HiTw+5zDA3R1VfUtgKhf3dfvNjbK6KM1YlE1BSGEmC4YDEoQWKOkpiCEEMIhQUEIIYRDgoIQQgiHBAUhxLpUKEBPz8xtlgV9fatSnHuGdDQLIdal7m44fRrGxy1aWjJkMhbt7X4yGT/V1W7C4VtzPAWDQTKZzIycT+WJe5Zl4fF4CAaDeDye1b68uyZBQQixLm3bBomEzXvvmUxMKJLJAKOjmkcemcDni5DJWMTjcedGn0qluHz5Mhs3biQSiWBZFr29vYTDYcLhMF6vl0KhQDKZpKKi4r4NDNJ8JIRYl5SCnTvTNDVBT4+HsTEXjz0GTU3KqSFMz/FkmiZ+vx/TNJ2cT8VikcnJSdxuN0op3G63M3/jfiVBQQixbpmmRS5nOK+TSYVhGFiWRTabnfG0X24yyufzM84x+3X5+PuVBAUhxLpkWdDe7md0VPPoowWam4tcuOCis1Pj8XicHE9lfr+fbDaL1+udcZ7ZrwuFwn3bdAQSFIQQ61RvL2Qyfh55JE9dncX+/QWamiwuXVIUi0FisRiWZZHL5SgWiwQCAbLZLIFAgGKxSC6Xw+VyEYlEsG0brTW2bTvrTNyvbrsc571GluMUQiyVZBKCQcsZPeR2e7DtIDU1pSf9tTT6aCmX4xRCiDWpogLAQ0Xpm1vMleMpFovNcZ65j78fSVAQa5plWXf8FCfrD4v1TPoUxJplWRbJZJJisYjX66VYLJJMJhccGSLrD4v1ToKCWLPKuf7vZAy5rD8s1jsJCmLNsiwLwzBmbLvdGPLZY9OhtLpYNptdljIKca+RoCDWLI/HQ6FQmLHtdmPIZ49NB1l/WKwvEhTEmlXuE7iTMeSzx6bncjksy5pzxIkQa5EEBbFmeTyloYYul4t8Po/L5bptojJZf1isdzIkVaxp5cBwJ2T9YRJTlCwAACAASURBVLGeSU3hThXt0r8Z2yzQxdUpjxBCLCGpKcxj9qSnkZEROjs7CabaCQT8VG3/59TVN+IxIJR+D7cvArVHVrvYK0omeQmx9khNYQ6zJz319fXxxhtvkM/nUeFWipkh+k7+JcODfbhGjpJJDmD5Gle72CtKJnkJsTZJUJjD7ElPFy9exOfz4fP5yKgacuF9RH05xs99B3dxgmL1ITK6crWLvaJkkpcQa5MEhTnMnvSUyWQIBAJordFak3NV43a7yedyALgC9ff1ohp3QyZ5CbE2SVCYw+xJT8FgENM0UUrhokC13YllFyj4GgCFGnkbj6Hu/IPsOZpa5tp2D5JJXkKsTdLRPIdgMEgymQRKaRF27NhBe3s7Xq+XRvclrMwI161m9h76GLlIAddoO6FsB/CRec+ZTCa5evUqQ0NDGIZBw4YorYErmO5Guob9ZDIZot4s2yoGiWz+MIRbVuZi71IsFiMejwOlIGpZFpZlsWHDhlUumRDipyFBYQ7lse2ZTIZ8Ps/mzZsJBoN0dnYymKogFGpgz/ZH2bBhA8rjIRAKlkYfzSOZTHL27FnS6TSBQIBCoUBfPEHWk8Iwf4Q3sgN/cCPe5CmuJA021fqIhVfwgu9CeZJXIpEgk8ng9/vZsGGDjD4S4j4nQWEesyc9VVRUsHXr1nn2XnhyVDweJ5/PEwwGcbtLP3KXy8W5a36aIzVscg1CdpBCoIox9QDdPXFitQ1LdSnLRiZ5CbH2SJ/CCjBNE601LtfNH3epUzZHzqh1thXcFfgCURnWKYRYNRIUVkAgEEApRbF4c9azZVlU+HNUWmcpuEJYng1483FcE2fl6VsIsWokKKyAxsZGvF6v00dhmib5zCi7akZRnghDaheT3gdJFmIY6S621d/FSCYhhFgC0qewDOZaF3j37t1cvnyZgYEBAOrrG9nUuJm8p56LXT1c7ekhn/PTVLEZXyaIb6oJSdJICCFWkgSFJVZOkWEYBl6vl0KhQDKZJBgM0tzcTGtrK4ZhUCgUyE0t+BKJRCgWi/h8PgBuDI+SnMzg8/mIRCIEg0EsyyIej0saZyHEspLmoyU237rAiURizu3xeJxsNksgEHBSaQQCAUZGRshms5JGQgixoiQoLLH51gXOZrNzbjdNE9u2Z7xnGAb5fB7bnpmiW9JICCGWmwSFJTbfusB+v3/O7YFAALfbPeO9QqGA1+t15jSUSRoJIcRyk6CwxOZbFzgWi825vbGxEb/fj2ma5HI5crkcpmlSU1OD3++XtYKFECtKOpqX2OwUGR6Ph3A4jMfjwePxzLl969atxONxhoeHUUpRV1dHY2NpfQZJIyGEWEkSFJbBfOsCz7c9GAzS1tZGW1vbnO8JIcRKWdagoJT6GPB/AAbwLa31/zbr/d8A/hVgA8PAF7TWvctZJnF/isfjdHR0kE6nCYVC7Nmzx6lNzSeTydDe3k5nZyf5fJ5IJMJjjz3G7t27b3uczA8R69Wy9SkopQzgj4FngV3AZ5VSu2bt9j5wQGu9F/hb4GvLVR5x/4rH4xw7dgzbtqmsrMS2bY4dO+ak7p5LJpPh7bff5uTJk0Ap1Ugmk+HVV1/l7NmzCx4ny4yK9Ww5O5ofBS5rrbu11nngu8Anpu+gtX5da13+a3sHaFrG8oj7VEdHB4FAgEgkgtvtJhKJEAgE6OjomPeYRCJBV1cXgUCAUCiE3+8nHA7jdrtpb29f8DhZZlSsZ8sZFBqBa9Ne909tm8+vAD+c6w2l1K8qpU4qpU4ODw8vYRHF/aC8DsV0gUCAdDo97zHZbJZcLjdjWK/L5cLlct32OFlmVKxnyxkU5srqpufcUanPAQeAr8/1vtb6Ba31Aa31gdra2rl2EWtYKBTCNM0Z20zTJBQKzXuM3+/H5/PNmABYLBYpFou3PU6WGRXr2XIGhX5g07TXTcDA7J2UUs8AXwSe01rnlrE84j61Z88eTNNkcnIS27aZnJzENE327Nkz7zGxWIy2tjZM0ySdTpPNZkmlUti2zcGDBxc8zrIsmR8i1q3lDArtQJtSqkUp5QWeB16cvoNS6iHgm5QCwtAylkXcxxobGzly5Ahut5vx8XHcbjdHjhxZcPRRMBjkQx/6EAcOHABKNYtgMMgzzzyz4Oij8jKjhmE4eawkCaFYT5TWc7boLM3Jlfo48IeUhqR+W2v9n5RSvwuc1Fq/qJR6FdgDXJ86pE9r/dxC5zxw4IAujyhZyxKJBN3d3WQyGYLBIK2trTOeVu9miKYQYv1SSr2ntT5w2/2WMygsh/UQFBKJBGfOnMHv9+P3+8lms2SzWfbu3UssFnOGaAYCAQKBAKZpYprmbZ+ehRDr12KDgsxovge89tprtLe3k8vl8Pl8NDY2sm3bNqdD9OrVq3R1dfHmm2/i8/moqqqisbGRSCTC0NAQ/f39ZLNZent7efbZZ287OUsIIeYjQWGVvfbaaxw9etRZlMe2bbq7uwHYt28fnZ2ddHV1Ofvbts3g4CBKKaqqquju7sYwDDweD/l8ntdffx1AAoMQ4q5IltRV1t7ejmEYzgSrcu2gHBjKAcHr9eL1ep33r1+/Tn9/P4Zh4PP5cLvdhEIhfD7fgpOzhBBiIRIUVlkul5tz8R1gxiQrrbUzqcrlKv3ayhOqyim5o9Eofr9/wclZQgixEGk+WgGWBbMmyTrbZk+wKnO73TNm43q9XidYKKVmNBl5PB4nadvExMSCk7OEWAqWZZHJZLAsC4/HQzAYvGUmuLg/SU1hmeXz8OqrcOqURTKZZGRkhHg8yT/+o82lS6V+g0KhwMTEBOl0msnJSQqFAocPH+bgwYM8/vjjAM4IpHQ6TaFQ4LHHHuPZZ58lGo0SDAZxu91MTEyQy+UWnJwlxE/Lskr/l4vFIl6vl2KxSDKZvGUmuLg/SU1hlmQySTweZ3x8HMuynElLgUCAioqKO06j7PFALGbx/vsmpgktLV7eesuFZWXw+zXbtm0jk8lw7tw5CoUCLpeLgwcP8vTTTwM4X6ePTnrsscec7eX3yjWEI0eOSCezWFblSX3lmmz5ayaTmXO9EHF/kXkK0ySTSadjd2JiAtu2GRsbo66uDp/PR3V1NS6X645nuI6PJzl9WtHXV6pee73w2GNZ0unrBINBfD6fs2+5j2HTpk3znU6IVTUyMoLX60Wpm+nNtNbk83lqampWsWRiIYudpyDNR9PE43F8Ph+WZeHz+SgWi876yV6vl0wmc1dplG3bYvv2m6+rqjRVVQamaUpGTnHf8Xg8FAqFGdsKhYL0KawR6zIoFIuldv4f/ejmNtuGV191c/p0Bfl8HpfL5fxHLz+9lzt1F7ppv/suHDtW+oyyo0d9vPCCm3QaYjHNjRuKjg6NUkEGB2f+cUlGTnGvKy8+ZNs2Wmts23YWJRL3v3XZp5BIwO/93hkGBw327z/Ntm1XOHt2F2fP7iYW6+M3fzNNba0bwzCcdvxCoYDX653zpl0eiTE8bPP66wGyWR+JRJJwuIMf/zjI669voarK4PBhk3D4It3dKY4dq8Lvr6amZozW1guMjg6jtaa6utrpXO7t7eW9995jdHQUr9fLrl272LVrl/PHl0wmuXr1KiMjIyilaGhooLm5Wf44xbIqrzWeyWScB6VwOCw1hTViXfYpfPOb3+T8+QxvvfU4phmiomKMsbFqKivH+fCH3yIUMtm3bx/BYPC2fQrlkRiGYWAYBl1dmr/7O5OenjFCITcTE0H8/gwHD54mHq9mfBxaWyc5d64Bn8+ksfEsfn9mxo28pqaGtrY2zpw54zRhWZaFaZrs2rWLRx55BMuyOHv2LOl0Gp/Ph9aabDZLXV0d27dvl8AghJhB+hQWMDg4SFXVBI8//jZKFUkkaggETCcgAIyNjeHz+WhtbSUUChGJRJy0ytNvuNNHYiil2L7dxdatl7BtN5OTYWIxm1/8xQEiEZP6+ktUVPgZGdlEba2itfUybvcEXq+XWCxGLBYjEomQSqU4ceIESinC4TA+n49wOEwwGKSvr49EIkE8Hiefzzsd1X6/n2AwSDKZlKUjhRB3bV02HwEUCor+/iYKhdKEsFzOR39/Izt2XAYgGo3y5JNP3vY8lmXh9XpnbOvuNrBtD14v2LaLs2dDRKNgmhYul5tSH50imwW3W1Oc1gFhGAbZbJZMJkMkEnFmL0Npotvk5CTZbBbTNCkUCjNGLpWbu+7FjupyjSqVSqG1JhqNEo1GpclBiHvMuqwpFArK6UOorBznIx95nUAgw+nT+7l4cRvAomcFzx6J8fLLBufONdDUlOSTn7xBKFTggw+qOX++jp6eFmy7yO7dCcLhPH19jUxOzrzxFwoFDMNwOvOmB4xcLuek0w4EAhiGMeP9csf4vdZRbVkWIyMjTExM4HK5nMVyEomETHgS4h6zLoNCRUUz1683OH0IjY03eOKJowSDGfr6NmHbrgWXepxu+kiM0VFNd7fmkUd8PPVUL7FYgsOHR/H5cly7VkskUkNLyzW83jG2bo1TXa0YGdkMlFb5ymQypNNpwuEwhw4dQmtNKpUil8uRSqXIZDJs3ryZWCxGY2OjM0y2XDsoTx6615aOnJ4OwePx4Ha78fl85HI5MpnMahdPCDHNuuxoBvijP/oW168P4/fnnW35vIHWLn7913/pjharmZ4HZnLSS1NTgNHRUS5cuEA6nca2K9i3bwvpNAwMnGd4eBilFHV1TUSjdQwOXmJgoLR8dVNTEw8//DB1dXVrZvTRyMgIqVRqxoQnrTWWZREKhWTCkxArQFZeE/eMZDJJMplEKeWkRCgUChQKBSorKyU1ghArQEYfiXtGOYOmZVlYloVt2878j3utViPEeidBQSw7j8dDTU0N0WiUYrGIbdtUVlYSi8Vk9JEQ95h1OyRVrKxyYJD+AyHubVJTEEII4ZCgIIQQwiFBQQghhEOCghBCCIcEhVkGB+GFF+DMB5pfen6ES2eG6euDb30LTr1X5POfHeJalyScE0KsTTL6aJaBAbh4Ef7kG+2Mj1Tx3CfyVNVcxNIexocrMVSRr371R9RuGr/l2C996UurUOLVMX0Wt8fjceYiCCHub1JTmOXhh2Fy8gX8ARt/OMtgYiMXLj3AcLwWQxV5+iOvzRkQAH7nd35nhUu7OsoZT4vFIl6vl2KxSDKZlOR2QqwB67KmcO4cTEzAoUNQXnv8zBnI5+GRR6Cx8TqTk2G0biFjjlLIejAMzZEDb1PXIk1H09eQAJyv5YR884nH43R0dJBOpwmFQuzZs2fBHFOWZdHb20tXVxdXr151ckYFg0EOHTrEE088sWA5E4kEL730Et3d3U45Dx8+zNNPP73gcXdaTiHWknUXFCwLfvCDEf7+7y+wbdsVWlp6GBio58KFBwgGM3z+8wXGx6PE401kMj4mxqqAItHQBCc/OEht4zCh6vxtP2fx5bn/mmHmWkOivIb1fOLxOMeOHSMQCFBZWYlpmhw7dowjR47MecO1LIvLly9z7tw5EokEw8PDQCmRXj6f54033gCYNzAkEgm+//3vE4/HnW22bXP06FGAeQPDnZZTiLVm3TUfDQz0Mj7+AlVV41y+vJV33z3A+fO78Puz7N17hhMnLvHee4+QyfhIj4eIhJJsarpGVd0o6WyQH770cdKj3tt/0CIsqhlGF289cK5tK2j2GhJwcy2H+XR0dBAIBIhEIrjdbiKRCIFAgI6Ojjn3z2Qy9Pb2EggEuHHjBlBaZMjj8ThrMpw4cWLez+vu7nYCgs/nc44FaG9vX7JyCrHWrLuawunTp/H5LPbuPcPJkwcYG6vG682xb98HhEImN26EMYwCrS1dnB3fx0efegXb6+XKla20tl7h4pndZDO+JaktlJthJiYm6OvrwzRNvF4v9fXNVFW1UBfogkwff/2TQc509pDPe9lS1cPOlhg/85kvgcvgxIkTnDhxAtM0CQQCHDp0iEOHDi3BT2p+5WU/oVRDKGc8DYfDc15jIpGgp6cH27adRYRCoZCz9nQmk7klMZ5lWaTTaQBnIaFcLue87/F4FlyLYfp7lmWhtaacEXj6eWZLp9NUVlbO2BYIBBgfn7sfSYi1Zt0FhVQqBcDISIxstrRCmW17GBraQCjUQ13dMDU1wxgGbN9xhfLDb339dQwDHnjgIvM9EB88eJA33niDaDRKX18fqVSKcDjMzp07yWazXLp0icnJScLhMNu3byccDtPV1cXFixfRWhMOh6mpqeH0aTfhcBVPPqrpP/190vE013qfZIN/mFjtCFd6LG5893vUb9zI8ePHndXWLMvi9ddfB1jWwODxeKioqCCTyZDP5/F4PITD4VtqCplMhng87iwQZFkWbrfbyZLq9/uprq4mHo/fsvY1lJp7RkZG5iyDbdsYhkEymZyzH2P2uZRSTlAo94HMJRQKYZomkUjE2Waa5qJX4hPifrfugkI4HCYeL/Uh+P1ZHn74FJcvb+Py5a0AtLT0YBiLH15648YN2tvbCQQCTlNHe3s7GzdupLKyklQqxSuvvILX68Xr9eLz+chkMpw+fRootX2XVyTLZrMMDAywcaOmv/8qb59q40pnHTWM8FDtB9TWjjCpqxjI1UNXF4M3buDxeAiFQmit8fv9pFIpTpw4sey1hXJgWEj52gYGBohGo4yPj1MsFlFKoZTCNE1qa2vxeDwkEokZN3KlFIZRWj87FAo5tYYyrTVtbW3E4/E5y9Ha2ko0GmViYmLGkqVQWshoPnv27OHYsWNAqYZgmiamaXLkyJGFfyBCrBHrLijs3r2fP/uzU/j9WfbvP00oZLJ37xnOnNnL8HAtjY1xDh3avejzXbhwgUAg4DSdJBIJfD4fExMTFAoFJicnmZiYwDAM50Y4nc/nc2ovZSMjI+zcCYlEFRf7duKtPUNL41W83jzdqS1AachUKpWiWCze0owyfY3m1RxJk81mCQaDmKZJMBjE6/Vy48YNCoWCs850JBKZsymoXHPyeDyMjo5imuaMm/u+fft44IEHbvnZlcViMXbs2MGVK1cYHR11tre0tNDc3DxvmRsbGzly5AgdHR2Mj48TCoWkk1msK+suKGzb1szXvgZ//ud/gcdT6iz1+Sweeqj05L537w7q6ur42te+NuMGrpRi8+bNHDx4kN27bwaN2W3QuVwOpRSTk5P4/X4Mw6BYLM47hn++9u2OjvN0d+doilwn5EmTt714fXmaA730mlsoYtzyBDz7nKs9kqbcpBUIBJwAUVtbi1LKaWryer1YljUjkEGpJhIIBPD7/dTX11NVVeV0bvv9fnbs2OH0o8yntraWqqqqGU0/6XR6weYjKAUGCQJivVp3QQFg+/ZmvvKV375lezKZ5OTJk/zkJz+55Wattaa/vx+feQmfeZBtBz4JlJo23BNn8IWqyHq34PP5GBkZwev14vF4nLbv2aN1FmJZbnp6mqkPXmf/lvfpvtHKO52H2NVynl0bztMc6KHH3ILGmPP4ctv59JE0gPO1o6NjRW56sViMeDxOQ0MDY2NjTE5OAjgL7TQ0NBAIBLAsiw0bNsw4NhgM0tjYyKVLl4DSz3lwcBClFFu2bME0TXK5HG1tbfN+fmtrK2fOnAFKgSSbzZLNZtm7d+8yXbEQ9791NyR1IfF4nKGhoXmf3guFApPJBO+/8Vd886v/lg9On2aj7zqkrpBNl5qLYrEYtm3j9/spFAporW/7ZDrb8HAttu2hsm4c0x2kWGUQCGS5dG0HPanNpAshlOv2cxnS6fQtT9KBQOCW9vnlUr6x19TUsGPHDiKRCEopvF4vdXV1bNy4kVAoNGcns8fjobm5md27d1MoFDBNk+rqapqampwRTG1tbQv2a8RiMfbu3Yvb7WZiYgK3283evXuJxWLLfelC3LfWZU1hPpOTk2Sz2QX3uZ7bCEC1Z4hLr/0eoVCI+GSEgcwAMODsNzw87Ey4qq+vX3D45Gz19YNUVY2ivQaDuQYMQ9Pc3IdluTEJY+bDhEI3b+7l/opyECo3zdwLI2mCwSDBYJD6+npaWlowDGPGMNaKiop55zd4PB4aGhoIhUJ3dNx0sVhMgoAQd2DdB4WplpapdBcuZ1s5/UWxCK4Z9SnF9dxGqjxjQOlpfCCzZcHPGBwcvKMyuVyaQGBmbcUwihjGzbkRhw4d4tSpU4yPj9/SNOVyufj93/99DMPA5/PR1NQ0YyRNJpOZkafpwQcf5FOf+tQt5Xjrrbc4ceIEuVwOn8+3qNQS87nb1Bh3e5wQ4u6s66CgNfzZn3XyzjvHCATSnDmzn717k6RSTXi9eZLJEP39m9i2rYOenu08+eQJrl2r54H6c4wn/fT3N/Hg7stE9Sg3svWEQrbT+VsouFCq9P2NG/XU1IygVBGtFYZRZHCwDigyPNxCa8sHhEMmylAMDNSRSDTzxf95Ky+/fJHkRCeGYaNUKTAMDdXzy7/8BLt372Lz5lZ++MN/cGb8loVCIXw+H7lcjvHxcYLBIKFQiFAoRCaToaenZ8b+nZ2dADMCw1tvvcUbb7yB2+3G5/Nh2/ZtU0ss5G5SY/w0xwH09sL0gUbFIvT3w+bNiy+3EOvNug4K7757gpMn32N8vBbT9FMswuuvf4RNm+IEgxP8+MfPEAyavPvuAfL5AAMDGwmTY2JDiPe7DnDlxlZ++998CcN0k5iMEdh9HSjdfHp6mvF4bGpqhhgfr2R8PEo6HSKb9VFbm8C23YyPV9DVtQ1XYoI9uzoYsBs4fuIxDGXzN3/812SyIQYLWxgersHjsdm48TrpdIQ//dOfcOVKnEjEZt++G7dcV3kIZnNzM+l0mqtXr855/W63G601hUKBzs5OnnvuOadJ5sSJE7jdbqepyePxkEqlOH78OIcPH77j/Ezl1BjT+1dulxoDSiOprl69Sj6fx+/3s3HjRgKBwG2Pe+UV+Kd/gieeuIZlvcPERIpTp3ZjWW185StVzOrXnuHGjRtcuHDBGca7c+dO6urq7uh6hbhfrbuOZsuCL38ZvvAF+M53OqmrG6aqapSjRx/i3LlGhod9DAw00N+/hbq6QbzeHNXVQ2gNFy8+SCrj4+TFQ1webCMaHePNzqfpG21mc3Of8xkuF1RVjTM5GWFkZAMbN8a5fr2BRCKGaQbp7d1MLJZg69ZuqqrGuTrcwuC1eiYuR/EaOT72yA+JRUYJ16VwuUpNWX19mzl9+iGi0XGuXGkjkwlSVzf3zb6st7d3wZQOtm3PeD0971Iul3Nu4OXmKbfbTS6Xu6s02cFgkEKhgG3baK2dlBezO5hnl+fatWvOkNVCoUBXVxfJZHLB4wA+9CHwekf4xjfGOX8+zOnTe+jujuD3n2Ry8sq8x5UnH9q2TWVlJbZt097efkttTIi1at3VFN58E0rN6QXgl2hpOYdhFOjp2TW1hyabvc7Onf088cTbJBIx3n9/PxUVCZLJGi5eexAAny9Lc3OcXC5IoNGkGJ755FpdXepzuH59I5OTESoqxqeagGwsy0MiUQPAww+f4uLFHbx/7SH21Hfws/v/kYroJJO+MJ5gkWZfD7btplg0GB6u4ezZ0ufv3/8+9fXDS/qzMQzDaasvNxl5PB7UVAdLsVjE5/PN2G+xFpsaY7p4PE4oFHJmeyulnFnbt6spBIOwa9cb9PRs4dSp7QAcOJBg584hTp0aZ+vWrXMeN3syYvnrhQsXpLYg1oV1V1ModSyXJ6Uprl7dzeXL08etK2zbg1JFzp7djctlYxhFQqGZM2eDwUmCwSzFoiIQuDnJzbIMLKs0fyASmQAgl3OTSoXxevO43UUsy0M+757a300yWcF4tnSDnZiowLYNtM+F1jAyUgtARcUYluWhUCj9ympqlmZdh3ItYMeOHRiG4dQADh06hG3bpFIpstksmUwG27Z56KGHZux3J8qBoaamZlGjh8oJAt1uN+FwmGg0SmVl5YK1n+ny+QmiUeW8jsVyBAKBeWdBw+oP4xVita2rmsKbb8Iv/IKmlCYiD0zvwCzPDi6QStVw/HgVYAB6at/yjNvS8WNjtZw8GaS+fox/+IePYdsePvzhtxgYaEJrFw8+2MHQUD2JRJSOjj1UVExQWztCMJji0qVtJJNRKioSXL/egNdj8S+e+Q7FrIdzPbvI5jyo6zDpD5OzwlRWJujqagM0hUIp4Bw79hhHjhzH7b45qzmTCRAMzkyjMT0R3Hx27NjBz/7szzo1A7jZmXz8+HFn9NGBAwc4fPjwjP2WUyAQIJ/Pz7hJz349n2IRTp3aTV9fgH37xhgaCvDGGw08/PAkO3fOP5GwPIx3esZXSYgn1pN1FRT274fRUZMN0XHMvJ/JrIdSgCgS8acoFBWZfHlMf/lHo7gZEMqvS2w7RCo1xo0bbSilOX9+mHQ6SjCY5sKFnXg8eZLJSjKZEIWCm+7uZpSCbNaHafoZGtpOoeDmo/tfpZDxko8avHvlAOd7H+Cf7X8FV0YT3pikp6eVXM5Pa2s3qVSEcHiSy5fbOHrU4CMfeROAgYF6xsaqaWnpJhi8OdfC6/XO+2RdWVnJz/3czxGJRJw2/uk3wyeeeILDhw+TTCadeQJz7bdcGhsb6erqcq4jn8/fdhZz2SuvgGm20dZ2kj17hlAqxA9+sImjRzfx0Y/OX/adO3c66y1MH8Z78ODBpbkoIe5x6nZPkfeaAwcO6JMnT97xccUiGEYWcBFwpwj4LVLZMHm7dMP3uHIUtUFB3y5O6ql/LqBIKJShUDBobu5hz57zpNMh8vlSM0+h4KZYdOH3p7h06QFyOR/h8CRKQSiUYvPmXs6de4Cgy6SyIsnFvl0Ui4rm5qs8dfjHjI7WkC5G8HjyTExE8PvzNDQMUFGR5L33HsK2PWzffplczsvYWDWx2Aj19UNOSb/whS/Q2dnJxYsXnfUPympqanj++edJp9Pkcjmqq6uJRqNz1gBWc3W4ZDJJPB538hw1NjYuqi8jn4f2dqivv8KpU6dILx7weAAADbRJREFUpVK43VECgUf59Kc3LXisjD4Sa5FS6j2t9YHb7rdegoJSJtObi3zGJLlCgJs1gnKz0kKKuFxFlAKXy8LtVihVpLm5hwcfvABAQ0OcoaFarl5tBWD3bpt0Ok5vbwO9vVspFiEanWDz5ms0NcVxuWzeeuvDJJNR8nkvDQ0DPPvsPxGNmuTzLq5ebcWySjfgpqZrVFSU8gfV1zfw7rsuJiejKKWoqUmwYUNpklwgEOC3fuu3nPUMyqm5LctifHycurq6GU/6tm3jcrlkMpgQa9hig8KydjQrpT6mlLqolLqslPoPc7zvU0p9b+r9E0qpLctVFq0DwM3Vs3KFCHcWEABcFIsuCgUXluXHtl0Ui4p4vJFkMozfn6Wnp5n+/k0Yho3fb2JZPtJpPyMjG7AsN4WCm5GRWpSySadDjI1Vksu5sSwvhYKBaQY5efIAtq2nAtDNoO1232wLz+ezM1673aWOX6WU0wlczj1UHi1kGAY1NTW3tI/fbcdxJpPh2rVrdHV1ce3atTtK5XEvnF8IcatlCwpKKQP4Y+BZYBfwWaXUrlm7/QowprXeBvwB8NXlKg/AL/7i31PqNJ7Ja2TxuhfOeXRT+Uempp76x7BtD6dP78e2NdeubWJ4uJaWlqts2dLL0FCQM2f2YpoBKirGaWm5gseT5/z53YyPhzh+/DHGx6upqholGMxgmj4mJiK8//4henqayec91Ndfx+fL0du7mXQ6iNvtZmioifHxKqqrE8RiWUZGmpiYKDVx+Hw+p7TBYJBNmzbR1tbGpk2biEQid7y+8lzKtZDyXINCoUA8Hl+yG/dyn18IMbfl7Gh+FListe4GUEp9F/gEcG7aPp8Avjz1/d8C/6dSSullatNqaLjBXJestE0okCOTL5LNz54UVaA0MskDWFNfC8RiQ6TTFWzcGMfr7ePq1W0kEjXU1IwQiXTT2noVUHi99XR27iMcTtDUdJ2qqiSVleN0d2/l9OmH8Xjy1NQMs3v3ebSGrq7tWFYF+XwFExMZWlt7qKiYJBqdoLd3C9eubSISKaLUNnbuvITLdYNi8Qa5XBPXrsXweCZ46qn5V127k/WVF1JeVa0cgMpfZ6+gdreW+/xCiLktZ1BoBK5Ne90PzL5bOftorW2lVBKIATMW5lVK/SrwqwCb7zJxTbEIX/3qv+fmk34BptYjyBUjeHI5PCpLFgVo9u07zb597WzYkMIwDC5erGL//mFGRjwYhoHfr0kkIjQ1jWCaPizrLcLh3NREtVK7/8aN9WzbNsaePQXOnfMB/USjw/T2NhMKdVBbGyWfTzA56cblKnU+b9t2ms997p8RCmU5etRLPF46l8dToLm5h+rqLXzmM0+RyVRTKLg5dmyc/v5+mpr6saxann32sQVzE93NJLK5lBfNmX3upXqSX+7zCyHmtpxBYa5G+tk1gMXsg9b6BeAFKHU0301hDGNmR7PX/WPy9kGgtGpayorxG7/xVaJRe2r/mwvjuFxFnnrKxuWK8fjjD+B2u3nyyScX9bm5HPzoR7BlyyC7d/8Mfr+PZFJx/LiXXG4C0zTYs6eamhrNmTMGtbUWLS0aw/DwqU99CLf75ufc2iH8AA888MAd/ywWs77y7ZRXVZveVDXXCmr36vmFEHNbzo7mfmD62L8mpi84MGsfpZQbqABGWQaljuZBYJSA7yV+/hdG+OIXv0GpUjKK1/syyWS9s//0dnfDMMhms9TU1GCaJjt37lz05/p88Mwz8NRTUWzbIpfLEYkU2Ls3RTbrZssWLw89lKe1tciePXkGBmBwMHhXuYJWUiwWw7JK11MsFsnlcliWtWRrFyz3+YUQc1u2IalTN/lLwNNAHGgH/oXW+uy0fX4d2KO1/tdKqeeB/0Zr/ZmFznu3Q1KnSybh61//irNGM4Bp+vF4Smko6urqnOaV8poEsViMpqamn2rMeiaTIZFIkM1m8fv9FIsx6us9ZLM35wCkUkEaGjwotbrzAxZj9vXEYrElDVrLfX4h1pN7Yp6CUurjwB9Sarz/ttb6Pymlfhc4qbV+USnlB/4CeIhSDeH5csf0fJYiKAghxHqz2KCwrGkutNYvAS/N2va/Tvs+C/z8cpZBCCHE4q27LKlCCCHmJ0FBCCGEQ4KCEEIIhwQFIYQQDgkKQgghHBIUhBBCOCQoCCGEcEhQEEII4ZCgIIQQwiFBQQghhEOCghBCCIcEBSGEEI5lzZK6HJRSw0DvEpyqhlkrvK1x6+l619O1glzvWrdU19usta693U73XVBYKkqpk4tJI7tWrKfrXU/XCnK9a91KX680HwkhhHBIUBBCCOFYz0HhhdUuwApbT9e7nq4V5HrXuhW93nXbpyCEEOJW67mmIIQQYpY1HxSUUh9TSl1USl1WSv2HOd73KaW+N/X+CaXUlpUv5dJYxLX+hlLqnFLqjFLqNaVU82qUc6nc7nqn7fdppZRWSt3XI1YWc71Kqc9M/Y7PKqX+cqXLuJQW8f95s1LqdaXU+1P/pz++GuVcCkqpbyulhpRSnfO8r5RSfzT1szijlHp42QqjtV6z/wADuAK0Al7gA2DXrH3+DfAnU98/D3xvtcu9jNf6FBCc+v7X7tdrXez1Tu0XAd4E3gEOrHa5l/n32wa8D1RNvd6w2uVe5ut9Afi1qe93AT2rXe6f4no/DDwMdM7z/seBHwIKOAycWK6yrPWawqPAZa11t9Y6D3wX+MSsfT4B/N9T3/8t8LRSSq1gGZfKba9Va/261joz9fIdoGmFy7iUFvO7BfiPwNeA7EoWbhks5nr/O+CPtdZjAFrroRUu41JazPVqIDr1fQUwsILlW1Ja6zeB0QV2+QTw57rkHaBSKbVxOcqy1oNCI3Bt2uv+qW1z7qO1toEkEFuR0i2txVzrdL9C6cnjfnXb61VKPQRs0lr/YCULtkwW8/vdDmxXSr2tlHpHKfWxFSvd0lvM9X4Z+JxSqh94Cfh3K1O0VXGnf993zb0cJ72HzPXEP3u41WL2uR8s+jqUUp8DDgBPLmuJlteC16uUcgF/AHx+pQq0zBbz+3VTakL6CKVa4FtKqQe11uPLXLblsJjr/SzwX7TW/7tS6jHgL6aut7j8xVtxK3afWus1hX5g07TXTdxaxXT2UUq5KVVDF6rG3asWc60opZ4Bvgg8p7XOrVDZlsPtrjcCPAj8RCnVQ6kd9sX7uLN5sf+X/15rbWmtrwIXKQWJ+9FirvdXgL8G0FofB/yU8gStRYv6+14Kaz0otANtSqkWpZSXUkfyi7P2eRH4panvPw38WE/17NxnbnutU80p36QUEO7n9ma4zfVqrZNa6xqt9Rat9RZKfSjPaa1Prk5xf2qL+b/8/1EaTIBSqoZSc1L3ipZy6SzmevuApwGUUg9QCgrDK1rKlfMi8C+nRiEdBpJa6+vL8UFruvlIa20rpf4t8DKl0Qzf1lqfVUr9LnBSa/0i8KeUqp2XKdUQnl+9Et+9RV7r14Ew8DdTfel9WuvnVq3QP4VFXu+ascjrfRn4qFLqHFAAflNrnVi9Ut+9RV7vvwf+L6XU/0ipKeXz9+kDHUqpv6LU7Fcz1UfyJcADoLX+E0p9Jh8HLgMZ4JeXrSz36c9QCCHEMljrzUdCCCHugAQFIYQQDgkKQgghHBIUhBBCOCQoCCGEcEhQEOueUqpnalz/3R7/k+WYFKeU+rJS6n9a6vMKsRAJCkKsEVMz8oX4qUhQEGuKUurgVL55v1IqNLWuwINKKZdS6j9Pvf6BUuolpdSnpx36m0qpd6f+bbuLj/75qWMvKaWemCqLoZT6ulKqfapM//3U9vDUehanlFIdSikn+6dS6otTawi8CuyYtn2rUuqflFLvKaXeUkrtnNr+X5RSv6+Ueh346t38zISYTp4sxJqitW5XSr0IfAUIAP+P1rpzKgBsAfYAG4DzwLenHTqhtX5UKfUvgT8E/us7/Gj31PEfpzQb9RlKuXmSWuuDSikf8LZS6keUsl1+Ums9MdVs9c5UmR+mNKP+IUp/m6eA96bO/wLwr7XWXUqpQ8B/Bn5m6r3twDNa68IdllmIW0hQEGvR71LKnZMF/oepbY8DfzOVQXNw6sl6ur+a9vUP7uIz/27q63uUgg/AR4G902okFZQS1PUDv6eU+jBQpJQCuQ54Avh+ec2LqUCBUioMHOFmehIA37TP/hsJCGKpSFAQa1E1pRxPHkpJ0tLMnXp4Oj3P9wAopV6mdOM+qbX+V3McX844W+Dm35UC/p3W+uVZ5/o8UAs8orW2prK4+uf7bErNvONa6/3zlD09z3Yh7pj0KYi16AXgfwG+w8129qPAp6b6FuooJR+b7hemfT0++4Ra6/9Ka71/noAwn5eBX1NKeQCUUtuVUiFKNYahqYDwFFBeK/tN4JNKqYBSKgL886nPngCuKqV+fuo8Sim17w7KIcSiSU1BrClTfQK21vovlVIGcEwp9TPA/0spzXIncAk4QWmVvTKfUuoEpQelzy5Rcb5FqSnplCq1+wwDP0cpWP2DUuokcBq4AKC1PqWU+t7Utl7grWnn+m+BbyilfptSDei7lNYtFmJJSZZUsW4opcJa65RSKga8C3xIaz242uUS4l4iNQWxnvxAKVUJeIH/KAFBiFtJTUEIIYRDOpqFEEI4JCgIIYRwSFAQQgjhkKAghBDCIUFBCCGEQ4KCEEIIx/8PdN4mJYtsYocAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, figsize=(6,6))\n", + "ax.scatter(dfpred['score_xgb'][~mask],\n", + " dfpred['score_glmnet'][~mask],\n", + " c=[0.5]*3,\n", + " alpha = 0.1,\n", + " )\n", + "\n", + "ax.scatter(dfpred['score_xgb'][mask],\n", + " dfpred['score_glmnet'][mask],\n", + " c=dfpred['label'][mask].map(lambda x: 'orange' if x=='special' else 'b'),\n", + " alpha = 0.333,\n", + " marker='x'\n", + " )\n", + "ax.set_title(\"Prediction concordance\")\n", + "ax.set_xlabel('xgb - header')\n", + "ax.set_ylabel('glmnet - header')\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
digitalFalseTrue
label
normal23511175
special302361
\n", + "
" + ], + "text/plain": [ + "digital False True \n", + "label \n", + "normal 2351 1175\n", + "special 302 361" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpred[\"label\"], dfpred[\"digital\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
settesttrainval
view
M9638096
N6122310604
T4174
W11379
X342
\n", + "
" + ], + "text/plain": [ + "set test train val\n", + "view \n", + "M 96 380 96\n", + "N 612 2310 604\n", + "T 4 17 4\n", + "W 11 37 9\n", + "X 3 4 2" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(dfpred[\"view\"], dfpred[\"set\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "N 3526\n", + "M 572\n", + "W 57\n", + "T 25\n", + "X 9\n", + "Name: view, dtype: int64" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[\"view\"].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# fig, ax = plt.subplots(1, figsize=(6,6))\n", + "# ax.scatter(dfpred['score_image'][~mask],\n", + "# dfpred['score_xgb'][~mask],\n", + "# c=[0.5]*3,\n", + "# alpha = 0.1,\n", + "# )\n", + "\n", + "# ax.scatter(dfpred['score_image'][mask],\n", + "# dfpred['score_xgb'][mask],\n", + "# c=dfpred['label'][mask].map(lambda x: 'orange' if x=='special' else 'b'),\n", + "# alpha = 0.333,\n", + "# marker='x',\n", + "# )\n", + "# ax.set_title(\"Prediction concordance\")\n", + "# ax.set_xlabel('image')\n", + "# ax.set_ylabel('header')\n", + "# pass" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0,0.5,'header')" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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WQWFdA/mPwQuBSom0t39zTHlS0RE8iDb6qP7gBeBlcCfAfuAp2PKk4gACxYsyHcWpAhlGxQa3P3rwIi7b3X3/wSoB41IBndnfDw/Q4Ll89hybsk2KIykl4fM7O1m9kZgWUx5Epk39u3bx5o1a/jgBz/IlVdeybe//W2uueYarrzySn7jN36DY8eOAWFuhIsvvphrr72W3//93+cd73gHAJ/+9Kf5q7/6q2h/a9euPemW1mPHjnHDDTdw5ZVXctlll/GDH/xg2mMfOHAgNyct57Rsg8J/N7Na4OPAJ4C/Az4WW65EYtDdDdu2waOPhmV399zs96WXXuLd7343jz32GF//+tfZsmULO3bsoLW1lb/+679maGiID3zgA/zoRz/iZz/7GZ2dnae1/4qKCh566CF27NjB448/zsc//nEmRiKYOPbOnTu58MIL5+aEpKhle/fRw+mnfcD18WVHJB4TAaG6GhoaYHAwrG/YAPVn2an5wgsvZOPGjTz88MPs2rWLN73pTQAMDw9zzTXX8OKLL3LRRRexcmUYFeaOO+44rYly3J0/+qM/4qc//SklJSW8+uqrvP766yccW2SuZHv30Wrgy8ASd19rZuuAW9z9v8eaO5E50t4eAkJ1esTsiWV7ewgMZ6M6vTN3561vfSvf/e53T3h9586dM/5tWVnZCW0B0w2Jfd9999HZ2cn27dtJJBI0NzdH200cW2SuZFt99DXgU6TbFtz9GeD2uDIlMtd6e6FqysjZVVUhfa5s3LiRn//859H0m4ODg/zyl7/k4osvZu/evVFbwcSw2hAGz5sYbnvHjh28/PLLJ+23r6+PxYsXk0gkePzxx3nllVfmLtMiU2QbFKrc/akpaaNznRmRuNTVhSqjTIODIX2uNDU18c1vfpM77riDdevWsXHjRl588UUqKyv527/9W2666SauvfZalixZQm1tLQC33XYb3d3dXHHFFXz5y19m9erVJ+33zjvvpK2tjdbWVu677z4uvvjiucu0yBSnM/bRKian43wXYbIdkXmhpSW0IUAoIQwOwsAArF17dvttbm7mueeei9bf/OY38/TTJ3fhuf7663nxxRdxdz70oQ/R2hpGMK6srOTHP/7xtPueuHOpsbGRJ554YtptMo8tMheyLSl8CPgqcLGZvQp8FPi92f9EpHDU14e2g2QSurrCci4ambP1ta99jSuuuIJLL72Uvr4+PvCBD+TmwCKnadZJdqKNzJKEeZmbgXrgKODu/plYczcNTbIjEzSBzKnpPZIJ2U6yk2310Q+AXmAHcPBsMiYiIoUr26CwzN1vijUnImfA3TGzfGejIGVTCyAyVbZtCv9qZpfFmhOR01RRUUFXV5cuftNwd7q6uqioqDj1xiIZZi0pmNmzhDuOyoD3mNleIAUYoU1hXfxZFJnesmXL6OjoOO1hI4pFRUUFy5ZpiDI5PaeqPnpHTnIhcgYSiUQ0dISIzI1Zg4K7q+ukiEgRybZNQUREioCCgoiIRBQUREQkkm0/hXPGnj2wdSscOgRLl8KmTbBqVb5zJSJSGIqqpLBnD9x3XxgIbfnysLzvvpAuIiJFFhS2boVFi8KjpGTy+dat+c6ZiEhhiDUomNlNZvaSme02s0/Ost27zMzN7JSDNZ2NQ4cgPYx9pLY2pIuISIxBwcxKgS8BbwMuAe4ws0um2a4G+H1gW1x5mbB0KfT1nZjW1xfSRUQk3pLCemC3u+9192HgfuDWabb7LPAXwMmT086xTZugpyc8xscnn2/aFPeRRUTmhziDwgXAgYz1jnRaxMzeCCx394djzEdk1Sq4884wafuBA2F55526+0hEZEKct6RON55xNJylmZUAnwd+95Q7Mns/8H6AFStWnFWmVq1SEBARmUmcJYUOYHnG+jJOnKCnBlgL/MTM9gEbgc3TNTa7+73u3ururU1NTTFmWUSkuMUZFJ4GWsxspZmVA7cDmydedPc+d29092Z3bwaeBG5xd821KSKSJ7EFBXcfBT4MPAq8ADzo7s+b2WfM7Ja4jisiImcu1mEu3P0R4JEpaX8yw7bXxZkXERE5taLq0SwiIrNTUBARkYiCgoiIRBQUREQkoqAgIiIRBQUREYkoKIiISERBQUREIgoKIiISUVAQEZGIgoKIiEQUFEREJKKgICIiEQUFERGJKCiIiEhEQUFERCIKCiIiElFQEBGRiIKCiIhEFBRERCSioCAiIhEFBRERiSgoiIhIREFBREQiCgoiIhJRUBARkYiCgoiIRBQUREQkoqAgIiIRBQUREYkoKIiISERBQUREIgoKIiISUVAQEZGIgoKIiEQUFEREJKKgICIiEQUFERGJKCiIiEhEQUFERCIKCiIiElFQEBGRiIKCiIhEFBRERCSioCAiIhEFBRERiSgoiIhIREFBREQiCgoiIhKJNSiY2U1m9pKZ7TazT07z+h+Y2S4ze8bM/tnMLowzPyIiMrvYgoKZlQJfAt4GXALcYWaXTNlsJ9Dq7uuA7wN/EVd+RETk1OIsKawHdrv7XncfBu4Hbs3cwN0fd/fB9OqTwLIY8yMiIqdQFuO+LwAOZKx3ABtm2f69wI9izI+IyPyR6ob+dhjuhfI6qGmBZH3sh42zpGDTpPm0G5rdBbQCfznD6+83szYza+vs7JzDLIqIFKBUNxzZBuMpSDaE5ZFtIT1mcQaFDmB5xvoy4ODUjczsLcB/A25x99R0O3L3e9291d1bm5qaYsmsiEjB6G+HRDWUVYNZWCaqQ3rM4gwKTwMtZrbSzMqB24HNmRuY2RuBrxICwuEY8yIiMn8M90Jp1YlppVUhPWaxBQV3HwU+DDwKvAA86O7Pm9lnzOyW9GZ/CSwAvmdmvzCzzTPsTkSkeJTXwdjgiWljgyE9ZnE2NOPujwCPTEn7k4znb4nz+CIi81JNS2hDgFBCGBuEkQFoXBv7odWjWUSk0CTroXEDlCQh1RWWjRtycvdRrCWFQtXdDe3t0NsLdXXQ0gL18b/XIiLZS9ZDcra7+ONRdCWF7m7Ytg1SKWhoCMtt20K6iEixK7qg0N4O1dXhYTb5vD3+O71ERApe0QWF3l6omnKnV1VVSBcRKXZF16ZQUgJbt8KhQ2F95Uq48EJQnzgRkSIrKXR3w/798PzzYb28HJ59Fn72M2hszG/eREQKQVGVFCbuOFq4EF57LbQpNDSEUsKRI7BqVb5zKCKSdg4OiFdw9u8PJYPe3vRwImUwMhIealMQkYKRxwHxiqqkcOgQdHbC+HgICqWlIb20FK6/Pr95ExGJ9LeDj8Gxl2GkHxI1UN4Q0mPuu1BUJYXDh2FsDIaHQyAYG4OurpDe0pLv3ImIpA3sh/49MD4Midqw7N8T0mNWVEFhYADe8Aa44IIQEADOPx8WLVKPZhEpICP94VbJ0sp0tUZlWB/pj/3QRVV91NQUqpBWrAjBYXgY+vpg6dJ850xEJENiIYz2w9hxKKmA8SHw8ZAes6IKCldfDQ8+CG1tIRjU1sLatSFdRKRgVC8HH4HeF2D4CJQ3Qt2akB6zoqo+Ki2FnTtDf4Xh4bDcuXOywVlEpCAkG+FoO1Q2QcPGsDzaHtJjVlRB4fvfh56e0Efh1VfDsqcnpIuIFIzUkdAvYagTup4My5qWkB6zoqo+2rIlBILKyjDe0chIWN+yJd85ExHJMHAAUodDdVFNS2hTSB2GkkSYVyFGRVVSOHwYEokwvIVZWCYSIV1EpGCMHAWbcveRlYT0mBVVUEgmwT3MoZBKweBgaFtIJPKdMxGRDIma0Mt27Hi4aI0dD+uJmtgPXVRBYc2aMLTF0FAICKOjISCcd54m2RGRAlK9AmpWQUk5jPSFZc2qkB6zogoK731vWCYSodQwUX10yy2aZEdECkhNC1gpLFgJjRvD0kpDesyKKigsWQIXXRRKCP394ZFMhnUNiCciBSNZHxqUS5KQ6grLxg05GSW1qO4+evTRMER2eXnouOYOx4/Dd74TqpZERApGsj72we+mU1RB4ZlnQsNyMhmqjcxC283QUHhNRKTYFVVQgFBVVFUV7j4aHg5plZVqaBYRgSJrU7jsMqiogGPHQse1kvTZl5SEGdhERIpdUQWFO+8MpYSjR0Mj87Fjk/0UmpvznTsRkfwrqqBQVwfV1aGReaJNoaICVq8OQUJEpNgVVZvC1q0hKLS2hhIDhE5sY2Nhmk4RkWJXVCWFQ4fCRDsjI+HhHobN7usL6SIixa6oSgpLl8LevaFUcPRoaGBOJmHxYk20IyICRVZSuPzyEAyqqqCxMbQrDAzANdfAVVflO3ciIhlS3XBkGxx8NCxTublvvqiCwugo3HhjCAYvvggHD4bgcP75UB9/73ERkexMBITxFCQbwjJHgaGoqo/27w+NzTt3TnZi6++HH/4Qrr0WVq06cfvu7jBQXm9vuHOppUXBQyTnUt3Q3w7DvVBeFwaFy8EYQDmXeZ6Dr0LlYiirDq9NLPvbYx/6oqhKCk89FcY/MgsX+fHxcNE/ciQEi0zd3bBtW+j53NAQltu2qeezSE7l8RdzTk09z+Fu6HkWjjwJnU9A73MwNhICRsyKKig8/XS442hwMNyJ1NsbSgwHDoT1TO3t4fbV6uoQRCaea4htkRzqb4dEdfilbBaWieqQfi456TwrYeAVGOiARC2MD0P39jD7WsyKqvqoqys8pnKHmikTGvX2njz0RVXV9H8vIjEZ7g2/nDOVVoXhpM8l052nJWBscMqGHntWiqqk8PLL06f39MAFF5yYVlcXShSZBgdDuojkSHndyRfGscGQfi6Zep7uUHMRlNWGmdesHOqvCukxK6qgMDAw82sLFpy43tISth8YCJ/DxPOW+Cc+EpEJNS0wMgCj6X/E0YGwnoMZyHJq6nmWlIVgULlkcpvx4zkJhkUVFGZz8OCJ6z09of3gO9+B++4LHd42bNDdRyI5lccZyHJq6nkmm2B0CBiHsoUwehS6dkCyMfasFFWbwmy+/nW49dZw0d+zJwSCRYvgV34lDIPx/PNwxRUKCiI5l6cZyHIu8zyPbIPFSRjugpGjkFgI1SshdQRqVs2+n7OkoJDW1gaPPw633RZuT120KDxgcrl162RfBvVhEJHYDPdC5XlQtXQyzT0nDeyqPkr1KJoWAAAPNUlEQVRLpWDLlvD80KEwvHam2trJ21bVh0FEYpXHBnYFhQyvvRaWS5eGKqNMfX0hHdSHQURilscGdgWFDJWVYblpU2ho7ukJvZ4nnm/aFF7v7Z2cj2FCVVVIFxE5a3lsYFebQoZkMlQD9fbCJZeE6qIDB0IJ4eabJ9sTJvowVFdP/q36MIjInMpTA3tRBYWSkvDLfyavvz7ZTlBZGS76092G2tISggeEEsLgYOjDsHZtfHkXKWjFMmhdESiqoDBbQAB45hm4//4wnPZVV4W7jtrbQ2DIVF8f0trbw7AXdXUhIOjuI4lFXBfcudrvxGBuieowVMPYIBx6DJKLQn24gkR2CiSwFlVQOJWDB0PbQXU1PPQQrFkTBsyDk285nQgMItM603/wqX+XbISjvzzxgntk29nXL093IT/T/WYO5gYwPhoGcxvpgfrWucvzuSrVHQa7O/Q4MAbli6A0AYe2wMLVUL0ipwEi1qBgZjcBXwBKgb9z9z+f8noS+BZwFdAF/Ja774szT7Nxh+99L7QnJBKwaxe0tob5F155Ba5a28veXYfY9TxQWsGyNzRQU78Q91P3VTjn+jWc7kWvQH4F5cSZXnCn+7uOzbCw5ezG1Z/uvZ96IT/d/Wbu8+iLULt28mpy9IUw9PPAPvCxkDZ6HI4fguXvzP5zzzyGlQAeT8kjn9/Nic/86C4YOwalSRg8ACP9MNof5lWoXwfH9sHSt+YkX+YxDbBkZqXAL4G3Ah3A08Ad7r4rY5sPAuvc/ffM7Hbg1939t2bbb2trq7e1tZ1hnrLftqQkBIbFi0PJITU0TBnHWbJknPOXjlJRPkJ3l3HJFQu58W3V0dSeE20Q3d2wfXsILAMDoerqiitCW8XEHA4bNkxOA3rGASMfX+jMi1dpVbh4jQzMfNE73e3nMp+5em+mmyClMqPj0ejA5B0kM+VvpA9KKyYv0ACvPR5KC4sug+E+GDgQhjzwcVj5H099PjO990OvAQajxyBRA1XLQ6/ZVBec/2unt8/uNhg+Cg2t4fVXvpceAroExoZC2sKLw7FrL83uc888xthI+CUNYVC40sTcfX9O9d2cruSWOgID+8OFO7EQqpfP/N2a6Ts4kf7aP4fPtW8XlDdAWQV07wgB1MpCkGjcAMnz4Py3hMBwhsxsu7u3nmq7OG9JXQ/sdve97j4M3A/cOmWbW4G/Tz//PnCD2elcuuMzPh6qjg4fhldfhb7eMQ53Jdl3oIL9HUk6DlVRVl7CvvZBXnjhxL4K3d3w2GOhhFFZGWZ36+gIk/w89RSUloZgs2dP6DD32GNn2BEuXxOQnO4Y9/kYEz+X7810E6T07wn/7BNKq06cIGWm/I2NnLjviYvQcB/0PQc+HIJLaTK785nuvWcMev4t/BKdGKu/9zk4/lp2naOm7rNmdTr9l+FiWVYZ8olB+cLwGOwI4/lk+7lnHuN4R2ifSC4K+5nL789s382pn9FQJ7x8H/TvhcGDMDYAx1+FVOf0n8VMn3H/nvT2nTC4P5SmRvth6PUwoc7xzlCyYiwEqJGjoSRxeOu0pzDX4gwKFwAHMtY70mnTbuPuo0AfMGVQ8fwbHQ2lVncjkXCOHy9hYKAEKKOEFPv2he0m+iq0t4e2iUWLQtrYWLjg79sXAkRlZXiMjoaL/0Q7xml3hMvXBCTDveEil2nqRe9stp8LuXxvph6roin8Sh7I+PpP7Y06Xf4qmuDYlPwlG8FKwwW3pCK9r6FwIc7mfKZ774eOQHk94DA+FPZrFvaVTeeoqfssrw2/4MdSoZRUfVEoJY2lgASMe2hfqF6e/eeeeYyR/pDHkopw8YS5+/7M9t2c+hkNd4XAdPQFSFSFuv+yKhjqmv6zmOk7+PrWsBzqgkR9KB1ULg3VbaXlMNYfSkMl5ZBcCKne8Lf9u8/+fLMQZ1CY7hf/1LqqbLbBzN5vZm1m1tbZ2TknmcvGRM3a2BhghpV4+G6MGCUlcLQfkpWTzTITfRV6e2FkBCrS/8MTHd0GB0M6wNBQmNhnZGQybULWHeHycbGF0++Cn48u+7l8b6Yeq2p5KGqmOmfujTpd/ha0wPEjJ/ZitVJYdku4wI6lwoWibm24EGdzPtO996kjofGydm0Yp3+kD8rSVUjZVMdMt8/SBDRuhKVvCXXgDRtC1cpINzA+medsP/fMYyRqQvAaHwr5hLn7/sz23Zz6GY30h/kNUkcmA/REoJrus5jpO3j8UFiO9of3fCyVrmocB0rBR0PVkSWgbBGM9oXvQ2nF2Z9vFuIMCh3A8oz1ZcDBmbYxszKgFjipPOzu97p7q7u3NjU1xZTdk5WWhv/tsjKoqCxlQdUIwymntGScyophhlPjkFhIc/OJ8y3U1YX2iKF0dep554USQiIR9nX8eHgsXx7SEokTj5t1R7h8jY9yul3w89FlP5fvzdRjldeGkSzL62fujTrThbVpml6sNavCBbf+8smLa7bnM917b6WhBFJeC4vWQtM1YUKX6uWz72u2fU58nhOvlZTBkk1QeUH4RV1z8el97pnHqFwGqZ7wqFo2t9+f2c5l6meUqAkX6GRjCFAwGaim+yxm+g5WLg3LshooLYMFq0J1YOX5kFgA1ReG9oXy2lDlVFoZquQWXXX255uFOIPC00CLma00s3LgdmDzlG02A7+Tfv4u4P95XC3fpymZDI+ysvCLvqYmweIl5STLnUTpCJVJuHZTJW/4d1UsWRK2nWhkbmkJVUc9PeECX1IS0i+6KOx7bAwuvTTsu74+bHtGk/nka3yU0+2Cn48u+7l8b2a68C5/Z2i0ne5cZ8pf/VVh+6l/d6bnM917v+yWkL8zfW9m+zwzX/NRqL8C6t8Ynp/O537Sft4Y9nW6+zmbc5n6npc3hMC0cA2MDMJwD4wOQkXD9O/fTJ/Zkk1hWdEQ/t5HQkNy829DxXlw3o0h+JVWhh8KtReHEVMvuPnszzcLsd19BGBmNwP/i3BL6jfc/XNm9hmgzd03m1kF8G3gjYQSwu3uvne2fZ7N3UchT7O/XlcXLtTV1SEY1NeH0sLwcFhfuRIuvBDOPz/80p/pTqHMu48g9HloTbf7T73TaLq0gr77aL7I191H2R4rn7f16nuTnbjvPho4kJ4voSZU6VlZuAmg97mwTUV9qOZbsums51HI9u6jWINCHM42KIiIFKNCuCVVRETmGQUFERGJKCiIiEhEQUFERCIKCiIiElFQEBGRiIKCiIhEFBRERCSioCAiIhEFBRERiSgoiIhIREFBREQiCgoiIhKZd6Okmlkn8Moc7KoRODIH+5kvdL7nrmI6V9D5nqkL3f2Us5TNu6AwV8ysLZthZM8VOt9zVzGdK+h846bqIxERiSgoiIhIpJiDwr35zkCO6XzPXcV0rqDzjVXRtimIiMjJirmkICIiU5zzQcHMbjKzl8xst5l9cprXk2b2QPr1bWbWnPtczp0szvcPzGyXmT1jZv9sZhfmI59z4VTnmrHdu8zMzWxe37GSzfma2W+mP9/nzew7uc7jXMriu7zCzB43s53p7/PN+cjnXDCzb5jZYTN7bobXzcy+mH4vnjGzK2PLjLufsw+gFNgDXASUA/8GXDJlmw8CX0k/vx14IN/5jvl8rweq0s//83w932zONb1dDfBT4EmgNd/5jvmzbQF2AovS64vzne+Yz/de4D+nn18C7Mt3vs/ifP89cCXw3Ayv3wz8CDBgI7Atrryc6yWF9cBud9/r7sPA/cCtU7a5Ffj79PPvAzeYmeUwj3PplOfr7o+7+2B69UlgWY7zOFey+WwBPgv8BTCUy8zFIJvzfR/wJXfvAXD3wznO41zK5nwdWJh+XgsczGH+5pS7/xTonmWTW4FvefAkUGdmS+PIy7keFC4ADmSsd6TTpt3G3UeBPqAhJ7mbe9mcb6b3En59zEenPFczeyOw3N0fzmXGYpLNZ7saWG1mPzezJ83sppzlbu5lc76fBu4ysw7gEeC/5CZreXG6/9tnrCyOnRaQ6X7xT73dKptt5ousz8XM7gJagU2x5ig+s56rmZUAnwd+N1cZilk2n20ZoQrpOkIJ8F/MbK2798actzhkc753AN909/9pZtcA306f73j82cu5nF2nzvWSQgewPGN9GScXMaNtzKyMUAydrRhXyLI5X8zsLcB/A25x91SO8jbXTnWuNcBa4Cdmto9QD7t5Hjc2Z/td/oG7j7j7y8BLhCAxH2Vzvu8FHgRw9yeACsI4QeeirP6358K5HhSeBlrMbKWZlRMakjdP2WYz8Dvp5+8C/p+nW3bmoVOeb7pK5auEgDCf65xnPVd373P3RndvdvdmQvvJLe7elp/snrVsvsv/SLiRADNrJFQn7c1pLudONue7H7gBwMzWEIJCZ05zmTubgXen70LaCPS5+6E4DnROVx+5+6iZfRh4lHA3wzfc/Xkz+wzQ5u6bga8Tip27CSWE2/OX47OT5fn+JbAA+F66PX2/u9+St0yfoSzP9ZyR5fk+CtxoZruAMeC/untX/nJ95rI8348DXzOzjxGqUn53vv6gM7PvEqr9GtNtJH8KJADc/SuENpObgd3AIPCe2PIyT99DERGJwblefSQiIqdBQUFERCIKCiIiElFQEBGRiIKCiIhEFBREpjCzf813HkTyRbekiohIRCUFkSnM7Fh6eZ2ZbTWzB83sl2b252Z2p5k9ZWbPmtmq9Hb/IT0Xx04z22JmS9LpTWb2mJntMLOvmtkr6Z7GmNld6f38Iv1aaf7OWGSSgoLI7C4HPgJcBvxHYLW7rwf+jslROX8GbHT3NxKGeP7DdPqfEoZNuRJ4CFgB0ZAMvwW8yd2vIPQ+vjM3pyMyu3N6mAuROfD0xBgzZrYH+HE6/VnS4wwRBid7ID2+fTnwcjr9WuDXAdz9n8ysJ51+A3AV8HR6qJFKYD6PQyXnEAUFkdlljiI7nrE+zuT/z/8G/trdN5vZdYRx/mH64Y4n0v/e3T81t1kVOXuqPhI5e7XAq+nnv5OR/jPgNwHM7EZgUTr9n4F3mdni9Gv1No/nypZzi4KCyNn7NGHU2X8BjmSk/xlh1NIdwNuAQ0C/u+8C7gF+bGbPAI8BsUytKHK6dEuqSEzMLAmMpYeBvgb4crphWaRgqU1BJD4rgAfTU4MOA+/Lc35ETkklBRERiahNQUREIgoKIiISUVAQEZGIgoKIiEQUFEREJKKgICIikf8P4+Js4Q9bGFQAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, figsize=(6,6))\n", + "label_mask = dfpred['label'][mask].map(lambda x: x=='special')\n", + "\n", + "ax.scatter(dfpred['score_image'][mask][label_mask],\n", + " dfpred['score_xgb'][mask][label_mask],\n", + " c='orange',\n", + " label='special',\n", + " alpha = 0.2\n", + " )\n", + "\n", + "ax.scatter(dfpred['score_image'][mask][~label_mask],\n", + " dfpred['score_xgb'][mask][~label_mask],\n", + " c='b',\n", + " label='regular',\n", + " alpha = 0.2\n", + " )\n", + "\n", + "plt.legend(loc='center')\n", + "ax.set_xlabel('image')\n", + "ax.set_ylabel('header')" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "N 3526\n", + "M 572\n", + "W 57\n", + "T 25\n", + "X 9\n", + "Name: view, dtype: int64" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# dfpred\n", + "dfpred[\"view\"].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idscore_gbmscore_xgbscore_rpartscore_gbmtViewModifiersetlabelviewscore_image...score_image*glmnetscore_image*gbmtscore_max_image_wirescore_max_image_wire_maxscore_max_image_wire+gbmtscore_max_image_wire_max+gbmtscore_max_wire_image+gbmtscore_max_wire_max_image+gbmtscore_max(image;wire_max;gbmt)score_ViewModifier
611000367304_1.2.840.113654.2.70.1.7929291008356...0.0037630.0021050.0068820.045998NaNvalnormalN0.000134...0.0007530.0024810.0001340.0001340.0230660.0230660.0230660.0230660.0459980.0
1801001369263_1.2.840.113654.2.70.1.1021686361183...0.9932730.9938301.0000000.906065magnificationtrainspecialM1.000000...0.9954040.9518741.0000001.0000000.9530320.9530320.9530320.9530321.0000001.0
8021004507537_1.2.840.113654.2.70.1.1283916788292...0.0012840.0032850.0068820.045498NaNtrainnormalN0.000903...0.0019550.0064080.0009030.0009030.0232000.0232000.0232000.0232000.0454980.0
8181004507537_1.2.840.113654.2.70.1.2054380122193...0.0017500.0038480.0068820.049429NaNtrainnormalN0.000788...0.0018260.0062410.0007880.0007880.0251090.0251090.0251090.0251090.0494290.0
10381005140751_1.2.840.113654.2.70.1.1511921198535...0.0012840.0022060.0068820.045471NaNvalnormalN0.000127...0.0007330.0024020.0001270.0001270.0227990.0227990.0227990.0227990.0454710.0
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " id score_gbm score_xgb \\\n", + "61 1000367304_1.2.840.113654.2.70.1.7929291008356... 0.003763 0.002105 \n", + "180 1001369263_1.2.840.113654.2.70.1.1021686361183... 0.993273 0.993830 \n", + "802 1004507537_1.2.840.113654.2.70.1.1283916788292... 0.001284 0.003285 \n", + "818 1004507537_1.2.840.113654.2.70.1.2054380122193... 0.001750 0.003848 \n", + "1038 1005140751_1.2.840.113654.2.70.1.1511921198535... 0.001284 0.002206 \n", + "\n", + " score_rpart score_gbmt ViewModifier set label view \\\n", + "61 0.006882 0.045998 NaN val normal N \n", + "180 1.000000 0.906065 magnification train special M \n", + "802 0.006882 0.045498 NaN train normal N \n", + "818 0.006882 0.049429 NaN train normal N \n", + "1038 0.006882 0.045471 NaN val normal N \n", + "\n", + " score_image ... score_image*glmnet score_image*gbmt \\\n", + "61 0.000134 ... 0.000753 0.002481 \n", + "180 1.000000 ... 0.995404 0.951874 \n", + "802 0.000903 ... 0.001955 0.006408 \n", + "818 0.000788 ... 0.001826 0.006241 \n", + "1038 0.000127 ... 0.000733 0.002402 \n", + "\n", + " score_max_image_wire score_max_image_wire_max \\\n", + "61 0.000134 0.000134 \n", + "180 1.000000 1.000000 \n", + "802 0.000903 0.000903 \n", + "818 0.000788 0.000788 \n", + "1038 0.000127 0.000127 \n", + "\n", + " score_max_image_wire+gbmt score_max_image_wire_max+gbmt \\\n", + "61 0.023066 0.023066 \n", + "180 0.953032 0.953032 \n", + "802 0.023200 0.023200 \n", + "818 0.025109 0.025109 \n", + "1038 0.022799 0.022799 \n", + "\n", + " score_max_wire_image+gbmt score_max_wire_max_image+gbmt \\\n", + "61 0.023066 0.023066 \n", + "180 0.953032 0.953032 \n", + "802 0.023200 0.023200 \n", + "818 0.025109 0.025109 \n", + "1038 0.022799 0.022799 \n", + "\n", + " score_max(image;wire_max;gbmt) score_ViewModifier \n", + "61 0.045998 0.0 \n", + "180 1.000000 1.0 \n", + "802 0.045498 0.0 \n", + "818 0.049429 0.0 \n", + "1038 0.045471 0.0 \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[~dfpred[\"view\"].isnull()].head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## SUBSET test and val sets\n", + "### 'test' in the code is referred to as 'validation' in the paper, and 'validation' in the code as 'hold-out' in the text " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:4: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + "/Applications/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:5: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n" + ] + } + ], + "source": [ + "df_test = dfpred[dfpred[\"set\"]==\"test\"]\n", + "df_val = dfpred[dfpred[\"set\"]==\"val\"]\n", + "\n", + "df_test[\"score_wire\"] = df_test[\"score_wire\"].fillna(0)\n", + "df_val[\"score_wire\"] = df_val[\"score_wire\"].fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(715, 28)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_val.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(df_val.label=='special', df_val.score_glmnet)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_test.score_ViewModifier.isnull().sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idscore_gbmscore_xgbscore_rpartscore_gbmtViewModifiersetlabelviewscore_image...score_image*glmnetscore_image*gbmtscore_max_image_wirescore_max_image_wire_maxscore_max_image_wire+gbmtscore_max_image_wire_max+gbmtscore_max_wire_image+gbmtscore_max_wire_max_image+gbmtscore_max(image;wire_max;gbmt)score_ViewModifier
01000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0022260.0068820.045568NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455680.0
11000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0022260.0068820.045573NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227860.0227860.00.00.0455730.0
21000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0018410.0068820.045569NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455690.0
31000047423_1.2.840.113654.2.70.1.2089724714216...0.0014340.0018410.0068820.045568NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227840.0227840.00.00.0455680.0
41000047594_1.2.840.113654.2.70.1.1921731705635...0.0014020.0038480.0068820.045498NaNNaNNaNNaNNaN...NaNNaN0.00.00.0227490.0227490.00.00.0454980.0
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " id score_gbm score_xgb \\\n", + "0 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.002226 \n", + "1 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.002226 \n", + "2 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.001841 \n", + "3 1000047423_1.2.840.113654.2.70.1.2089724714216... 0.001434 0.001841 \n", + "4 1000047594_1.2.840.113654.2.70.1.1921731705635... 0.001402 0.003848 \n", + "\n", + " score_rpart score_gbmt ViewModifier set label view score_image \\\n", + "0 0.006882 0.045568 NaN NaN NaN NaN NaN \n", + "1 0.006882 0.045573 NaN NaN NaN NaN NaN \n", + "2 0.006882 0.045569 NaN NaN NaN NaN NaN \n", + "3 0.006882 0.045568 NaN NaN NaN NaN NaN \n", + "4 0.006882 0.045498 NaN NaN NaN NaN NaN \n", + "\n", + " ... score_image*glmnet score_image*gbmt \\\n", + "0 ... NaN NaN \n", + "1 ... NaN NaN \n", + "2 ... NaN NaN \n", + "3 ... NaN NaN \n", + "4 ... NaN NaN \n", + "\n", + " score_max_image_wire score_max_image_wire_max score_max_image_wire+gbmt \\\n", + "0 0.0 0.0 0.022784 \n", + "1 0.0 0.0 0.022786 \n", + "2 0.0 0.0 0.022784 \n", + "3 0.0 0.0 0.022784 \n", + "4 0.0 0.0 0.022749 \n", + "\n", + " score_max_image_wire_max+gbmt score_max_wire_image+gbmt \\\n", + "0 0.022784 0.0 \n", + "1 0.022786 0.0 \n", + "2 0.022784 0.0 \n", + "3 0.022784 0.0 \n", + "4 0.022749 0.0 \n", + "\n", + " score_max_wire_max_image+gbmt score_max(image;wire_max;gbmt) \\\n", + "0 0.0 0.045568 \n", + "1 0.0 0.045573 \n", + "2 0.0 0.045569 \n", + "3 0.0 0.045568 \n", + "4 0.0 0.045498 \n", + "\n", + " score_ViewModifier \n", + "0 0.0 \n", + "1 0.0 \n", + "2 0.0 \n", + "3 0.0 \n", + "4 0.0 \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[dfpred[\"score_image\"].isnull()].head()\n", + "# .reset_index()[\"index\"].to_csv(\"../tables/spotmag_predictions/missing_imgs.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idscore_gbmscore_xgbscore_rpartscore_gbmtViewModifiersetlabelviewscore_image...score_image*glmnetscore_image*gbmtscore_max_image_wirescore_max_image_wire_maxscore_max_image_wire+gbmtscore_max_image_wire_max+gbmtscore_max_wire_image+gbmtscore_max_wire_max_image+gbmtscore_max(image;wire_max;gbmt)score_ViewModifier
611000367304_1.2.840.113654.2.70.1.7929291008356...0.0037630.0021050.0068820.045998NaNvalnormalN0.000134...0.0007530.0024810.0001340.0001340.0230660.0230660.0230660.0230660.0459980.0
1801001369263_1.2.840.113654.2.70.1.1021686361183...0.9932730.9938301.0000000.906065magnificationtrainspecialM1.000000...0.9954040.9518741.0000001.0000000.9530320.9530320.9530320.9530321.0000001.0
8021004507537_1.2.840.113654.2.70.1.1283916788292...0.0012840.0032850.0068820.045498NaNtrainnormalN0.000903...0.0019550.0064080.0009030.0009030.0232000.0232000.0232000.0232000.0454980.0
8181004507537_1.2.840.113654.2.70.1.2054380122193...0.0017500.0038480.0068820.049429NaNtrainnormalN0.000788...0.0018260.0062410.0007880.0007880.0251090.0251090.0251090.0251090.0494290.0
10381005140751_1.2.840.113654.2.70.1.1511921198535...0.0012840.0022060.0068820.045471NaNvalnormalN0.000127...0.0007330.0024020.0001270.0001270.0227990.0227990.0227990.0227990.0454710.0
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " id score_gbm score_xgb \\\n", + "61 1000367304_1.2.840.113654.2.70.1.7929291008356... 0.003763 0.002105 \n", + "180 1001369263_1.2.840.113654.2.70.1.1021686361183... 0.993273 0.993830 \n", + "802 1004507537_1.2.840.113654.2.70.1.1283916788292... 0.001284 0.003285 \n", + "818 1004507537_1.2.840.113654.2.70.1.2054380122193... 0.001750 0.003848 \n", + "1038 1005140751_1.2.840.113654.2.70.1.1511921198535... 0.001284 0.002206 \n", + "\n", + " score_rpart score_gbmt ViewModifier set label view \\\n", + "61 0.006882 0.045998 NaN val normal N \n", + "180 1.000000 0.906065 magnification train special M \n", + "802 0.006882 0.045498 NaN train normal N \n", + "818 0.006882 0.049429 NaN train normal N \n", + "1038 0.006882 0.045471 NaN val normal N \n", + "\n", + " score_image ... score_image*glmnet score_image*gbmt \\\n", + "61 0.000134 ... 0.000753 0.002481 \n", + "180 1.000000 ... 0.995404 0.951874 \n", + "802 0.000903 ... 0.001955 0.006408 \n", + "818 0.000788 ... 0.001826 0.006241 \n", + "1038 0.000127 ... 0.000733 0.002402 \n", + "\n", + " score_max_image_wire score_max_image_wire_max \\\n", + "61 0.000134 0.000134 \n", + "180 1.000000 1.000000 \n", + "802 0.000903 0.000903 \n", + "818 0.000788 0.000788 \n", + "1038 0.000127 0.000127 \n", + "\n", + " score_max_image_wire+gbmt score_max_image_wire_max+gbmt \\\n", + "61 0.023066 0.023066 \n", + "180 0.953032 0.953032 \n", + "802 0.023200 0.023200 \n", + "818 0.025109 0.025109 \n", + "1038 0.022799 0.022799 \n", + "\n", + " score_max_wire_image+gbmt score_max_wire_max_image+gbmt \\\n", + "61 0.023066 0.023066 \n", + "180 0.953032 0.953032 \n", + "802 0.023200 0.023200 \n", + "818 0.025109 0.025109 \n", + "1038 0.022799 0.022799 \n", + "\n", + " score_max(image;wire_max;gbmt) score_ViewModifier \n", + "61 0.045998 0.0 \n", + "180 1.000000 1.0 \n", + "802 0.045498 0.0 \n", + "818 0.049429 0.0 \n", + "1038 0.045471 0.0 \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred[~dfpred[\"score_image\"].isnull()].head()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "magnification 41039\n", + "spot compression 23194\n", + "implant displaced 15534\n", + "rolled medial 114\n", + "rolled lateral 82\n", + "axillary tail 38\n", + "tangential 38\n", + "cleavage 7\n", + "infra-mammary fold 7\n", + "nipple in profile 3\n", + "rolled inferior 1\n", + "rolled superior 1\n", + "Name: ViewModifier, dtype: int64" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfpred.ViewModifier.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def specificity_at_sensitivity100(fpr_, tpr_):\n", + " tpr_max = tpr_.max() \n", + " if tpr_max == 1:\n", + " return 1-fpr_[np.argmax(tpr_ == tpr_max)]\n", + " else:\n", + " return 0\n", + " \n", + "def thr_at_sensitivity100(thr, tpr_):\n", + " tpr_max = tpr_.max() \n", + " if tpr_max == 1:\n", + " return thr[np.argmax(tpr_ == tpr_max)]\n", + " else:\n", + " return 1.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## VALIDATION SET\n", + "in code and tables referred to as 'test'" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "score_gbm 114 0.5\n", + "score_xgb 114 0.5\n", + "score_rpart 114 0.5\n", + "score_gbmt 114 0.5\n", + "score_image 114 0.5\n", + "score_image_max 114 0.5\n", + "score_glmnet 114 0.5\n", + "score_wire 114 0.5\n", + "score_wire_max 114 0.5\n", + "score_image+glmnet 114 0.5\n", + "score_image+gbmt 114 0.5\n", + "score_max(image;gbmt) 114 0.5\n", + "score_image*glmnet 114 0.5\n", + "score_image*gbmt 114 0.5\n", + "score_max_image_wire 114 0.5\n", + "score_max_image_wire_max 114 0.5\n", + "score_max_image_wire+gbmt 114 0.5\n", + "score_max_image_wire_max+gbmt 114 0.5\n", + "score_max_wire_image+gbmt 114 0.5\n", + "score_max_wire_max_image+gbmt 114 0.5\n", + "score_max(image;wire_max;gbmt) 114 0.5\n", + "score_ViewModifier 114 0.5\n", + "score_wire 11\n", + "score_wire_max 11\n" + ] + } + ], + "source": [ + "dfmodels = []\n", + "THR = 0.5\n", + "optimal=False\n", + "for cc in df_test.columns:\n", + " mdict = {}\n", + " if not cc.startswith(\"score\"):\n", + " continue\n", + "\n", + " label = df_test[\"label\"]!= 'normal'\n", + " fpr_, tpr_, thresholds = roc_curve(label, df_test[cc], pos_label=1)\n", + " if optimal:\n", + " opt_thr = thresholds[np.argmax(tpr_ - fpr_)]\n", + " else:\n", + " opt_thr=THR\n", + " \n", + " print(cc, label.sum(), opt_thr)\n", + "# pr, rec, thresholds_ = precision_recall_curve(df_test[\"label\"]!= 'normal', df_test[cc], pos_label=1)\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_test[cc]>=opt_thr)\n", + " mdict[ff.__name__] = mm\n", + " auc_ = auc(fpr_, tpr_)\n", + " mdict[\"auROC\"] = auc_\n", + " mdict[\"specificity_at_sensitivity100\"] = specificity_at_sensitivity100(fpr_, tpr_)\n", + "# auc_ = auc(pr, rec, )\n", + "# mdict[\"auPRC\"] = auc_\n", + " mdict[\"model\"] = cc\n", + " mdict[\"thr\"] = opt_thr\n", + "# print(cc, auc_)\n", + " dfmodels.append(mdict)\n", + "# break\n", + "\n", + "for cc in [\"score_wire\", 'score_wire_max']:\n", + " mdict = {}\n", + " if cc in [\"score_wire\", 'score_wire_max']:\n", + " label = df_test[\"view\"]== 'W'\n", + " else:\n", + " label = df_test[\"label\"]!= 'normal'\n", + " print(cc, label.sum())\n", + " fpr_, tpr_, thresholds = roc_curve(label, df_test[cc], pos_label=1)\n", + "# pr, rec, thresholds_ = precision_recall_curve(df_test[\"label\"]!= 'normal', df_test[cc], pos_label=1)\n", + " if optimal:\n", + " opt_thr = thresholds[np.argmax(tpr_ - fpr_)]\n", + " else:\n", + " opt_thr=THR\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_test[cc]>=opt_thr)\n", + " mdict[ff.__name__] = mm\n", + " auc_ = auc(fpr_, tpr_)\n", + " mdict[\"auROC\"] = auc_\n", + " mdict[\"specificity_at_sensitivity100\"] = specificity_at_sensitivity100(fpr_, tpr_)\n", + " mdict[\"thr\"] = opt_thr\n", + "# auc_ = auc(pr, rec, )\n", + "# mdict[\"auPRC\"] = auc_\n", + " cc_ = cc + \" (vs other views)\"\n", + " mdict[\"model\"] = cc_\n", + "# print(cc, auc_)\n", + " dfmodels.append(mdict)\n", + " \n", + "dfmodels = pd.DataFrame(dfmodels)[[\"model\", \"auROC\",\"average_precision_score\", \"f1_score\", \n", + " \"precision_score\", \"recall_score\", \"accuracy_score\", \"thr\", \"specificity_at_sensitivity100\" ]]\n", + "\n", + "dfmodels[\"model\"] = dfmodels[\"model\"].str.replace('score_','')\n", + "dfmodels.columns = [cc.replace('_score','') for cc in dfmodels.columns]\n", + "dfmodels.rename(columns={\"average_precision\":\"auPRC\", \"f1\":\"F1\"}, inplace=True)\n", + "\n", + "dfmodels = dfmodels.set_index('model').round(4)*100\n", + "dfmodels = dfmodels.loc[[ 'ViewModifier', 'rpart', 'gbm', 'glmnet','xgb', 'gbmt', \n", + " 'image',\n", + " 'image_max',\n", + "# 'wire', 'wire_max', \n", + " 'wire (vs other views)',\n", + " 'wire_max (vs other views)',\n", + "# 'max_image_wire',\n", + "# \"image+glmnet\" ,\n", + "# 'max_image_wire+gbmt',\n", + " 'max_image_wire_max',\n", + " 'image+gbmt',\n", + "# 'max(image;gbmt)',\n", + "# 'max_image_wire_max+gbmt',\n", + " 'max_wire_max_image+gbmt',\n", + "# 'max(image;wire_max;gbmt)',\n", + "# 'max_wire_image+gbmt'\n", + "# # \"image*glmnet\" ,'img*gbmt'\n", + " ]]\n", + "dfmodels.rename(index={\"max_image_wire\":\"max(image, wire)\",\n", + " 'image':'avg(image)',\n", + " 'image_max':'max(image)',\n", + " 'image+gbmt': 'avg(image)+gbmt',\n", + " 'wire_max':'max(wire)', \n", + " 'wire (vs other views)':'avg(wire) (vs other views)',\n", + " 'wire_max (vs other views)':'max(wire) (vs other views)',\n", + " 'max_wire_image+gbmt': 'max(wire, image+gbmt)',\n", + "# \"max_image_wire+gbmt\":\"max(image, wire) + gbmt\",\n", + " 'max_image_wire_max': \"max(avg(image), max(wire))\",\n", + "# 'max_image_wire_max+gbmt':'max(image, max(wire))+gbmt',\n", + " 'max(image;gbmt)':'max(image, gbmt)',\n", + " 'max(image;wire_max;gbmt)':'max(image, wire_max, gbmt)',\n", + " 'max_wire_max_image+gbmt':'max(max(wire), avg(image)+gbmt)',\n", + " }, inplace=True)\n", + "df_performance_test = dfmodels" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0,0.5,'score_wire_max')" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "label = df_test[\"view\"]== 'W'\n", + "\n", + "# fpr_, tpr_, thresholds = roc_curve(label, df_test[cc], pos_label=1)\n", + "# plt.plot(fpr_, tpr_)\n", + "fig, axs = plt.subplots(1,3, sharex=True, sharey=True, figsize=(14,4))\n", + "\n", + "cc = 'score_wire'\n", + "axs[0].scatter(label, df_test[cc])\n", + "axs[0].set_title(cc)\n", + "axs[0].set_xlabel('label')\n", + "axs[0].set_xticks([0,1])\n", + "cc = 'score_wire_max'\n", + "axs[1].scatter(label, df_test[cc])\n", + "axs[1].set_title(cc)\n", + "axs[1].set_xlabel('label')\n", + "axs[1].set_xticks([0,1])\n", + "\n", + "axs[2].scatter(df_test['score_wire'], df_test['score_wire_max'])\n", + "axs[2].set_xlabel('score_wire')\n", + "axs[2].set_ylabel('score_wire_max')" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
auROCauPRCF1precisionrecallaccuracythrspecificity_at_sensitivity100
model
ViewModifier92.2375.0385.4783.3387.7295.3250.00.00
rpart94.3090.3993.95100.0088.6098.2150.00.00
gbm94.8290.3993.95100.0088.6098.2150.01.31
glmnet95.8890.3993.95100.0088.6098.2150.00.33
xgb96.3090.3993.95100.0088.6098.2150.011.11
gbmt96.5990.3993.95100.0088.6098.2150.05.56
avg(image)99.6093.1095.9698.1793.8698.7650.079.41
max(image)99.5292.2695.5497.2793.8698.6250.075.33
avg(wire) (vs other views)100.0091.0595.24100.0090.9199.8650.0100.00
max(wire) (vs other views)100.00100.00100.00100.00100.00100.0050.0100.00
max(avg(image), max(wire))99.9897.5498.6998.2699.1299.5950.097.71
avg(image)+gbmt99.2992.6195.41100.0091.2398.6250.076.14
max(max(wire), avg(image)+gbmt)100.0098.5299.12100.0098.2599.7250.099.84
\n", + "
" + ], + "text/plain": [ + " auROC auPRC F1 precision recall \\\n", + "model \n", + "ViewModifier 92.23 75.03 85.47 83.33 87.72 \n", + "rpart 94.30 90.39 93.95 100.00 88.60 \n", + "gbm 94.82 90.39 93.95 100.00 88.60 \n", + "glmnet 95.88 90.39 93.95 100.00 88.60 \n", + "xgb 96.30 90.39 93.95 100.00 88.60 \n", + "gbmt 96.59 90.39 93.95 100.00 88.60 \n", + "avg(image) 99.60 93.10 95.96 98.17 93.86 \n", + "max(image) 99.52 92.26 95.54 97.27 93.86 \n", + "avg(wire) (vs other views) 100.00 91.05 95.24 100.00 90.91 \n", + "max(wire) (vs other views) 100.00 100.00 100.00 100.00 100.00 \n", + "max(avg(image), max(wire)) 99.98 97.54 98.69 98.26 99.12 \n", + "avg(image)+gbmt 99.29 92.61 95.41 100.00 91.23 \n", + "max(max(wire), avg(image)+gbmt) 100.00 98.52 99.12 100.00 98.25 \n", + "\n", + " accuracy thr specificity_at_sensitivity100 \n", + "model \n", + "ViewModifier 95.32 50.0 0.00 \n", + "rpart 98.21 50.0 0.00 \n", + "gbm 98.21 50.0 1.31 \n", + "glmnet 98.21 50.0 0.33 \n", + "xgb 98.21 50.0 11.11 \n", + "gbmt 98.21 50.0 5.56 \n", + "avg(image) 98.76 50.0 79.41 \n", + "max(image) 98.62 50.0 75.33 \n", + "avg(wire) (vs other views) 99.86 50.0 100.00 \n", + "max(wire) (vs other views) 100.00 50.0 100.00 \n", + "max(avg(image), max(wire)) 99.59 50.0 97.71 \n", + "avg(image)+gbmt 98.62 50.0 76.14 \n", + "max(max(wire), avg(image)+gbmt) 99.72 50.0 99.84 " + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_performance_test" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, figsize=(7,5))\n", + "sns.heatmap(df_performance_test.drop(['thr', 'specificity_at_sensitivity100'], axis=1), annot=True, fmt=\".2f\", \n", + " annot_kws={\"size\": 12, #'weight':'bold'\n", + " },\n", + " linewidths=.5, cmap=\"viridis_r\", vmin=75, vmax=100, ax=ax)\n", + "ax.xaxis.tick_top()\n", + "ax.set_ylabel('')\n", + "locs, labels = plt.yticks()\n", + "plt.setp(labels, rotation=0)\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "os.makedirs('img', exist_ok=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Confusion matrix on validation set" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cc = 'score_image+gbmt'\n", + "optimal = False\n", + "mask = dfpred[\"set\"]==\"test\"\n", + "label = df_test.label != 'normal'\n", + "fpr_, tpr_, thresholds = roc_curve(label, df_test[cc], pos_label=1)\n", + "if optimal:\n", + " opt_thr = thresholds[np.argmax(tpr_ - fpr_)]\n", + "else:\n", + " opt_thr=THR\n", + "\n", + "fig = plt.figure(figsize=(8, 2))\n", + "\n", + "gs = gridspec.GridSpec(1, 2, width_ratios=[15, 1],) \n", + "axs = [plt.subplot(gs_) for gs_ in gs]\n", + "\n", + "conf_view = pd.crosstab(dfpred[cc][mask]>=opt_thr, dfpred[mask][\"view\"]).loc[:,[\"N\", \"M\", \"T\",\"W\", \"X\"]]\n", + "conf_view.index = conf_view.index.map(lambda x: {True:\"special\", False:\"normal\"}[x])\n", + "colmap = {\"N\":\"normal\", \"M\": \"magnified\\nor spot\",\n", + " \"T\":\"stereotactic\", \"W\":\"wire\\nlocalization\", \"X\":\"other\"}\n", + "conf_view.columns = conf_view.columns.map(lambda x: colmap[x])\n", + "\n", + "formatter = LogFormatter(10, labelOnlyBase=False) \n", + "hm = sns.heatmap((conf_view+1), #.applymap(lambda x: np.log10(1+x)),\n", + " annot=conf_view,\n", + " annot_kws={\"size\": 16, 'weight':'bold'},\n", + " fmt=\"d\", linewidths=.5, cmap=\"YlGnBu\", \n", + " vmin=1, vmax=600,\n", + " ax=axs[0],\n", + " cbar_kws=dict(format = formatter, ticks=1+np.r_[0,10,100, 500],\n", + " ),\n", + " cbar_ax=axs[1],\n", + " norm=LogNorm())\n", + "\n", + "locs, labels = plt.yticks()\n", + "plt.setp(labels, rotation=0)\n", + "\n", + "axs[1].set_yticklabels([0,10,100, 500])\n", + "axs[0].axes.yaxis.set_tick_params(rotation=0, labelsize=16)\n", + "axs[0].axes.xaxis.set_tick_params(rotation=30, labelsize=16)\n", + "\n", + "# axs[0].axes.yaxis.set_label(\"prediction\", size=16)\n", + "axs[0].set_ylabel(\"prediction\", fontsize=16, labelpad=12)\n", + "axs[0].set_xlabel(\"ground truth\", fontsize=16, labelpad=12)\n", + "axs[0].set_title(\"Confusion matrix\", fontsize=16)\n", + "# fig.tight_layout(rect=[0, 0.03, 1, 0.95])\n", + "\n", + "# plt.subplots_adjust(top=0.85, bottoxm=-0.0)\n", + "plt.savefig(f\"./img/confmatr_test_0.5-{tag}.eps\", bbox_inches='tight', pad_inches=0)\n", + "plt.savefig(f\"./img/confmatr_test_0.5-{tag}.tiff\", bbox_inches='tight', pad_inches=0, dpi=300)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## HOLDOUT SET\n", + "in code and tables referred to as 'val'" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Applications/anaconda3/lib/python3.6/site-packages/pandas/core/indexing.py:517: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " self.obj[item] = s\n" + ] + } + ], + "source": [ + "df_val.loc[:,\"score_wire\"] = df_val[\"score_wire\"].fillna(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Confusion matrix on the holdout set" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
viewNMTWX
score_max_wire_image+gbmt
False6020111
True296381
\n", + "
" + ], + "text/plain": [ + "view N M T W X\n", + "score_max_wire_image+gbmt \n", + "False 602 0 1 1 1\n", + "True 2 96 3 8 1" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.crosstab(df_val['score_max_wire_image+gbmt']>0.5, df_val.view)[['N','M','T','W','X']]" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(df_val.view, df_val['score_max_wire_image+gbmt'], alpha=0.2)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# def specificity_at_sensitivity100(fpr_, tpr_):\n", + "# tpr_max = tpr_.max() \n", + "# if tpr_max == 1:\n", + "# return 1-fpr_[np.argmax(tpr_ == tpr_max)]\n", + "# else:\n", + "# return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "modeldict = {\"max_image_wire\":\"max(image, wire)\",\n", + " 'max_wire_image+gbmt': 'max(wire, image+gbmt)',\n", + " \"max_image_wire+gbmt\":\"max(image,wire) + gbmt\"}" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "score_gbm gbm 111 0.5\n", + "score_xgb xgb 111 0.5\n", + "score_rpart rpart 111 0.5\n", + "score_gbmt gbmt 111 0.5\n", + "score_image image 111 0.5\n", + "score_image_max image_max 111 0.5\n", + "score_glmnet glmnet 111 0.5\n", + "score_wire wire 111 0.5\n", + "score_wire_max wire_max 111 0.5\n", + "score_image+glmnet image+glmnet 111 0.5\n", + "score_image+gbmt image+gbmt 111 0.5\n", + "score_max(image;gbmt) max(image;gbmt) 111 0.5\n", + "score_image*glmnet image*glmnet 111 0.5\n", + "score_image*gbmt image*gbmt 111 0.5\n", + "score_max_image_wire max(image, wire) 111 0.5\n", + "score_max_image_wire_max max_image_wire_max 111 0.5\n", + "score_max_image_wire+gbmt max(image,wire) + gbmt 111 0.5\n", + "score_max_image_wire_max+gbmt max_image_wire_max+gbmt 111 0.5\n", + "score_max_wire_image+gbmt max(wire, image+gbmt) 111 0.5\n", + "score_max_wire_max_image+gbmt max_wire_max_image+gbmt 111 0.5\n", + "score_max(image;wire_max;gbmt) max(image;wire_max;gbmt) 111 0.5\n", + "score_ViewModifier ViewModifier 111 0.5\n", + "score_wire wire 9 0.5\n" + ] + } + ], + "source": [ + "dfmodels = []\n", + "THR = 0.5\n", + "optimal=False\n", + "\n", + "for cc in df_val.columns:\n", + " mdict = {}\n", + " if not cc.startswith(\"score\"):\n", + " continue\n", + "\n", + " label = df_val[\"label\"]!= 'normal'\n", + " fpr_, tpr_, thresholds = roc_curve(label, df_val[cc], pos_label=1)\n", + " cc_out = cc.replace('score_','')\n", + " cc_out = modeldict.get(cc_out, cc_out)\n", + " if optimal:\n", + " try:\n", + " opt_thr = df_performance_test.loc[cc_out, \"thr\"] / 100\n", + " except KeyError as ee:\n", + " print(\"no key '%s' found\" % cc_out)\n", + " else:\n", + " opt_thr = THR\n", + " print(cc, cc_out, label.sum(), opt_thr)\n", + "# pr, rec, thresholds_ = precision_recall_curve(df_test[\"label\"]!= 'normal', df_test[cc], pos_label=1)\n", + " mdict[\"specificity_at_sensitivity100\"] = specificity_at_sensitivity100(fpr_, tpr_)\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_val[cc]>THR)\n", + " mdict[ff.__name__] = mm\n", + " auc_ = auc(fpr_, tpr_)\n", + " mdict[\"auROC\"] = auc_\n", + "# auc_ = auc(pr, rec, )\n", + "# mdict[\"auPRC\"] = auc_\n", + " mdict[\"thr\"] = opt_thr\n", + " mdict[\"model\"] = cc\n", + "# print(cc, auc_)\n", + " dfmodels.append(mdict)\n", + "# break\n", + "\n", + "for cc in [\"score_wire\"]:\n", + " cc_out = cc.replace('score_','')\n", + " cc_out = modeldict.get(cc_out, cc_out)\n", + " mdict = {}\n", + " if not cc.startswith(\"score\"):\n", + " continue\n", + "\n", + " if cc==\"score_wire\": \n", + " label = df_val[\"view\"]== 'W'\n", + " else:\n", + " label = df_val[\"label\"]!= 'normal'\n", + " \n", + " fpr_, tpr_, thresholds = roc_curve(label, df_val[cc], pos_label=1)\n", + " if optimal:\n", + " try:\n", + " opt_thr = df_performance_test.loc[cc_out, \"thr\"] / 100.0\n", + " except KeyError as ee:\n", + " print(\"no key '%s' found\" % cc_out)\n", + "# opt_thr = thresholds[np.argmax(tpr_ - fpr_)]\n", + " else:\n", + " opt_thr = THR\n", + " print(cc, cc_out, label.sum(), opt_thr)\n", + "# pr, rec, thresholds_ = precision_recall_curve(df_test[\"label\"]!= 'normal', df_test[cc], pos_label=1)\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_val[cc]>opt_thr)\n", + " mdict[ff.__name__] = mm\n", + " auc_ = auc(fpr_, tpr_)\n", + " mdict[\"auROC\"] = auc_\n", + "# auc_ = auc(pr, rec, )\n", + "# mdict[\"auPRC\"] = auc_\n", + " mdict[\"thr\"] = opt_thr\n", + " cc = \"score_wire (vs other views)\"\n", + " mdict[\"model\"] = cc\n", + "# print(cc, auc_)\n", + " dfmodels.append(mdict)\n", + " \n", + "dfmodels = pd.DataFrame(dfmodels)[[\"model\", \"auROC\",\"average_precision_score\", \"f1_score\", \n", + " \"precision_score\", \"recall_score\", \"accuracy_score\", 'thr',\n", + " 'specificity_at_sensitivity100']]\n", + "\n", + "dfmodels[\"model\"] = dfmodels[\"model\"].str.replace('score_','')\n", + "dfmodels.columns = [cc.replace('_score','') for cc in dfmodels.columns]\n", + "dfmodels.rename(columns={\"average_precision\":\"auPRC\", \"f1\":\"F1\"}, inplace=True)\n", + "\n", + "dfmodels = dfmodels.set_index('model').round(4)*100\n", + "dfmodels = dfmodels.loc[[ 'ViewModifier', 'rpart', 'gbm', 'glmnet','xgb', 'gbmt', \n", + " 'image',\n", + " 'image_max',\n", + "# 'wire', 'wire_max', \n", + " 'wire (vs other views)',\n", + " 'wire_max (vs other views)',\n", + "# 'max_image_wire',\n", + "# \"image+glmnet\" ,\n", + "# 'max_image_wire+gbmt',\n", + " 'max_image_wire_max',\n", + " 'image+gbmt',\n", + "# 'max_image_wire_max+gbmt',\n", + " 'max_wire_max_image+gbmt',\n", + "# 'max_wire_image+gbmt'\n", + "# # \"image*glmnet\" ,'img*gbmt'\n", + " ]]\n", + "dfmodels.rename(index={\"max_image_wire\":\"max(image, wire)\",\n", + " 'image':'avg(image)',\n", + " 'image_max':'max(image)',\n", + " 'image+gbmt': 'avg(image)+gbmt',\n", + " 'wire_max':'max(wire)', \n", + " 'wire (vs other views)':'avg(wire) (vs other views)',\n", + " 'wire_max (vs other views)':'max(wire) (vs other views)',\n", + " 'max_wire_image+gbmt': 'max(wire, image+gbmt)',\n", + "# \"max_image_wire+gbmt\":\"max(image, wire) + gbmt\",\n", + " 'max_image_wire_max': \"max(avg(image), max(wire))\",\n", + "# 'max_image_wire_max+gbmt':'max(image, max(wire))+gbmt',\n", + " 'max_wire_max_image+gbmt':'max(max(wire), avg(image)+gbmt)',\n", + " }, inplace=True)\n", + "df_performance_val = dfmodels.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "N 604\n", + "M 96\n", + "W 9\n", + "T 4\n", + "X 2\n", + "Name: view, dtype: int64" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_val.view.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(715, 28)" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_val.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Error analysis on the holdout set" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Int64Index([416533, 737995], dtype='int64')" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_val[(df_val['score_max_wire_max_image+gbmt']>0.5) &\n", + " (df_val.label == 'normal')].index" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Int64Index([403353, 605642, 703377], dtype='int64')" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_val[((df_val['score_max_wire_max_image+gbmt']<=0.5) &\n", + " (df_val.label != 'normal'))].index" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'max(max(wire), avg(image)+gbmt)'" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "best_model_name = df_performance_test['auROC'].drop(['avg(wire) (vs other views)',\n", + " 'max(wire) (vs other views)']).argmax()\n", + "# best_model_name = 'max(max(wire),image+gbmt)'\n", + "best_model_name" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Performance table for the validation set + best model for the holdout set" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
auROCauPRCF1precisionrecallaccuracythrspecificity_at_sensitivity100
model
ViewModifier92.2375.0385.4783.3387.7295.3250.00.00
rpart94.3090.3993.95100.0088.6098.2150.00.00
gbm94.8290.3993.95100.0088.6098.2150.01.31
glmnet95.8890.3993.95100.0088.6098.2150.00.33
xgb96.3090.3993.95100.0088.6098.2150.011.11
gbmt96.5990.3993.95100.0088.6098.2150.05.56
avg(image)99.6093.1095.9698.1793.8698.7650.079.41
max(image)99.5292.2695.5497.2793.8698.6250.075.33
avg(wire) (vs other views)100.0091.0595.24100.0090.9199.8650.0100.00
max(wire) (vs other views)100.00100.00100.00100.00100.00100.0050.0100.00
max(avg(image), max(wire))99.9897.5498.6998.2699.1299.5950.097.71
avg(image)+gbmt99.2992.6195.41100.0091.2398.6250.076.14
max(max(wire), avg(image)+gbmt)100.0098.5299.12100.0098.2599.7250.099.84
[holdout] max(max(wire), avg(image)+gbmt)99.7395.9597.7498.1897.3099.3050.088.25
\n", + "
" + ], + "text/plain": [ + " auROC auPRC F1 precision \\\n", + "model \n", + "ViewModifier 92.23 75.03 85.47 83.33 \n", + "rpart 94.30 90.39 93.95 100.00 \n", + "gbm 94.82 90.39 93.95 100.00 \n", + "glmnet 95.88 90.39 93.95 100.00 \n", + "xgb 96.30 90.39 93.95 100.00 \n", + "gbmt 96.59 90.39 93.95 100.00 \n", + "avg(image) 99.60 93.10 95.96 98.17 \n", + "max(image) 99.52 92.26 95.54 97.27 \n", + "avg(wire) (vs other views) 100.00 91.05 95.24 100.00 \n", + "max(wire) (vs other views) 100.00 100.00 100.00 100.00 \n", + "max(avg(image), max(wire)) 99.98 97.54 98.69 98.26 \n", + "avg(image)+gbmt 99.29 92.61 95.41 100.00 \n", + "max(max(wire), avg(image)+gbmt) 100.00 98.52 99.12 100.00 \n", + "[holdout] max(max(wire), avg(image)+gbmt) 99.73 95.95 97.74 98.18 \n", + "\n", + " recall accuracy thr \\\n", + "model \n", + "ViewModifier 87.72 95.32 50.0 \n", + "rpart 88.60 98.21 50.0 \n", + "gbm 88.60 98.21 50.0 \n", + "glmnet 88.60 98.21 50.0 \n", + "xgb 88.60 98.21 50.0 \n", + "gbmt 88.60 98.21 50.0 \n", + "avg(image) 93.86 98.76 50.0 \n", + "max(image) 93.86 98.62 50.0 \n", + "avg(wire) (vs other views) 90.91 99.86 50.0 \n", + "max(wire) (vs other views) 100.00 100.00 50.0 \n", + "max(avg(image), max(wire)) 99.12 99.59 50.0 \n", + "avg(image)+gbmt 91.23 98.62 50.0 \n", + "max(max(wire), avg(image)+gbmt) 98.25 99.72 50.0 \n", + "[holdout] max(max(wire), avg(image)+gbmt) 97.30 99.30 50.0 \n", + "\n", + " specificity_at_sensitivity100 \n", + "model \n", + "ViewModifier 0.00 \n", + "rpart 0.00 \n", + "gbm 1.31 \n", + "glmnet 0.33 \n", + "xgb 11.11 \n", + "gbmt 5.56 \n", + "avg(image) 79.41 \n", + "max(image) 75.33 \n", + "avg(wire) (vs other views) 100.00 \n", + "max(wire) (vs other views) 100.00 \n", + "max(avg(image), max(wire)) 97.71 \n", + "avg(image)+gbmt 76.14 \n", + "max(max(wire), avg(image)+gbmt) 99.84 \n", + "[holdout] max(max(wire), avg(image)+gbmt) 88.25 " + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds_best_performance_val = df_performance_val.loc[best_model_name]\n", + "ds_best_performance_val.name = \"[holdout] \" + ds_best_performance_val.name\n", + "df_performance_test.append(ds_best_performance_val)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "auROC 99.73\n", + "auPRC 95.95\n", + "F1 97.74\n", + "precision 98.18\n", + "recall 97.30\n", + "accuracy 99.30\n", + "thr 50.00\n", + "specificity_at_sensitivity100 88.25\n", + "Name: [holdout] max(max(wire), avg(image)+gbmt), dtype: float64" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# from matplotlib.pyplot import cm\n", + "ds_best_performance_val" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['ViewModifier', 'rpart', 'gbm', 'glmnet', 'xgb', 'gbmt', 'avg(image)',\n", + " 'max(image)', 'avg(wire) (vs other views)',\n", + " 'max(wire) (vs other views)', 'max(avg(image), max(wire))',\n", + " 'avg(image)+gbmt', 'max(max(wire), avg(image)+gbmt)'],\n", + " dtype='object', name='model')" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_performance_test.index" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, figsize=(8.5,6))\n", + "# cmap = haline_r#\n", + "cmap = plt.cm.get_cmap('viridis_r')\n", + "cmap.set_under([0.9]*3)\n", + "\n", + "hm = sns.heatmap(df_performance_test.append(ds_best_performance_val).drop(\n", + " ['thr', 'specificity_at_sensitivity100'], axis=1).rename(\n", + "# index = {'rpart':'RPART', 'gbm':'GBM', 'glmnet':'GLMNet', 'xgb':'XGB', 'gbmt':'GBMT',\n", + "# 'avg(image)+gbmt':'avg(image)+GBMT',\n", + "# 'max(max(wire), avg(image)+gbmt)':'max(max(wire), avg(image)+GBMT)',\n", + "# '[holdout] max(max(wire), avg(image)+gbmt)':'[holdout] max(max(wire), avg(image)+GBMT)',\n", + "# } \n", + "\n", + " index = {'rpart':'RPART', 'gbm':'GBM', 'glmnet':'GLMNet', 'xgb':'XGB', 'gbmt':'GBMT',\n", + " 'avg(image)+gbmt':'image+GBMT',\n", + " 'max(avg(image), max(wire))':'max(image, wire)',\n", + " 'max(max(wire), avg(image)+gbmt)':'max(wire, image+GBMT)',\n", + " 'max(wire, image+gbmt)':'max(wire, image+GBMT)',\n", + " '[holdout] max(max(wire), avg(image)+gbmt)':'[holdout] max(wire, image+GBMT)',\n", + " } ),\n", + " annot=True, fmt=\".2f\", \n", + " annot_kws={\"size\": 12, #'weight':'bold'\n", + " },\n", + " cbar_kws={'extend':'min', 'ticks': np.arange(80,100+1, 5)},\n", + " linewidths=.75, cmap=cmap, vmin=80, vmax=100, ax=ax)\n", + "ax.xaxis.tick_top()\n", + "ax.set_ylabel('')\n", + "locs, labels = plt.yticks()\n", + "plt.setp(labels, rotation=0)\n", + "plt.tight_layout()\n", + "plt.savefig(f\"./img/all_model_performance-{tag}.eps\",)\n", + "plt.savefig(f\"./img/all_model_performance-{tag}.tiff\", dpi=300)\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "auROC 99.73\n", + "auPRC 95.95\n", + "F1 97.74\n", + "precision 98.18\n", + "recall 97.30\n", + "accuracy 99.30\n", + "thr 50.00\n", + "specificity_at_sensitivity100 88.25\n", + "Name: [holdout] max(max(wire), avg(image)+gbmt), dtype: float64" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds_best_performance_val" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calibrate threshold for the whole dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
accuracy_scoreaverage_precision_scoref1_scoreprecision_scorerecall_score
0.0100000.1552450.1552450.2687650.1552451.0
0.0206970.1566430.1554620.2690910.1554621.0
0.0207800.1580420.1556800.2694170.1556801.0
0.0208820.1594410.1558990.2697450.1558991.0
0.0226200.1608390.1561180.2700730.1561181.0
\n", + "
" + ], + "text/plain": [ + " accuracy_score average_precision_score f1_score precision_score \\\n", + "0.010000 0.155245 0.155245 0.268765 0.155245 \n", + "0.020697 0.156643 0.155462 0.269091 0.155462 \n", + "0.020780 0.158042 0.155680 0.269417 0.155680 \n", + "0.020882 0.159441 0.155899 0.269745 0.155899 \n", + "0.022620 0.160839 0.156118 0.270073 0.156118 \n", + "\n", + " recall_score \n", + "0.010000 1.0 \n", + "0.020697 1.0 \n", + "0.020780 1.0 \n", + "0.020882 1.0 \n", + "0.022620 1.0 " + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# df_val[\"score_max_wire_img+gbmt\"]\n", + "# df_val.label\n", + "cc = \"score_image+gbmt\"\n", + "df_thr_calibration = {}\n", + "\n", + "label = df_val[\"label\"]!= 'normal'\n", + "# _,_, thresholds = roc_curve(label, df_val[cc])\n", + "\n", + "thresholds = df_val[cc].unique()\n", + "thresholds = thresholds[(thresholds<=0.5) & (thresholds>=1e-3)]\n", + "thresholds = sorted([0.01] + thresholds.tolist() + [0.5])\n", + "# thresholds = thresholds[::-1]\n", + "# thresholds = thresholds[thresholds<=0.5]\n", + "\n", + "# for thr in [0.01, 0.02, 0.03, 0.04] + np.arange(0.05, 0.55, 0.05).tolist():\n", + "for thr in [0.01] + thresholds:# np.arange(0.01, 0.51, 0.01).tolist():\n", + " mdict = {}\n", + "\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_val[cc]>thr)\n", + " mdict[ff.__name__] = mm\n", + " df_thr_calibration[thr] = pd.Series(mdict)\n", + " del mdict\n", + "df_thr_calibration = pd.DataFrame(df_thr_calibration).T\n", + "df_thr_calibration.to_csv(\"threshold_calibration_{}.csv\".format(cc))\n", + "df_thr_calibration.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xticks = [0.01, 0.03, 0.05, 0.1, 0.3, 0.5]\n", + "fig, ax = plt.subplots(1)\n", + "(100*df_thr_calibration.recall_score).plot(ax=ax)\n", + "plt.xscale('log')\n", + "\n", + "ax.set_xticks(xticks)\n", + "ax.set_xlim([0.008, xticks[-1] + xticks[0]])\n", + "# ax.set_yticks(np.arange(97.0, 100.5, 1.0))\n", + "\n", + "ax.axes.yaxis.set_tick_params(rotation=0, labelsize=14)\n", + "ax.set_xticklabels(xticks, fontdict={\"fontsize\": 14})\n", + "\n", + "plt.xlabel(\"threshold\", fontdict={\"fontsize\": 16})\n", + "plt.ylabel(\"recall, %\" , fontdict={\"fontsize\": 16})\n", + "plt.title(cc)\n", + "\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
accuracy_scoreaverage_precision_scoref1_scoreprecision_scorerecall_score
0.0011400.9818180.4090910.5806450.4090911.0
0.0012090.9832170.4285710.6000000.4285711.0
0.0015190.9846150.4500000.6206900.4500001.0
0.0016240.9860140.4736840.6428570.4736841.0
0.0016430.9874130.5000000.6666670.5000001.0
\n", + "
" + ], + "text/plain": [ + " accuracy_score average_precision_score f1_score precision_score \\\n", + "0.001140 0.981818 0.409091 0.580645 0.409091 \n", + "0.001209 0.983217 0.428571 0.600000 0.428571 \n", + "0.001519 0.984615 0.450000 0.620690 0.450000 \n", + "0.001624 0.986014 0.473684 0.642857 0.473684 \n", + "0.001643 0.987413 0.500000 0.666667 0.500000 \n", + "\n", + " recall_score \n", + "0.001140 1.0 \n", + "0.001209 1.0 \n", + "0.001519 1.0 \n", + "0.001624 1.0 \n", + "0.001643 1.0 " + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# df_val[\"score_max_wire_img+gbmt\"]\n", + "# df_val.label\n", + "cc = \"score_wire\"\n", + "df_thr_calibration = {}\n", + "# for thr in [0.01, 0.02, 0.03, 0.04] + np.arange(0.05, 0.55, 0.05).tolist():\n", + "\n", + "label = df_val[\"view\"]== 'W'\n", + "# _,_, thresholds = roc_curve(label, df_val[cc])\n", + "# thresholds = thresholds[::-1]\n", + "thresholds = df_val[cc].unique()\n", + "thresholds = thresholds[(thresholds<=0.5) & (thresholds>=1e-3)]\n", + "thresholds = sorted([0.01] + thresholds.tolist() + [0.5])\n", + "# thresholds.remove(0.0)\n", + "\n", + "for thr in thresholds:# np.arange(0.01, 0.51, 0.01).tolist():\n", + " mdict = {}\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_val[cc]>thr)\n", + " mdict[ff.__name__] = mm\n", + " df_thr_calibration[thr] = pd.Series(mdict)\n", + " del mdict\n", + "df_thr_calibration = pd.DataFrame(df_thr_calibration).T\n", + "df_thr_calibration.to_csv(f\"threshold_calibration_{cc}-{tag}.csv\")\n", + "df_thr_calibration.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.006923830000000075" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "thr_wire = df_thr_calibration[df_thr_calibration.recall_score==1.0].f1_score.argmax()\n", + "thr_wire" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xticks = [0.01, 0.03, 0.05, 0.1, 0.3, 0.5]\n", + "fig, ax = plt.subplots(1)\n", + "(100*df_thr_calibration.recall_score).plot(ax=ax)\n", + "plt.xscale('log')\n", + "\n", + "ax.set_xticks(xticks)\n", + "# ax.set_xlim([0.008, xticks[-1] + xticks[0]])\n", + "# ax.set_yticks(np.arange(97.0, 100.5, 1.0))\n", + "\n", + "ax.axes.yaxis.set_tick_params(rotation=0, labelsize=14)\n", + "ax.set_xticklabels(xticks, fontdict={\"fontsize\": 14})\n", + "\n", + "plt.xlabel(\"threshold\", fontdict={\"fontsize\": 16})\n", + "plt.ylabel(\"recall, %\" , fontdict={\"fontsize\": 16})\n", + "plt.title(cc)\n", + "\n", + "\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.013986013986013986" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(df_val['score_wire']>thr_wire).mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.012587412587412588" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(df_val[cc]>0.5).mean()\n", + "# thresholds" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "threshold_calibration_score_image+gbmt-fixed_wire-e5ce2d69b035975cb5336cec0da9a32a.csv\n", + "1.0\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
accuracy_scoreaverage_precision_scoref1_scoreprecision_scorerecall_score
0.0100000.1552450.1552450.2687650.1552451.0
0.0206970.1566430.1554620.2690910.1554621.0
0.0207800.1580420.1556800.2694170.1556801.0
0.0208820.1594410.1558990.2697450.1558991.0
0.0226200.1608390.1561180.2700730.1561181.0
\n", + "
" + ], + "text/plain": [ + " accuracy_score average_precision_score f1_score precision_score \\\n", + "0.010000 0.155245 0.155245 0.268765 0.155245 \n", + "0.020697 0.156643 0.155462 0.269091 0.155462 \n", + "0.020780 0.158042 0.155680 0.269417 0.155680 \n", + "0.020882 0.159441 0.155899 0.269745 0.155899 \n", + "0.022620 0.160839 0.156118 0.270073 0.156118 \n", + "\n", + " recall_score \n", + "0.010000 1.0 \n", + "0.020697 1.0 \n", + "0.020780 1.0 \n", + "0.020882 1.0 \n", + "0.022620 1.0 " + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# df_val[\"score_max_wire_img+gbmt\"]\n", + "# df_val.label\n", + "cc = \"score_image+gbmt\"\n", + "df_thr_calibration = {}\n", + "# for thr in [0.01, 0.02, 0.03, 0.04] + np.arange(0.05, 0.55, 0.05).tolist():\n", + "\n", + "label = df_val[\"label\"]!= 'normal'\n", + "# _,_, thresholds = roc_curve(label, df_val[cc])\n", + "thresholds = df_val[cc].unique()\n", + "thresholds = thresholds[(thresholds<=0.5) & (thresholds>=1e-3)]\n", + "thresholds = sorted([0.01] + thresholds.tolist() + [0.5])\n", + "\n", + "for thr in thresholds:# np.arange(0.01, 0.51, 0.01).tolist():\n", + " mdict = {}\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, (df_val[cc]>thr) | (df_val['score_wire']>thr_wire))\n", + " mdict[ff.__name__] = mm\n", + " df_thr_calibration[thr] = pd.Series(mdict)\n", + " del mdict\n", + "df_thr_calibration = pd.DataFrame(df_thr_calibration).T\n", + "outfn = f\"threshold_calibration_{cc}-fixed_wire-{tag}.csv\"\n", + "print(outfn)\n", + "df_thr_calibration.to_csv(outfn)\n", + "print(df_thr_calibration.recall_score.max())\n", + "df_thr_calibration.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xticks = [0.01, 0.03, 0.05, 0.1, 0.3, 0.5]\n", + "fig, ax = plt.subplots(1)\n", + "(100*df_thr_calibration.recall_score).plot(ax=ax)\n", + "plt.xscale('log')\n", + "\n", + "ax.set_xticks(xticks)\n", + "# ax.set_xlim([0.008, xticks[-1] + xticks[0]])\n", + "# ax.set_yticks(np.arange(97.0, 100.5, 1.0))\n", + "\n", + "ax.axes.yaxis.set_tick_params(rotation=0, labelsize=14)\n", + "ax.set_xticklabels(xticks, fontdict={\"fontsize\": 14})\n", + "\n", + "plt.xlabel(\"threshold\", fontdict={\"fontsize\": 16})\n", + "plt.ylabel(\"recall, %\" , fontdict={\"fontsize\": 16})\n", + "plt.title(cc)\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
accuracy_scoreaverage_precision_scoref1_scoreprecision_scorerecall_score
0.0100000.1552450.1552450.2687650.1552451.0
0.0206970.1566430.1554620.2690910.1554621.0
0.0207800.1580420.1556800.2694170.1556801.0
0.0208820.1594410.1558990.2697450.1558991.0
0.0226200.1608390.1561180.2700730.1561181.0
\n", + "
" + ], + "text/plain": [ + " accuracy_score average_precision_score f1_score precision_score \\\n", + "0.010000 0.155245 0.155245 0.268765 0.155245 \n", + "0.020697 0.156643 0.155462 0.269091 0.155462 \n", + "0.020780 0.158042 0.155680 0.269417 0.155680 \n", + "0.020882 0.159441 0.155899 0.269745 0.155899 \n", + "0.022620 0.160839 0.156118 0.270073 0.156118 \n", + "\n", + " recall_score \n", + "0.010000 1.0 \n", + "0.020697 1.0 \n", + "0.020780 1.0 \n", + "0.020882 1.0 \n", + "0.022620 1.0 " + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# df_val[\"score_max_wire_img+gbmt\"]\n", + "# df_val.label\n", + "cc = \"score_max_wire_image+gbmt\"\n", + "df_thr_calibration = {}\n", + "# for thr in [0.01, 0.02, 0.03, 0.04] + np.arange(0.05, 0.55, 0.05).tolist():\n", + "label = df_val[\"label\"]!= 'normal'\n", + "thresholds = df_val[cc].unique()\n", + "thresholds = thresholds[(thresholds<=0.5) & (thresholds>=1e-3)]\n", + "thresholds = sorted([0.01] + thresholds.tolist() + [0.5])\n", + "\n", + "for thr in thresholds:\n", + " mdict = {}\n", + " for ff in [f1_score, accuracy_score, precision_score, recall_score, average_precision_score]:\n", + " mm = ff(label, df_val[cc]>thr)\n", + " mdict[ff.__name__] = mm\n", + " df_thr_calibration[thr] = pd.Series(mdict)\n", + " del mdict\n", + "df_thr_calibration = pd.DataFrame(df_thr_calibration).T\n", + "df_thr_calibration.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
accuracy_scoreaverage_precision_scoref1_scoreprecision_scorerecall_score
0.1116080.9888110.9331000.9649120.9401710.990991
0.1458410.9902100.9411310.9691630.9482760.990991
0.1574180.9916080.9493030.9734510.9565220.990991
0.1604150.9930070.9576180.9777780.9649120.990991
0.1745400.9944060.9660800.9821430.9734510.990991
\n", + "
" + ], + "text/plain": [ + " accuracy_score average_precision_score f1_score precision_score \\\n", + "0.111608 0.988811 0.933100 0.964912 0.940171 \n", + "0.145841 0.990210 0.941131 0.969163 0.948276 \n", + "0.157418 0.991608 0.949303 0.973451 0.956522 \n", + "0.160415 0.993007 0.957618 0.977778 0.964912 \n", + "0.174540 0.994406 0.966080 0.982143 0.973451 \n", + "\n", + " recall_score \n", + "0.111608 0.990991 \n", + "0.145841 0.990991 \n", + "0.157418 0.990991 \n", + "0.160415 0.990991 \n", + "0.174540 0.990991 " + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_thr_calibration.loc[0.1:0.2]" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "df_thr_calibration.to_csv(f\"threshold_calibration_final_model-{tag}.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xticks = [0.01, 0.03, 0.05, 0.1, 0.3, 0.5]\n", + "fig, ax = plt.subplots(1)\n", + "(100*df_thr_calibration.recall_score).plot(ax=ax)\n", + "plt.xscale('log')\n", + "\n", + "ax.set_xticks(xticks)\n", + "ax.set_xlim([0.008, xticks[-1] + xticks[0]])\n", + "ax.set_yticks(np.arange(97.0, 100.5, 1.0))\n", + "\n", + "ax.axes.yaxis.set_tick_params(rotation=0, labelsize=14)\n", + "ax.set_xticklabels(xticks, fontdict={\"fontsize\": 14})\n", + "\n", + "plt.xlabel(\"threshold\", fontdict={\"fontsize\": 16})\n", + "plt.ylabel(\"recall, %\" , fontdict={\"fontsize\": 16})\n", + "\n", + "pass" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [default]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}