Kaggle competition: Quick, Draw! Doodle Recognition Challenge
<SOS> metric: MAP@{K} Kaggle data source: quick,-draw!-doodle-recognition-challenge<feature_engineering>
%matplotlib inline
train['log_budget'] = np.log1p(train['budget'])
 train['log_revenue'] = np.log1p(train['revenue'])
 test['log_budget'] = np.log1p(test['budget'] )<feature_engineering>
train_dir = '.. /input/train_simplified'
test_dir = '.. /input'
test_file = 'test_simplified.csv'
train_nrows = 2000
val_nrows = 100
train_files = os.listdir(train_dir)
 train_files = sorted(train_files)
 w2i_dict = {fn[:-4].replace(' ','_'): i for i, fn in enumerate(train_files)}
i2w_dict = {v: k for k, v in w2i_dict.items() }
for table in [train, test]:
table['has_homepage'] = 0
table.loc[table['homepage'].isnull() == True, 'has_homepage'] = 0
table.loc[table['homepage'].isnull() == False, 'has_homepage'] = 1<feature_engineering>
class DoodleDataset(Dataset):
def __init__(self, file, dir, mode='train', nrows = None, skiprows=None, transform = None):
self.file = file
self.dir = dir
self.mode = mode
self.nrows = nrows
self.transform = transform
self.pd_frame = pd.read_csv(os.path.join(self.dir, self.file), usecols=['drawing'], nrows=nrows, skiprows=skiprows)
 if self.mode == 'train':
self.label = w2i_dict[file[:-4].replace(' ','_')]
@staticmethod
def _point2line(strokes):
img = np.zeros(( 256,256), dtype = np.uint8)
 for stroke in strokes:
x_coords = stroke[0]
y_coords = stroke[1]
for i in range(len(stroke[0])-1):
cv2.line(img,(x_coords[i], y_coords[i]),(x_coords[i+1], y_coords[i+1]), color = 255, thickness = 2)
 return img
def __len__(self):
return len(self.pd_frame)
 def __getitem__(self, idx):
strokes = eval(self.pd_frame.drawing[idx])
 sample = self._point2line(strokes)
 if self.transform:
sample = self.transform(sample)
 if self.mode=='train':
sample = sample.numpy()
return sample.astype('float32'), self.label
else:
sample = sample.numpy()
return sample.astype('float32')
 data_transform = transforms.Compose([
transforms.ToPILImage() ,
transforms.RandomHorizontalFlip() ,
transforms.Resize(( 128,128)) ,
transforms.ToTensor()
])
 val_data_transform = transforms.Compose([
transforms.ToPILImage() ,
transforms.Resize(( 128,128)) ,
transforms.ToTensor()
])
 doodles = ConcatDataset([DoodleDataset(fn, train_dir, nrows=train_nrows, transform = data_transform)for fn in train_files])
 doodles_val = ConcatDataset([DoodleDataset(fn, train_dir, nrows=val_nrows, transform = val_data_transform, skiprows=range(1, train_nrows+1)) for fn in train_files] )
def fix_date(x):
year = x.split('/')[2]
if int(year)<= 19:
return x[:-2]+"20"+year
else:
return x[:-2]+"19"+year
test.loc[test['release_date'].isnull() , 'release_date'] = '5/1/00'
for table in [train, test]:
table['release_date'] = table['release_date'].apply(lambda x:fix_date(x))<data_type_conversions>
dataloader = DataLoader(doodles, batch_size = 16, shuffle = True, num_workers = 4)
 valloader = DataLoader(doodles_val, batch_size = 16, shuffle = True, num_workers = 4 )
def trans(table):
df = pd.DataFrame()
t = pd.to_datetime(table['release_date'])
 date_parts = ["year", "weekday", "month", 'weekofyear', 'day', 'quarter']
for part in date_parts:
part_col = 'release_date' + "_" + part
df[part_col] = getattr(t.dt, part ).astype(int)
 table = pd.concat([table, df], axis=1)
 return table
