Kaggle competition: Cassava Leaf Disease Classification
<feature_engineering>
CONFIG_NAME = 'stacking12.yml'
debug = False
STAGE2_DIR = '.. /input/train-stacking-2dcnn-ver3/output'
print("Making submission...")
 y_test = np.array(test_pred ).transpose()
df_preds = pd.DataFrame(
 y_test, index=df_2017.index,
columns=pd.date_range("2017-08-16", periods=16)
 ).stack().to_frame("unit_sales")
 df_preds.index.set_names(["store_nbr", "item_nbr", "date"], inplace=True)
 submission = df_test[["id"]].join(df_preds, how="left" ).fillna(0)
 submission["unit_sales"] = np.clip(np.expm1(submission["unit_sales"]), 0, 1000 )<save_to_csv>
CONFIG_PATH = f'{STAGE2_DIR}/{CONFIG_NAME}'
with open(CONFIG_PATH)as f:
config = yaml.load(f)
 INFO = config['info']
TAG = config['tag']
CFG = config['cfg']
OUTPUT_DIR = './'
DATA_PATH = '.. /input/cassava-leaf-disease-classification'
submission.to_csv('lgb6w.csv', float_format='%.4f', index=None )<import_modules>
! nvidia-smi<install_modules>
sys.path.append('.. /input/pytorch-image-models/pytorch-image-models-master')
 Compose, OneOf, Normalize, Resize, RandomResizedCrop, RandomCrop, HorizontalFlip, VerticalFlip,
RandomBrightness, RandomContrast, RandomBrightnessContrast, Rotate, ShiftScaleRotate, Cutout,
IAAAdditiveGaussianNoise, Transpose, CenterCrop 
)
 warnings.filterwarnings('ignore')
 if CFG['debug']:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 else:
device = torch.device('cuda')
 start_time = datetime.datetime.now()
start_time_str = start_time.strftime('%m%d%H%M' )
! pip install torch
! pip install torchvision<import_modules>
train = pd.read_csv(f'{DATA_PATH}/train.csv')
 test = pd.read_csv(f'{DATA_PATH}/sample_submission.csv')
 label_map = pd.read_json(f'{DATA_PATH}/label_num_to_disease_map.json',
orient='index')
 if CFG['debug']:
train = train.sample(n=1000, random_state=CFG['seed'] ).reset_index(drop=True )
import pandas as pd
import subprocess
import torch
import torch.optim as optim
from torch import nn
from torch.utils.data import Dataset
from torch.utils.data.sampler import SubsetRandomSampler
import torchvision
from torchvision import transforms
import os
import random
from glob import glob
import cv2
import numpy as np
from tqdm.notebook import tqdm<define_variables>
model_dirs = []
for stage1 in CFG['stage1_models']:
num = str(stage1 ).rjust(2, '0')
 output_dir_ = glob.glob(f'.. /input/{num}*/')
 assert len(output_dir_)== 1, output_dir_
model_dirs.append(output_dir_[0])
 model_dirs
EPOCH = 100
BATCH_SIZE = 16
PATIENCE = 5
DATA_PATH = '.. /input/state-farm-distracted-driver-detection'
MODEL_NAME = './model.baseline.driver_split.data_aug'<normalization>
normal_configs = []
tta_configs = []
normal_model_dirs = []
tta_model_dirs = []
for model_dir in model_dirs:
assert len(glob.glob(f'{model_dir}/*.yml')) ==1
config_path = glob.glob(f'{model_dir}/*.yml')[0]
with open(config_path)as f:
config = yaml.load(f)
 if 'valid_augmentation' in config['tag'].keys() :
tta_model_dirs.append(model_dir)
 tta_configs.append(config)
 else:
normal_model_dirs.append(model_dir)
 normal_configs.append(config )
transform = transforms.Compose([
transforms.RandomAffine(30, translate=(0.3, 0.3)) ,
transforms.RandomPerspective(p=0.1),
transforms.RandomRotation(degrees=30),
transforms.Resize(( 224, 224)) ,
transforms.ToTensor() ,
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])] )<load_from_csv>
def get_score(y_true, y_pred):
return accuracy_score(y_true, y_pred)
 def remove_glob(pathname, recursive=True):
for p in glob.glob(pathname, recursive=recursive):
if os.path.isfile(p):
os.remove(p)
 @contextmanager
