Kaggle competition: Quick, Draw! Doodle Recognition Challenge
<SOS> metric: MAP@{K} Kaggle data source: quick,-draw!-doodle-recognition-challenge<feature_engineering>
warnings.filterwarnings('ignore')
 %matplotlib inline
%config InlineBackend.figure_format = 'retina'
train_df["images"] = [np.array(load_img(".. /input/train/images/{}.png".format(idx), grayscale=True)) / 255 for idx in tqdm_notebook(train_df.index)]<feature_engineering>
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader, ConcatDataset
import torchvision
from torchvision import transforms, utils
train_df["masks"] = [np.array(load_img(".. /input/train/masks/{}.png".format(idx), grayscale=True)) / 255 for idx in tqdm_notebook(train_df.index)]<categorify>
en_dict = {}
path = '.. /input/train_simplified/'
filenames = glob.glob(os.path.join(path, '*.csv'))
filenames = sorted(filenames)
 def encode_files() :

 counter = 0
for fn in filenames:
en_dict[fn[:-4].split('/')[-1].replace(' ', '_')] = counter
counter += 1
encode_files()
dec_dict = {v: k for k, v in en_dict.items() }
def decode_labels(label):
return dec_dict[label]
def get_label(nfile):

 return en_dict[nfile.replace(' ', '_')[:-4]]
train_df["coverage"] = train_df.masks.map(np.sum)/ pow(img_size_ori, 2)
 def cov_to_class(val):
for i in range(0, 11):
if val * 10 <= i :
return i
train_df["coverage_class"] = train_df.coverage.map(cov_to_class)
<split>
class DoodlesDataset(Dataset):

 def __init__(self, csv_file, root_dir, mode='train', nrows=1000, skiprows=None, size=256, transform=None):

 self.root_dir = root_dir
file = os.path.join(self.root_dir, csv_file)
 self.size = size
self.mode = mode
self.doodle = pd.read_csv(file, usecols=['drawing'], nrows=nrows, skiprows=skiprows)
 self.transform = transform
if self.mode == 'train':
self.label = get_label(csv_file)
 @staticmethod
def _draw(raw_strokes, size=256, lw=6, time_color=True):
BASE_SIZE = 256
img = np.zeros(( BASE_SIZE, BASE_SIZE), np.uint8)
 for t, stroke in enumerate(raw_strokes):
for i in range(len(stroke[0])- 1):
color = 255 - min(t, 10)* 13 if time_color else 255
_ = cv2.line(img,(stroke[0][i], stroke[1][i]), 
(stroke[0][i + 1], stroke[1][i + 1]), color, lw)
 if size != BASE_SIZE:
return cv2.resize(img,(size, size))
else:
return img
def __len__(self):
return len(self.doodle)
 def __getitem__(self, idx):
raw_strokes = ast.literal_eval(self.doodle.drawing[idx])
 sample = self._draw(raw_strokes, size=self.size, lw=2, time_color=True)
 if self.transform:
sample = self.transform(sample)
 if self.mode == 'train':
return(sample[None]/255 ).astype('float32'), self.label
else:
return(sample[None]/255 ).astype('float32' )
ids_train, ids_valid, x_train, x_valid, y_train, y_valid, cov_train, cov_test, depth_train, depth_test = train_test_split(
 train_df.index.values,
np.array(train_df.images.map(upsample ).tolist() ).reshape(-1, img_size_target, img_size_target, 1),
np.array(train_df.masks.map(upsample ).tolist() ).reshape(-1, img_size_target, img_size_target, 1),
train_df.coverage.values,
train_df.z.values,
test_size=0.2, stratify=train_df.coverage_class, random_state= 1234 )<define_search_model>
SIZE = 224
select_nrows = 10000
doodles = ConcatDataset([DoodlesDataset(fn.split('/')[-1], path,
nrows=select_nrows, size=SIZE)for fn in filenames] )
def convolution_block(x, filters, size, strides=(1,1), padding='same', activation=True):
x = Conv2D(filters, size, strides=strides, padding=padding )(x)
 x = BatchNormalization()(x)
 if activation == True:
x = Activation('relu' )(x)
 return x
def residual_block(blockInput, num_filters=16):
x = Activation('relu' )(blockInput)
 x = BatchNormalization()(x)
 x = convolution_block(x, num_filters,(3,3))
x = convolution_block(x, num_filters,(3,3), activation=False)
 x = Add()([x, blockInput])
 return x 
<choose_model_class>
print('Train set:', len(doodles))
loader = DataLoader(doodles, batch_size=128, shuffle=True, num_workers=0)
def build_model(input_layer, start_neurons, DropoutRatio = 0.5):
conv1 = Conv2D(start_neurons * 1,(3, 3), activation=None, padding="same" )(input_layer)
 conv1 = residual_block(conv1,start_neurons * 1)
 conv1 = residual_block(conv1,start_neurons * 1)
 conv1 = Activation('relu' )(conv1)
 pool1 = MaxPooling2D(( 2, 2))(conv1)
 pool1 = Dropout(DropoutRatio/2 )(pool1)
 conv2 = Conv2D(start_neurons * 2,(3, 3), activation=None, padding="same" )(pool1)
 conv2 = residual_block(conv2,start_neurons * 2)
 conv2 = residual_block(conv2,start_neurons * 2)
 conv2 = Activation('relu' )(conv2)
 pool2 = MaxPooling2D(( 2, 2))(conv2)
 pool2 = Dropout(DropoutRatio )(pool2)
 conv3 = Conv2D(start_neurons * 4,(3, 3), activation=None, padding="same" )(pool2)
 conv3 = residual_block(conv3,start_neurons * 4)
 conv3 = residual_block(conv3,start_neurons * 4)
 conv3 = Activation('relu' )(conv3)
 pool3 = MaxPooling2D(( 2, 2))(conv3)
 pool3 = Dropout(DropoutRatio )(pool3)
 conv4 = Conv2D(start_neurons * 8,(3, 3), activation=None, padding="same" )(pool3)
 conv4 = residual_block(conv4,start_neurons * 8)
 conv4 = residual_block(conv4,start_neurons * 8)
 conv4 = Activation('relu' )(conv4)
 pool4 = MaxPooling2D(( 2, 2))(conv4)
 pool4 = Dropout(DropoutRatio )(pool4)
 convm = Conv2D(start_neurons * 16,(3, 3), activation=None, padding="same" )(pool4)
 convm = residual_block(convm,start_neurons * 16)
 convm = residual_block(convm,start_neurons * 16)
 convm = Activation('relu' )(convm)
 deconv4 = Conv2DTranspose(start_neurons * 8,(3, 3), strides=(2, 2), padding="same" )(convm)
 uconv4 = concatenate([deconv4, conv4])
 uconv4 = Dropout(DropoutRatio )(uconv4)
 uconv4 = Conv2D(start_neurons * 8,(3, 3), activation=None, padding="same" )(uconv4)
 uconv4 = residual_block(uconv4,start_neurons * 8)
 uconv4 = residual_block(uconv4,start_neurons * 8)
 uconv4 = Activation('relu' )(uconv4)
 deconv3 = Conv2DTranspose(start_neurons * 4,(3, 3), strides=(2, 2), padding="valid" )(uconv4)
 uconv3 = concatenate([deconv3, conv3])
 uconv3 = Dropout(DropoutRatio )(uconv3)
 uconv3 = Conv2D(start_neurons * 4,(3, 3), activation=None, padding="same" )(uconv3)
 uconv3 = residual_block(uconv3,start_neurons * 4)
 uconv3 = residual_block(uconv3,start_neurons * 4)
 uconv3 = Activation('relu' )(uconv3)
 deconv2 = Conv2DTranspose(start_neurons * 2,(3, 3), strides=(2, 2), padding="same" )(uconv3)
 uconv2 = concatenate([deconv2, conv2])
 uconv2 = Dropout(DropoutRatio )(uconv2)
 uconv2 = Conv2D(start_neurons * 2,(3, 3), activation=None, padding="same" )(uconv2)
 uconv2 = residual_block(uconv2,start_neurons * 2)
 uconv2 = residual_block(uconv2,start_neurons * 2)
 uconv2 = Activation('relu' )(uconv2)
 deconv1 = Conv2DTranspose(start_neurons * 1,(3, 3), strides=(2, 2), padding="valid" )(uconv2)
 uconv1 = concatenate([deconv1, conv1])
 uconv1 = Dropout(DropoutRatio )(uconv1)
 uconv1 = Conv2D(start_neurons * 1,(3, 3), activation=None, padding="same" )(uconv1)
 uconv1 = residual_block(uconv1,start_neurons * 1)
 uconv1 = residual_block(uconv1,start_neurons * 1)
 uconv1 = Activation('relu' )(uconv1)
 uconv1 = Dropout(DropoutRatio/2 )(uconv1)
 output_layer = Conv2D(1,(1,1), padding="same", activation="sigmoid" )(uconv1)
 return output_layer<concatenate>