train = trans(train)
 test = trans(test )<drop_column>
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
train = train.drop(['homepage', 'imdb_id', 'poster_path', 'release_date', 'status','log_revenue'], axis=1)
 test = test.drop(['homepage', 'imdb_id', 'poster_path', 'release_date','status'], axis=1 )<rename_columns>
class RAdam(Optimizer):
def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0):
defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay)
 super(RAdam, self ).__init__(params, defaults)
 self.step_buffer = [None, None, None]
self.N_sma_max = 2 /(1-betas[1])-1
def __setstate__(self, state):
super(RAdam, self ).__setstate__(state)
 def step(self, closure=None):
loss = None if closure is None else closure()
for group in self.param_groups:
for p in group['params']:
if p.grad is None:
continue
p_data_fp32 = p.data.float()
state = self.state[p]
if len(state)== 0:
state['step'] = 1
state['exp_avg'] = torch.zeros_like(p_data_fp32)
 state['exp_avg_sq'] = torch.zeros_like(p_data_fp32)
 else:
state['step'] += 1
state['exp_avg'] = state['exp_avg'].type_as(p_data_fp32)
 state['exp_avg_sq'] = state['exp_avg_sq'].type_as(p_data_fp32)
 exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq']
beta1, beta2 = group['betas']
beta1_t, beta2_t = beta1 ** state['step'], beta2 ** state['step']
bias_correction1, bias_correction2 = 1 - beta1_t, 1 - beta2_t
grad = p.grad.data.float()
if grad.is_sparse:
raise RuntimeError('RAdam does not support sparse gradients')
 exp_avg.mul_(beta1 ).add_(1 - beta1, grad)
 exp_avg_sq.mul_(beta2 ).addcmul_(1 - beta2, grad, grad)
 if state['step'] == self.step_buffer[0]:
N_sma, step_size = self.step_buffer[1], self.step_buffer[2]
else:
N_sma = self.N_sma_max - 2 * state['step'] * beta2_t /(1 - beta2_t)
 if N_sma >= 5:
rectification = math.sqrt(((N_sma-4)*(N_sma-2)*self.N_sma_max)/(( self.N_sma_max-4)*(self.N_sma_max-2)*N_sma))
step_size = math.sqrt(bias_correction2)* rectification / bias_correction1
else:
step_size = 1.0 / bias_correction1
self.step_buffer[0] = state['step']
self.step_buffer[1] = N_sma
self.step_buffer[2] = step_size
if group['weight_decay'] != 0:
p_data_fp32.add_(-group['weight_decay'] * group['lr'], p_data_fp32)
 if N_sma >= 5:
denom = exp_avg_sq.sqrt().add_(group['eps'])
 p_data_fp32.addcdiv_(-step_size * group['lr'], exp_avg, denom)
 else:
p_data_fp32.add_(-step_size * group['lr'], exp_avg)
 p.data.copy_(p_data_fp32)
 return loss
train.rename(columns={'belongs_to_collection':"collection_name"}, inplace=True)
 test.rename(columns={'belongs_to_collection':"collection_name"}, inplace=True )<feature_engineering>
device = 'cuda'
def squeeze_weights(m):
m.weight.data = m.weight.data.sum(dim=1)[:,None]
m.in_channels = 1
model = torchvision.models.densenet121(pretrained=True)

num_ftrs = model.classifier.in_features
model.classifier = nn.Linear(num_ftrs, 340)
 model.features.conv0.apply(squeeze_weights)
 model = model.to(device)
 criterion = nn.CrossEntropyLoss()
optimizer = RAdam(model.parameters() , lr=0.005)
 scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30000,60000,90000], gamma=0.3 )
train['log_budget'] = np.log1p(train['budget'])
 test['log_budget'] = np.log1p(test['budget'] )<feature_engineering>
epochs = 3
itr = 1
p_itr = 5000
total_loss, score = 0,0
val_score = 0.0
best_model_wts = copy.deepcopy(model.state_dict())
 best_score = 0.0
loss_list = []
score_list = []
for epoch in range(epochs):
model.train()
for samples, labels in dataloader:
samples, labels = samples.to(device), labels.to(device)
 optimizer.zero_grad()
output = model(samples)
 loss = criterion(output, labels)
 loss.backward()