def timer(name):
t0 = time.time()
LOGGER.info(f'[{name}] start')
 yield
LOGGER.info(f'[{name}] done in {time.time() - t0:.0f} s.')
 def seed_torch(seed=42):
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
classes = [f'c{i}' for i in range(10)]
seed = 2020
validation_split = 0.2
driver_list = pd.read_csv(f'{DATA_PATH}/driver_imgs_list.csv')
 drivers = np.unique(driver_list['subject'].values)
 split = int(np.floor(validation_split * len(drivers)))
 np.random.seed(seed)
 trn_idx, val_idx = drivers[split:], drivers[:split]<load_pretrained>
TRAIN_PATH = '.. /input/cassava-leaf-disease-classification/train_images'
TEST_PATH = '.. /input/cassava-leaf-disease-classification/test_images'
train_dataset = torchvision.datasets.ImageFolder(f'./{split_dir}/train',
transform=transform)
 train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=2)
 valid_transform = transforms.Compose([
transforms.Resize(( 224, 224)) ,
transforms.ToTensor() ,
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
 valid_dataset = torchvision.datasets.ImageFolder(f'./{split_dir}/valid',
transform=valid_transform)
 valid_loader = torch.utils.data.DataLoader(valid_dataset,
batch_size=BATCH_SIZE,
num_workers=2 )<set_options>
class TestDataset(Dataset):
def __init__(self, df, transform=None):
self.df = df
self.file_names = df['image_id'].values
self.transform = transform
def __len__(self):
return len(self.df)
 def __getitem__(self, idx):
file_name = self.file_names[idx]
file_path = f'{TEST_PATH}/{file_name}'
image = cv2.imread(file_path)
 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
 if self.transform:
augmented = self.transform(image=image)
 image = augmented['image']
return image
class TTADataset(Dataset):
def __init__(self, df, image_path, ttas):
self.df = df
self.file_names = df['image_id'].values
self.labels = df['label'].values
self.image_path = image_path
self.ttas = ttas
def __len__(self)-> int:
return len(self.df)
 def __getitem__(self, idx):
file_name = self.file_names[idx]
file_path = f'{self.image_path}/{file_name}'
image = cv2.imread(file_path)
 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
 imglist=[tta(image=image)['image'] for tta in self.ttas]
image=torch.stack(imglist)
 label = torch.tensor(self.labels[idx] ).long()
return image, label
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
 print(device )<choose_model_class>
def _get_augmentations(aug_list, cfg):
process = []
for aug in aug_list:
if aug == 'Resize':
process.append(Resize(cfg['size'], cfg['size']))
elif aug == 'RandomResizedCrop':
process.append(RandomResizedCrop(cfg['size'], cfg['size']))
elif aug == 'CenterCrop':
process.append(CenterCrop(CFG['size'], CFG['size']))
elif aug == 'Transpose':
process.append(Transpose(p=0.5))
elif aug == 'HorizontalFlip':
process.append(HorizontalFlip(p=0.5))
elif aug == 'VerticalFlip':
process.append(VerticalFlip(p=0.5))
elif aug == 'ShiftScaleRotate':
process.append(ShiftScaleRotate(p=0.5))
elif aug == 'Normalize':
process.append(Normalize(
 mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225], 
))
else:
raise ValueError(f'{aug} is not suitable')
 process.append(ToTensorV2())
 return process
def get_transforms(*, aug_list, cfg):
return Compose(
 _get_augmentations(aug_list, cfg)
 )
model_conv = torchvision.models.resnet50(pretrained=True)
 num_ftrs = model_conv.fc.in_features
model_conv.fc = nn.Sequential(
 nn.Linear(num_ftrs, num_ftrs),
nn.ReLU() ,
nn.Dropout(0.5),
nn.Linear(num_ftrs, num_ftrs),
nn.ReLU() ,
nn.Dropout(0.5),
nn.Linear(num_ftrs, len(classes)))
 print(f'
model_conv = model_conv.to(device )<choose_model_class>
class CustomModel(nn.Module):
def __init__(self, model_name, target_size, pretrained=False):
super().__init__()
self.model = timm.create_model(model_name, pretrained=pretrained)
 if hasattr(self.model, 'classifier'):
n_features = self.model.classifier.in_features
self.model.classifier = nn.Linear(n_features, target_size)
 elif hasattr(self.model, 'fc'):
n_features = self.model.fc.in_features
self.model.fc = nn.Linear(n_features, target_size)
 elif hasattr(self.model, 'head'):
n_features = self.model.head.in_features
self.model.head = nn.Linear(n_features, target_size)
 def forward(self, x):
x = self.model(x)
 return x
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_conv.parameters() , lr=0.0001, weight_decay=1e-6, momentum=0.9)
 softmax = nn.Softmax(dim=1)
 best_valid_score = 999
patience = 0<train_model>
def inference_tta(model, states, tta_loader, device):
model.to(device)
 tk0 = tqdm(enumerate(tta_loader), total=len(tta_loader))
probs = []
for i,(images, _)in tk0:
images = images.to(device)
 batch_size, n_crops, c, h, w = images.size()
images = images.view(-1, c, h, w)
 avg_preds = []
for state in states:
model.load_state_dict(state['model'])
 model.eval()
with torch.no_grad() :
y_preds = model(images ).softmax(1)
 y_preds = y_preds.view(batch_size, n_crops,-1)
 avg_preds.append(y_preds.to('cpu' ).numpy())
 avg_preds = np.mean(avg_preds, axis=0)
 probs.append(avg_preds)
 del images, _, y_preds, avg_preds
torch.cuda.empty_cache()
probs = np.concatenate(probs)
 return probs
def train(model_conv, train_loader, optimizer, criterion, trn_cnt):
running_loss = 0.
 running_acc = 0.
 pbar = tqdm(total=trn_cnt)
 cnt = 0
for i, data in enumerate(train_loader, 0):
inputs, labels = data
inputs = inputs.to(device)
 labels = labels.to(device)
 optimizer.zero_grad()
model_conv.train()
outputs = model_conv(inputs)
 probs = softmax(outputs)
 _, preds = probs.max(axis=1)
 running_acc += sum(labels == preds)/(1.* BATCH_SIZE)
 loss = criterion(outputs, labels)
 loss.backward()
optimizer.step()
running_loss += loss.item()
cnt += 1
pbar.update(BATCH_SIZE)
 pbar.close()
return running_loss / cnt, running_acc / cnt<init_hyperparams>
def main_tta(config, model_dir):
INFO = config['info']
TAG = config['tag']
CFG = config['cfg']
CFG['train'] = False
CFG['inference'] = True
inference_batch_size = 8
seed_torch(seed=CFG['seed'])
 model = CustomModel(TAG['model_name'], CFG['target_size'], pretrained=False)
 states = [torch.load(path)for path in glob.glob(f'{model_dir}/*.pth')]
ttas = get_ttas(CFG)
 tta_dataset = TTADataset(test, TEST_PATH, ttas=ttas)
 tta_loader = DataLoader(tta_dataset, batch_size=inference_batch_size, shuffle=False,
num_workers=2, pin_memory=True)
 predictions = inference_tta(model, states, tta_loader, device)
 return predictions
def evaluate(model_conv, valid_loader, criterion):
with torch.no_grad() :
model_conv.eval()
valid_loss = 0.0
valid_acc = 0.0
cnt = 0
pbar = tqdm(total=val_cnt)
 for data in valid_loader:
inputs, labels = data
inputs = inputs.to(device)
 labels = labels.to(device)
 outputs = model_conv(inputs)
 probs = softmax(outputs)
 _, preds = probs.max(axis=1)
 valid_acc += sum(labels == preds)/(1.* BATCH_SIZE)
 labels.require_grad = False
loss = criterion(outputs, labels)
 valid_loss += loss
cnt += 1
pbar.update(BATCH_SIZE)
 pbar.close()
return valid_loss / cnt, valid_acc / cnt<train_model>
data_num = len(test)
 model_num = len(model_dirs)
 target_num = CFG['target_size']
channel_num = 4
stage1_predictions = np.zeros(( model_num, data_num, channel_num, target_num), dtype=np.float)
 for config, model_dir in zip(tta_configs, tta_model_dirs):
stage1_predictions[model_dirs.index(model_dir)] = main_tta(config, model_dir)
 stage1_predictions = stage1_predictions.transpose(1, 2, 0, 3 )
for epoch in range(EPOCH):
print(f'
trn_loss, trn_acc = train(model_conv, train_loader, optimizer, criterion, trn_cnt)
 print(f'
valid_loss, valid_acc = evaluate(model_conv, valid_loader, criterion)
 print(f'
if valid_loss < best_valid_score:
best_valid_score = valid_loss
print(f'
torch.save(model_conv, MODEL_NAME)
 patience = 0
patience += 1
if patience == PATIENCE:
break
print('Finished Training' )<define_variables>
class StackingDataset(Dataset):
def __init__(self, X: np.ndarray, y: Optional[np.ndarray] = None):
self.X = X
self.y = y
def __len__(self):
return self.X.shape[0]
def __getitem__(self, idx):
if self.y is None:
return torch.tensor(self.X[idx], dtype=torch.float)
 else:
return(
 torch.tensor(self.X[idx], dtype=torch.float),
torch.tensor(self.y[idx], dtype=torch.long),
)
TEST_SIZE = 79726
BATCH_SIZE = 128
test_ids = [os.path.basename(fl)for fl in glob(f'{DATA_PATH}/imgs/test/img_*.jpg')]
test_ids.sort()
transform = transforms.Compose([
transforms.Resize(( 224, 224)) ,
transforms.ToTensor() ,
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
 test_dataset = torchvision.datasets.ImageFolder(f'{DATA_PATH}/imgs',
transform=transform)
 test_loader = torch.utils.data.DataLoader(test_dataset,
batch_size=BATCH_SIZE,
num_workers=2)
 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
 print(device)
 model_conv = torch.load(MODEL_NAME)
 print(f'
model_conv = model_conv.to(device)
 softmax = nn.Softmax(dim=1)
 pbar = tqdm(total=TEST_SIZE)
 end_flag = False
with open('submission.csv', 'w')as out:
out.write('img,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9
')
 for i, data in enumerate(test_loader, 0):
inputs, labels = data
inputs = inputs.to(device)
 labels = labels.to(device)
 with torch.no_grad() :
model_conv.eval()
outputs = model_conv(inputs)
 probs = softmax(outputs)
 for j, prob in enumerate(probs):
if BATCH_SIZE * i + j >= TEST_SIZE:
end_flag = True
break
test_id = test_ids[i * BATCH_SIZE + j]
prob = ','.join([str(round(val, 3)) for val in prob.cpu().detach().numpy() ])
 out.write(f'{test_id},{prob}
')
 pbar.update(BATCH_SIZE)
 if end_flag:
break
pbar.close()
print('Finished Eval' )<import_modules>
class CNNStacking(nn.Module):
def __init__(self, n_labels):
super(CNNStacking, self ).__init__()
self.sq = nn.Sequential(
 nn.Conv2d(in_channels=4, out_channels=8, kernel_size=(3, 1), bias=False),
nn.ReLU() ,
nn.Conv2d(in_channels=8, out_channels=16, kernel_size=(3, 1), bias=False),
nn.ReLU() ,
nn.Flatten() ,
nn.Linear(in_features=16* n_labels, out_features=4 * n_labels),
nn.ReLU() ,
nn.Linear(in_features=4 * n_labels, out_features=n_labels), 
)
 def forward(self, x):
return self.sq(x )
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
import keras
import numpy
from keras.preprocessing.image import ImageDataGenerator<import_modules>
def inference(model, states, test_loader, device):
model.to(device)
 tk0 = tqdm(enumerate(test_loader), total=len(test_loader))
probs = []
for i,(features)in tk0:
features = features.to(device)
 avg_preds = []
for state in states:
model.load_state_dict(state['model'])
 model.eval()
with torch.no_grad() :
y_preds = model(features)
 avg_preds.append(y_preds.softmax(1 ).to('cpu' ).numpy())
 avg_preds = np.mean(avg_preds, axis=0)
 probs.append(avg_preds)
 probs = np.concatenate(probs)
 return probs
import keras
import numpy
from keras.preprocessing.image import ImageDataGenerator<choose_model_class>
model = CNNStacking(CFG['target_size'])
 states = [torch.load(STAGE2_DIR+f'/fold{fold}_best.pth')for fold in CFG['trn_fold']]
test_dataset = StackingDataset(stage1_predictions)
 test_loader = DataLoader(test_dataset, batch_size=CFG['batch_size'], shuffle=False,
num_workers=CFG['num_workers'], pin_memory=True)
 predictions = inference(model, states, test_loader, device)
 test['label'] = predictions.argmax(1)
 test[['image_id', 'label']].to_csv(OUTPUT_DIR+'submission.csv', index=False )