Kaggle competition: APTOS 2019 Blindness Detection
<SOS> metric: QuadraticWeightedKappa Kaggle data source: aptos-2019-blindness-detection<define_variables>
%reload_ext autoreload
%autoreload 2
%matplotlib inline
DATA = '.. /input/prostate-cancer-grade-assessment/test_images'
TEST = '.. /input/prostate-cancer-grade-assessment/test.csv'
SAMPLE = '.. /input/prostate-cancer-grade-assessment/sample_submission.csv'
MODELS = [f'.. /input/panda-init-class-model1/RNXT50_128k_0_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128k_3_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_1_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_2_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_2feature_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_9_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_7c_{i}.pth' for i in range(4)] + \
[f'.. /input/panda-init-class-model1/RNXT50_128kr_3_{i}.pth' for i in range(4)]
ws = [1.0,1.0,1.0,7.0,1.0,1.0,1.0,1.0]
sz = 128
bs = 1
N = 128
nworkers = 2<choose_model_class>
import fastai
from fastai import *
from fastai.vision import *
from fastai.callbacks import *
import cv2
import pandas as pd
import matplotlib.pyplot as plt
def _resnext(url, block, layers, pretrained, progress, **kwargs):
model = ResNet(block, layers, **kwargs)
 return model
class Model(nn.Module):
def __init__(self, arch='resnext50_32x4d', n=6, pre=True):
super().__init__()
m = _resnext(semi_supervised_model_urls[arch], Bottleneck, [3, 4, 6, 3], False, progress=False,\
groups=32,width_per_group=4)
 self.enc = nn.Sequential(*list(m.children())[:-2])
 nc = list(m.children())[-1].in_features
self.head = nn.Sequential(AdaptiveConcatPool2d() ,Flatten() ,
nn.Linear(2*nc,512),Mish() ,nn.GroupNorm(32,512),
nn.Dropout(0.5),nn.Linear(512,n))
def forward(self, x):
shape = x.shape
n = shape[1]
x = x.view(-1,shape[2],shape[3],shape[4])
 x = self.enc(x)
 shape = x.shape
x = x.view(-1,n,shape[1],shape[2],shape[3] ).permute(0,2,1,3,4 ).contiguous() \ 
.view(-1,shape[1],shape[2]*n,shape[3])
 x = self.head(x)
 return x[:,:1]<train_model>
def seed_everything(seed):
random.seed(seed)
 os.environ['PYTHONHASHSEED'] = str(seed)
 np.random.seed(seed)
 torch.manual_seed(seed)
 torch.cuda.manual_seed(seed)
 torch.backends.cudnn.deterministic = True
SEED = 1667
seed_everything(SEED )
models = []
for path in MODELS:
state_dict = torch.load(path,map_location=torch.device('cpu'))
model = Model(n=1+10)
 model.load_state_dict(state_dict)
 model.float()
model.eval()
model.cuda()
models.append(model)
 del state_dict<train_model>
base_image_dir = os.path.join('.. ', 'input/aptos2019-blindness-detection/')
 train_dir = os.path.join(base_image_dir,'train_images/')
 df = pd.read_csv(os.path.join(base_image_dir, 'train.csv'))
df['path'] = df['id_code'].map(lambda x: os.path.join(train_dir,'{}.png'.format(x)))
 df = df.drop(columns=['id_code'])
 df = df.sample(frac=1 ).reset_index(drop=True)
 df.head(10 )