optimizer.step()
total_loss += loss.item()
score += mapk(output, labels)[0].item()
scheduler.step()
if itr%p_itr==0:
print('[Epoch {}/{}] Iteration {} -> Train Loss: {:.4f}, MAP@3: {:.3f}'.format(epoch+1, epochs, itr, total_loss/p_itr, score/p_itr))
loss_list.append(total_loss/p_itr)
 score_list.append(score/p_itr)
 total_loss, score = 0,0
itr += 1
model.eval()
for samples, labels in valloader:
with torch.no_grad() :
samples = samples.to(device)
 labels = labels.to(device)
 output = model(samples)
 val_score += mapk(output, labels)[0].item()
print('[Epoch {}/{}] Validation Score: {:.4f}'.format(epoch+1, epochs, val_score/len(valloader)))
 if val_score > best_score:
best_score = val_score
best_model_wts = copy.deepcopy(model.state_dict())
 val_score = 0
model.load_state_dict(best_model_wts )
list_of_genres = list(train['genres'].apply(lambda x: [i['name'] for i in x] if x != {} else [] ).values)
 train['num_genres'] = train['genres'].apply(lambda x: len(x)if x != {} else 0)
 train['all_genres'] = train['genres'].apply(lambda x: ' '.join(sorted([i['name'] for i in x])) if x != {} else '')
 top_genres = [m[0] for m in Counter([i for j in list_of_genres for i in j] ).most_common(15)]
for g in top_genres:
train['genre_' + g] = train['all_genres'].apply(lambda x: 1 if g in x else 0)
 test['num_genres'] = test['genres'].apply(lambda x: len(x)if x != {} else 0)
 test['all_genres'] = test['genres'].apply(lambda x: ' '.join(sorted([i['name'] for i in x])) if x != {} else '')
 for g in top_genres:
test['genre_' + g] = test['all_genres'].apply(lambda x: 1 if g in x else 0)
 train = train.drop(['genres'], axis=1)
 test = test.drop(['genres'], axis=1 )<feature_engineering>
filename_pth = 'ckpt_densenet121.pth'
torch.save(model.state_dict() , filename_pth)
 test_transform = transforms.Compose([
transforms.ToPILImage() ,
transforms.Resize(( 128,128)) ,
transforms.ToTensor()
])
 testset = DoodleDataset(test_file, test_dir, mode='test', transform = test_transform)
 testloader = DataLoader(testset, batch_size=16, shuffle=False, num_workers=4 )
list_of_companies = list(train['production_companies'].apply(lambda x: [i['name'] for i in x] if x != {} else [] ).values)
 train['num_companies'] = train['production_companies'].apply(lambda x: len(x)if x != {} else 0)
 train['all_production_companies'] = train['production_companies'].apply(lambda x: ' '.join(sorted([i['name'] for i in x])) if x != {} else '')
 top_companies = [m[0] for m in Counter([i for j in list_of_companies for i in j] ).most_common(30)]
for g in top_companies:
train['production_company_' + g] = train['all_production_companies'].apply(lambda x: 1 if g in x else 0)
 test['num_companies'] = test['production_companies'].apply(lambda x: len(x)if x != {} else 0)
 test['all_production_companies'] = test['production_companies'].apply(lambda x: ' '.join(sorted([i['name'] for i in x])) if x != {} else '')
 for g in top_companies:
test['production_company_' + g] = test['all_production_companies'].apply(lambda x: 1 if g in x else 0)
 train = train.drop(['production_companies', 'all_production_companies'], axis=1)
 test = test.drop(['production_companies', 'all_production_companies'], axis=1 )<feature_engineering>
model.eval()
labels = np.empty(( 0,3))
for x in tqdm.tqdm_notebook(testloader):
with torch.no_grad() :
x = x.to(device)
 output = model(x)
 _, pred = output.topk(3,1,True,True)
 labels = np.concatenate([labels, pred.cpu() ], axis=0)
 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([i2w_dict[l] for l in label])
 submission.to_csv('preds_densenet121.csv' )
<feature_engineering><EOS> 
FileLinks('.')