def validation(lossf, scoref):
model.eval()
loss, score = 0, 0
vlen = len(valid_loader)
 for x, y in valid_loader:
x, y = x.to(device), y.to(device)
 output = model(x)
 loss += lossf(output, y ).item()
score += scoref(output, y)[0].item()
model.train()
return loss/vlen, score/vlen
x_train2 = np.append(x_train, [np.fliplr(x)for x in x_train], axis=0)
 y_train2 = np.append(y_train, [np.fliplr(x)for x in y_train], axis=0)
 print(x_train2.shape)
 print(y_valid.shape )<choose_model_class>
def accuracy(output, target, topk=(3,)) :

 with torch.no_grad() :
maxk = max(topk)
 batch_size = target.size(0)
 _, pred = output.topk(maxk, 1, True, True)
 pred = pred.t()
correct = pred.eq(target.view(1, -1 ).expand_as(pred))
res = []
for k in topk:
correct_k = correct[:k].view(-1 ).float().sum(0, keepdim=True)
 res.append(correct_k.mul_(100.0 / batch_size))
return res
input_layer = Input(( img_size_target, img_size_target, 1))
output_layer = build_model(input_layer, 16,0.5)
 model = Model(input_layer, output_layer)
 model.compile(loss="binary_crossentropy", optimizer="adam", metrics=[my_iou_metric])
 model.summary()<train_model>
def mapk(output, target, k=3):

 with torch.no_grad() :
batch_size = target.size(0)
 _, pred = output.topk(k, 1, True, True)
 pred = pred.t()
correct = pred.eq(target.view(1, -1 ).expand_as(pred))
for i in range(k):
correct[i] = correct[i]*(k-i)
 score = correct[:k].view(-1 ).float().sum(0, keepdim=True)
 score.mul_(1.0 /(k * batch_size))
return score
early_stopping = EarlyStopping(monitor='val_my_iou_metric', mode = 'max',patience=20, verbose=1)
 model_checkpoint = ModelCheckpoint("./unet_best1.model",monitor='val_my_iou_metric',
mode = 'max', save_best_only=True, verbose=1)
 reduce_lr = ReduceLROnPlateau(monitor='val_my_iou_metric', mode = 'max',factor=0.2, patience=5, min_lr=0.00001, verbose=1)
 epochs = 200
batch_size = 32
history = model.fit(x_train2, y_train2,
validation_data=[x_valid, y_valid],
epochs=epochs,
batch_size=batch_size,
callbacks=[early_stopping, model_checkpoint, reduce_lr],
verbose=2 )<load_pretrained>
model = torchvision.models.resnet18(pretrained=True )
model = load_model("./unet_best1.model",custom_objects={'my_iou_metric': my_iou_metric})
<predict_on_test>
def squeeze_weights(m):
m.weight.data = m.weight.data.sum(dim=1)[:,None]
m.in_channels = 1
model.conv1.apply(squeeze_weights);
num_classes = 340
model.fc = nn.Linear(in_features=512, out_features=num_classes, bias=True )
def predict_result(model,x_test,img_size_target):
x_test_reflect = np.array([np.fliplr(x)for x in x_test])
 preds_test1 = model.predict(x_test ).reshape(-1, img_size_target, img_size_target)
 preds_test2_refect = model.predict(x_test_reflect ).reshape(-1, img_size_target, img_size_target)
 preds_test2 = np.array([ np.fliplr(x)for x in preds_test2_refect])
 preds_avg =(preds_test1 +preds_test2)/2