def tile(img):
shape = img.shape
pad0,pad1 =(sz - shape[0]%sz)%sz,(sz - shape[1]%sz)%sz
img = np.pad(img,[[pad0//2,pad0-pad0//2],[pad1//2,pad1-pad1//2],[0,0]],constant_values=255)
 img = img.reshape(img.shape[0]//sz,sz,img.shape[1]//sz,sz,3)
 img = img.transpose(0,2,1,3,4 ).reshape(-1,sz,sz,3)
 if len(img)< N:
img = np.pad(img,[[0,N-len(img)],[0,0],[0,0],[0,0]],constant_values=255)
 idxs = np.argsort(img.reshape(img.shape[0],-1 ).sum(-1)) [:N]
img = img[idxs]
return img
mean = torch.Tensor([1.0-0.85506157, 1.0-0.7035249, 1.0-0.80203127])
 std = torch.Tensor([0.40011922, 0.52504386, 0.42675745])
 class PandaDataset(Dataset):
def __init__(self, path, test):
self.path = path
self.names = list(pd.read_csv(test ).image_id)
 def __len__(self):
return len(self.names)
 def __getitem__(self, idx):
name = self.names[idx]
img = skimage.io.MultiImage(os.path.join(DATA,name+'.tiff')) [1]
tiles = torch.Tensor(( 255 - tile(img)) /255.0)
 tiles =(tiles - mean)/std
return tiles.permute(0,3,1,2), name<create_dataframe>
bs=32
src =(ImageList.from_df(df=df,path='./',cols='path')
.split_by_rand_pct(0.2, seed=42)
.label_from_df(cols='diagnosis',label_cls=FloatList)
)
 src
ths = np.array([1.03125,1.03125,0.8125,0.90625,1.0859375] ).cumsum()
ws = torch.Tensor(ws ).cuda()
sub_df = pd.read_csv(SAMPLE)
 if os.path.exists(DATA):
bs=2
ds = PandaDataset(DATA,TEST)
 dl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)
 names,preds = [],[]
with torch.no_grad() :
for x,y in tqdm(dl):
x = x.cuda()
b = x.shape[0]
x = torch.stack([x,x.flip(-1),x.flip(-2),x.flip(-1,-2),x.transpose(-1,-2),\
x.transpose(-1,-2 ).flip(-1)],1)
 n_tta = 6
x = x.view(-1,N,3,sz,sz)
 p = [model(x)for model in models]
p = torch.stack(p,1)
 p = p.view(b,n_tta,len(models)//4,4 ).permute(0,2,3,1 ).reshape(b,len(models)//4,4*n_tta)
 w = ws/torch.clamp(p.std(-1),0.04)
 w /= w.sum(-1 ).unsqueeze(-1)
 p =(p*w.unsqueeze(-1)).mean(-1 ).sum(-1 ).cpu()
p = 6.0*torch.sigmoid(p ).view(-1)
 for pi,yi in zip(p,y):
preds.append(bisect_right(ths, pi.numpy()))
names.append(yi)
 sub_df = pd.DataFrame({'image_id': names, 'isup_grade': preds} )<save_to_csv>
tfms = get_transforms(do_flip=True, flip_vert=True, max_rotate=0.10, max_zoom=1.3, max_warp=0.0, max_lighting=0.2)
 data =(
 src.transform(tfms,size=128)
.databunch(bs=bs)
.normalize(imagenet_stats)
)
 data
sub_df.to_csv("submission.csv", index=False)
 sub_df.head()<define_variables>
def quadratic_kappa(y_hat, y):
return torch.tensor(cohen_kappa_score(torch.round(y_hat), y, weights='quadratic'),device='cuda:0' )
sys.path = [
'.. /input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master',
] + sys.path<define_variables>
learn = cnn_learner(data, base_arch=models.resnet50 ,metrics=[quadratic_kappa],model_dir='/kaggle',pretrained=True,
callback_fns=[partial(EarlyStoppingCallback, monitor='quadratic_kappa', min_delta=0.01, patience=3)] )
sys.path = [
'.. /input/ttach-kaggle/ttach/',
] + sys.path 
<import_modules>
learn.fit_one_cycle(4, 1e-2)
import skimage.io
import numpy as np
import pandas as pd
import torchvision
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader, Dataset
from efficientnet_pytorch import model as enet
import matplotlib.pyplot as plt
from tqdm import tqdm_notebook as tqdm<load_from_csv>
learn.save('stage1' )
data_dir = '.. /input/prostate-cancer-grade-assessment'
df_train = pd.read_csv(os.path.join(data_dir, 'train.csv'))
df_test = pd.read_csv(os.path.join(data_dir, 'test.csv'))
df_sub = pd.read_csv(os.path.join(data_dir, 'sample_submission.csv'))
model_dir = '.. /input/panda-public-models'
image_folder = os.path.join(data_dir, 'test_images')
 is_test = os.path.exists(image_folder)
 image_folder = image_folder if is_test else os.path.join(data_dir, 'train_images')
 df = df_test if is_test else df_train.loc[:16]
tile_size = 256
image_size = 256
n_tiles = 36
batch_size = 4
num_workers = 4
device = torch.device('cuda')
 print(image_folder )<import_modules>
data =(
 src.transform(tfms,size=224)
.databunch(bs=bs)
.normalize(imagenet_stats)
)
 data
class enetv3(nn.Module):
def __init__(self, modelname, out_dim=5, freeze_bn=True):
super(enetv3, self ).__init__()
self.basemodel = EfficientNet.from_name(modelname)
 self.myfc = nn.Linear(self.basemodel._fc.in_features, out_dim)
 self.basemodel._fc = nn.Identity()
self.basemodel._avg_pooling = nn.AdaptiveAvgPool2d(1)
 def extract(self, x):
return self.basemodel(x)
 def forward(self, x):
x = self.basemodel(x)
 if not "eff" in modelname:
x = self.pool(x ).squeeze(2 ).squeeze(2)
 x = self.myfc(x)
 else:
x = self.myfc(x)
 return x
def load_models(model_files):
models = []
for model_f in model_files:
model_f = os.path.join(".. /input/latesubspanda", model_f)
 if "res" in model_f:
model = enetv2(out_dim=5)
 elif "eff" in model_f:
model = enetv3(modelname, out_dim=5)
 model.load_state_dict(torch.load(model_f))
model.eval()
model.to(device)
 models.append(model)
 print(f'{model_f} loaded!')
 return models
modelname="efficientnet-b0"
model_files2 = [
"efficientnet-b0famlabelsmodelsub_avgpool_tile36_imsize256_mixup_final_epoch20_fold0.pth",
"efficientnet-b0famlabelsmodelsub_avgpool_tile36_imsize256_mixup_final_epoch20_fold1.pth",
"efficientnet-b0famlabelsmodelsub_avgpool_tile36_imsize256_mixup_final_epoch20_fold2.pth",
"efficientnet-b0famlabelsmodelsub_avgpool_tile36_imsize256_mixup_final_epoch20_fold3.pth",
"efficientnet-b0famlabelsmodelsub_avgpool_tile36_imsize256_mixup_final_epoch20_fold4.pth"
]
models2 = load_models(model_files2 )<categorify>
learn.fit_one_cycle(4, 1e-2 )
def get_tiles(img, mode=0):
result = []
h, w, c = img.shape
pad_h =(tile_size - h % tile_size)% tile_size +(( tile_size * mode)// 2)
 pad_w =(tile_size - w % tile_size)% tile_size +(( tile_size * mode)// 2)
 img2 = np.pad(img,[[pad_h // 2, pad_h - pad_h // 2], [pad_w // 2,pad_w - pad_w//2], [0,0]], constant_values=255)
 img3 = img2.reshape(
 img2.shape[0] // tile_size,
tile_size,
img2.shape[1] // tile_size,
tile_size,
3 
)
 img3 = img3.transpose(0,2,1,3,4 ).reshape(-1, tile_size, tile_size,3)
 n_tiles_with_info =(img3.reshape(img3.shape[0],-1 ).sum(1)< tile_size ** 2 * 3 * 255 ).sum()
if len(img)< n_tiles:
img3 = np.pad(img3,[[0,N-len(img3)],[0,0],[0,0],[0,0]], constant_values=255)
 idxs = np.argsort(img3.reshape(img3.shape[0],-1 ).sum(-1)) [:n_tiles]
img3 = img3[idxs]
for i in range(len(img3)) :
result.append({'img':img3[i], 'idx':i})
 return result, n_tiles_with_info >= n_tiles
class PANDADataset(Dataset):
def __init__(self,
df,
image_size,
n_tiles=n_tiles,
tile_mode=0,
rand=False,
sub_imgs=False 
):
self.df = df.reset_index(drop=True)
 self.image_size = image_size
self.n_tiles = n_tiles
self.tile_mode = tile_mode
self.rand = rand
self.sub_imgs = sub_imgs
def __len__(self):
return self.df.shape[0]
def __getitem__(self, index):
row = self.df.iloc[index]
img_id = row.image_id
tiff_file = os.path.join(image_folder, f'{img_id}.tiff')
 image = skimage.io.MultiImage(tiff_file)[1][:,:,::-1]
tiles, OK = get_tiles(image, self.tile_mode)
 if self.rand:
idxes = np.random.choice(list(range(self.n_tiles)) , self.n_tiles, replace=False)
 else:
idxes = list(range(self.n_tiles))
idxes = np.asarray(idxes)+ self.n_tiles if self.sub_imgs else idxes
n_row_tiles = int(np.sqrt(self.n_tiles))
images = np.zeros(( image_size * n_row_tiles, image_size * n_row_tiles, 3))
for h in range(n_row_tiles):
for w in range(n_row_tiles):
i = h * n_row_tiles + w
if len(tiles)> idxes[i]:
this_img = tiles[idxes[i]]['img']
else:
this_img = np.ones(( self.image_size, self.image_size, 3)).astype(np.uint8)* 255
this_img = 255 - this_img
h1 = h * image_size
w1 = w * image_size
images[h1:h1+image_size, w1:w1+image_size] = this_img
images = images.astype(np.float32)
 images /= 255
images = images.transpose(2, 0, 1)
 return torch.tensor(images )<create_dataframe>
learn.fit_one_cycle(10, max_lr=slice(1e-6,1e-3))
dataset = PANDADataset(df, image_size, n_tiles, 0)
 loader = DataLoader(dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False)
 dataset2 = PANDADataset(df, image_size, n_tiles, 2)
 loader2 = DataLoader(dataset2, batch_size=batch_size, num_workers=num_workers, shuffle=False )<choose_model_class>
valid_preds = learn.get_preds(ds_type=DatasetType.Valid )
if len(dataset)> 50:
transforms = tta.Compose(
 [
tta.HorizontalFlip() ,
tta.VerticalFlip() ,
tta.Rotate90(angles=[0, 90, 180]),
] 
)
 else:
transforms = tta.Compose(
 [
] 
)
 tta_models2 = []
for model in models2:
tta_models2.append(tta.ClassificationTTAWrapper(model, transforms))<categorify>
import numpy as np
import pandas as pd
import os
import scipy as sp
from functools import partial
from sklearn import metrics
from collections import Counter
import json
LOGITS = []
LOGITS2 = []
LOGITS12 = []
LOGITS22 = []
with torch.no_grad() :
for data in tqdm(loader):
data = data.to(device)
 for i, tta_model in enumerate(tta_models2):
if i == 0:
logits = tta_model(data ).sigmoid()
else:
logits = logits + tta_model(data ).sigmoid()
LOGITS2.append(logits/5)
 for data in tqdm(loader2):
data = data.to(device)
 for i, tta_model in enumerate(tta_models2):
if i == 0:
logits = tta_model(data ).sigmoid()
else:
logits = logits + tta_model(data ).sigmoid()
LOGITS22.append(logits/5)
 LOGITS =(torch.cat(LOGITS2 ).cpu() + torch.cat(LOGITS22 ).cpu())/ 2<feature_engineering>
class OptimizedRounder(object):
def __init__(self):
self.coef_ = 0
def _kappa_loss(self, coef, X, y):
X_p = np.copy(X)
 for i, pred in enumerate(X_p):
if pred < coef[0]:
X_p[i] = 0
elif pred >= coef[0] and pred < coef[1]:
X_p[i] = 1
elif pred >= coef[1] and pred < coef[2]:
X_p[i] = 2
elif pred >= coef[2] and pred < coef[3]:
X_p[i] = 3
else:
X_p[i] = 4
ll = metrics.cohen_kappa_score(y, X_p, weights='quadratic')
 return -ll
def fit(self, X, y):
loss_partial = partial(self._kappa_loss, X=X, y=y)
 initial_coef = [0.5, 1.5, 2.5, 3.5]
self.coef_ = sp.optimize.minimize(loss_partial, initial_coef, method='nelder-mead')
 print(-loss_partial(self.coef_['x']))
def predict(self, X, coef):
X_p = np.copy(X)
 for i, pred in enumerate(X_p):
if pred < coef[0]:
X_p[i] = 0
elif pred >= coef[0] and pred < coef[1]:
X_p[i] = 1
elif pred >= coef[1] and pred < coef[2]:
X_p[i] = 2
elif pred >= coef[2] and pred < coef[3]:
X_p[i] = 3
else:
X_p[i] = 4
return X_p
def coefficients(self):
return self.coef_['x']
PREDS = LOGITS.sum(1 ).numpy()
df['isup_grade'] = PREDS
df<feature_engineering>
optR = OptimizedRounder()
optR.fit(valid_preds[0],valid_preds[1] )
df['isup_grade'] = df['isup_grade'].apply(lambda x: int(np.round(x)) )<save_to_csv>
sample_df = pd.read_csv('.. /input/aptos2019-blindness-detection/sample_submission.csv')
 sample_df.head()
<define_variables><EOS> 
learn.data.add_test(ImageList.from_df(sample_df,'.. /input/aptos2019-blindness-detection',folder='test_images',suffix='.png'))
preds,y = learn.TTA(ds_type=DatasetType.Test)
 test_predictions = optR.predict(preds, coefficients)
 sample_df.diagnosis = test_predictions.astype(int)
 sample_df.head()
sample_df.to_csv('submission.csv',index=False )