return preds_avg<predict_on_test>
%%time
model(torch.randn(12,1,224,224)).size()
preds_valid = predict_result(model,x_valid,img_size_target)
 preds_valid2 = np.array([downsample(x)for x in preds_valid])
 y_valid2 = np.array([downsample(x)for x in y_valid] )<compute_train_metric>
device = 'cuda'
model.to(device);
thresholds = np.linspace(0.3, 0.7, 31)
 ious = np.array([iou_metric_batch(y_valid2, np.int32(preds_valid2 > threshold)) for threshold in tqdm_notebook(thresholds)])
<categorify>
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters() , lr=0.002, amsgrad=True )
def rle_encode(im):

 pixels = im.flatten(order = 'F')
 pixels = np.concatenate([[0], pixels, [0]])
 runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
runs[1::2] -= runs[::2]
return ' '.join(str(x)for x in runs )<predict_on_test>
scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[5000,12000,18000], gamma=0.5 )
preds_test = predict_result(model,x_test,img_size_target )<compute_test_metric>
%%time
epochs = 1
lsize = len(loader)
 itr = 1
p_itr = 1000
model.train()
tloss, score = 0, 0
for epoch in range(epochs):
for x, y in loader:
x, y = x.to(device), y.to(device)
 optimizer.zero_grad()
output = model(x)
 loss = criterion(output, y)
 loss.backward()
optimizer.step()
tloss += loss.item()
score += mapk(output, y)[0].item()
scheduler.step()
if itr%p_itr==0:
print('Iteration {} -> Train Loss: {:.4f}, MAP@3: {:.3f}'.format(itr, tloss/p_itr, score/p_itr))
tloss, score = 0, 0
itr +=1
t1 = time.time()
pred_dict = {idx: rle_encode(np.round(downsample(preds_test[i])> threshold_best)) for i, idx in enumerate(tqdm_notebook(test_df.index.values)) }
t2 = time.time()
print(f"Usedtime = {t2-t1} s" )<save_to_csv>
filename_pth='checkpoint_resnet18.pth'
torch.save(model.state_dict() , filename_pth )
sub = pd.DataFrame.from_dict(pred_dict,orient='index')
 sub.index.names = ['id']
sub.columns = ['rle_mask']
sub.to_csv('submission13.csv' )<set_options>
testset = DoodlesDataset('test_simplified.csv', '.. /input', mode='test', nrows=None, size=SIZE)
 testloader = DataLoader(testset, batch_size=128, shuffle=False, num_workers=0 )
plt.style.use('seaborn-white')
 sns.set_style("white")
<train_model>
model.eval()
labels = np.empty(( 0,3))
for x in tqdm.tqdm(testloader):
x = x.to(device)
 output = model(x)
 _, pred = output.topk(3, 1, True, True)
 labels = np.concatenate([labels, pred], axis = 0 )
img_size_ori = 101
img_size_target = 128
def upsample(img):
if img_size_ori == img_size_target:
return img
return resize(img,(img_size_target, img_size_target), mode='constant', preserve_range=True)
 def downsample(img):
if img_size_ori == img_size_target:
return img
return resize(img,(img_size_ori, img_size_ori), mode='constant', preserve_range=True)
<import_modules>
%%time
submission = pd.read_csv('.. /input/test_simplified.csv', index_col='key_id')
 submission.drop(['countrycode', 'drawing'], axis=1, inplace=True)
 submission['word'] = ''
for i, label in enumerate(labels):
submission.word.iloc[i] = " ".join([decode_labels(l)for l in label] )
<load_from_csv><EOS> 
submission.to_csv('preds_resnet18.csv' )