Kaggle competition: iWildCam 2020 - FGVC7
<SOS> metric: CategorizationAccuracy Kaggle data source: iwildcam-2020-fgvc7<drop_column>
ImageFile.LOAD_TRUNCATED_IMAGES = True
%matplotlib inline
feature_col, target_cols = 'Image', list(df_train.drop('Image', axis=1 ).columns )<data_type_conversions>
def kaggle_commit_logger(str_to_log, need_print = True):
if need_print:
print(str_to_log)
 os.system('echo ' + str_to_log )
IMG_WIDTH = 96
IMG_HEIGHT = 96
IMG_CHANNELS = 1
images = np.array(df_train[feature_col].str.split().tolist() , dtype='float' ).reshape(-1, IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS)
 labels = df_train[target_cols].to_numpy()<define_variables>
with open(r'/kaggle/input/iwildcam-2020-fgvc7/iwildcam2020_train_annotations.json')as json_file:
train_data = json.load(json_file )
normalized_images = images / 255 .<split>
df_train = pd.DataFrame({'id': [item['id'] for item in train_data['annotations']],
'category_id': [item['category_id'] for item in train_data['annotations']],
'image_id': [item['image_id'] for item in train_data['annotations']],
'file_name': [item['file_name'] for item in train_data['images']]})
 df_train.head()
train_images, valid_images, train_labels, valid_labels = train_test_split(normalized_images, labels, test_size=0.1, random_state=7 )<define_search_model>
df_image = pd.DataFrame.from_records(train_data['images'])
 indices = []
for _id in df_image[df_image['location'] == 537]['id'].values:
indices.append(df_train[ df_train['image_id'] == _id ].index)
 for the_index in indices:
df_train = df_train.drop(df_train.index[the_index] )
Input,
Conv2D,
MaxPool2D,
Dense,
BatchNormalization,
ReLU,
Dropout,
Flatten,
Dropout,
Concatenate,
GlobalAvgPool2D 
)
 def inception_module(inputs, f1, f2):
x1 = Conv2D(f1, 3, padding='same' )(inputs)
 x1 = BatchNormalization()(x1)
 x1 = ReLU()(x1)
 x2 = Conv2D(f2, 5, padding='same' )(inputs)
 x2 = BatchNormalization()(x2)
 x2 = ReLU()(x2)
 return Concatenate()([x1, x2] )<define_search_model>
%%time
indices = []
for i in df_train['file_name']:
try:
Image.open('/kaggle/input/iwildcam-2020-fgvc7/train/' + i)
 except:
print(i)
 df_train.drop(df_train.loc[df_train['file_name']==i].index, inplace=True )
def build_model() :
inputs = Input(( 96, 96, 1))
x = inception_module(inputs, 64, 32)
 x = MaxPool2D()(x)
 x = inception_module(x, 64, 32)
 x = MaxPool2D()(x)
 x = inception_module(x, 128, 32)
 x = MaxPool2D()(x)
 x = inception_module(x, 128, 32)
 x = MaxPool2D()(x)
 x = inception_module(x, 256, 64)
 x = MaxPool2D()(x)
 x = Flatten()(x)
 x = Dense(1024, kernel_regularizer=L2(l2=0.05))(x)
 x = BatchNormalization()(x)
 x = ReLU()(x)
 x = Dense(512, kernel_regularizer=L2(l2=0.02))(x)
 x = BatchNormalization()(x)
 x = ReLU()(x)
 x = Dense(128, kernel_regularizer=L2(l2=0.01))(x)
 x = BatchNormalization()(x)
 x = ReLU()(x)
 x = Dense(30 )(x)
 model = tf.keras.Model(inputs, outputs=x)
 return model
model = build_model()
model.summary()<choose_model_class>
with open(r'/kaggle/input/iwildcam-2020-fgvc7/iwildcam2020_test_information.json')as f:
test_data = json.load(f )
model.compile(optimizer='adam', loss='mean_squared_error', metrics=['mae'] )<train_model>
df_test = pd.DataFrame.from_records(test_data['images'])
 df_test.head()
ckp_filepath = 'trained_models/model'
model_checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath=ckp_filepath,
monitor='val_mae',
mode='auto',
save_best_only=True,
save_weights_only=True)
 reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(factor=0.9, monitor='val_mae',
mode='auto', cooldown=0, patience=5, verbose=1, min_lr=1e-5 )<train_model>
batch_size = 64
IMG_SIZE = 64
N_EPOCHS = 1
ID_COLNAME = 'file_name'
ANSWER_COLNAME = 'category_id'
TRAIN_IMGS_DIR = r'.. /input/iwildcam-2020-fgvc7/train/'
TEST_IMGS_DIR = r'.. /input/iwildcam-2020-fgvc7/test/'
EPOCHS = 300
BATCH_SIZE = 256
history = model.fit(train_images,
train_labels,
validation_data=(valid_images, valid_labels),
batch_size=BATCH_SIZE, epochs=EPOCHS, callbacks=[model_checkpoint, reduce_lr] )<load_from_csv>
train_df, test_df = train_test_split(df_train[[ID_COLNAME, ANSWER_COLNAME]],
test_size = 0.15,
shuffle = True
)
df_test = pd.read_csv('.. /input/facial-keypoints-detection/test.zip')
 df_test.head(1 )<split>
NUM_CLASSES = len(CLASSES_TO_USE)
 NUM_CLASSES
test_images = np.array(df_test['Image'].str.split().tolist() , dtype='int' ).reshape(-1, 96, 96, 1 )<feature_engineering>
CLASSMAP = dict(
 [(i, j)for i, j
in zip(CLASSES_TO_USE, range(NUM_CLASSES))
] 
)
 CLASSMAP
normalized_test_images = test_images / 255 .<predict_on_test>
REVERSE_CLASSMAP = dict([(v, k)for k, v in CLASSMAP.items() ])
 REVERSE_CLASSMAP
model.load_weights(ckp_filepath)
 keypoints_predictions = model.predict(normalized_test_images, batch_size=BATCH_SIZE )<randomize_order>
model = models.densenet121(pretrained='imagenet' )
idx = np.random.choice(16, 16)
 show_examples(test_images[idx], keypoints_predictions[idx] )<load_from_csv>
new_head = torch.nn.Linear(model.classifier.in_features, NUM_CLASSES)
 model.classifier = new_head
lookup = pd.read_csv('.. /input/facial-keypoints-detection/IdLookupTable.csv')
 lookup.head()<save_to_csv>
model.load_state_dict(torch.load('.. /input/iwild2020-torch/model'))
df_test_predictions = pd.DataFrame(keypoints_predictions, columns=target_cols)
 df_test_predictions.index += 1
lookup['Location'] = lookup.set_index(['ImageId', 'FeatureName'] ).index.map(df_test_predictions.stack() ).values
timestamp = pd.to_datetime('today' ).floor('15min')
 lookup[['RowId', 'Location']].to_csv(f'predictions_{timestamp}.csv', index=False )<set_options>
normalizer = transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
 train_augmentation = transforms.Compose([
transforms.Resize(( IMG_SIZE,IMG_SIZE)) ,
transforms.ToTensor() ,
normalizer,
])
 val_augmentation = transforms.Compose([
transforms.Resize(( IMG_SIZE,IMG_SIZE)) ,
transforms.ToTensor() ,
normalizer,
] )
%matplotlib inline<load_from_csv>
class IMetDataset(Dataset):
def __init__(self,
df,
images_dir,
n_classes = NUM_CLASSES,
id_colname = ID_COLNAME,
answer_colname = ANSWER_COLNAME,
label_dict = CLASSMAP,
transforms = None 
):
self.df = df
self.images_dir = images_dir
self.n_classes = n_classes
self.id_colname = id_colname
self.answer_colname = answer_colname
self.label_dict = label_dict
self.transforms = transforms
def __len__(self):
return self.df.shape[0]
def __getitem__(self, idx):
cur_idx_row = self.df.iloc[idx]
img_id = cur_idx_row[self.id_colname]
img_name = img_id
img_path = os.path.join(self.images_dir, img_name)
 img = Image.open(img_path)
 if self.transforms is not None:
img = self.transforms(img)
 if self.answer_colname is not None:
label = torch.zeros(( self.n_classes,), dtype=torch.float32)
 label[self.label_dict[cur_idx_row[self.answer_colname]]] = 1.0
return img, label
else:
return img, img_id
def load_data(dir_path, filename):
df = pd.read_csv(os.path.join(dir_path, filename))
if filename not in ['IdLookupTable.csv','SampleSubmission.csv']:
df['Image'] = df['Image'].apply(lambda img: np.fromstring(img, sep=' '))
return df<count_missing_values>
train_dataset = IMetDataset(train_df, TRAIN_IMGS_DIR, transforms = train_augmentation)
 test_dataset = IMetDataset(test_df, TRAIN_IMGS_DIR, transforms = val_augmentation )
def summary(df, test=False):
dataname = 'test' if test else 'train'
print("Length of %s data %d..
" %(dataname, len(df)))
 print("Count values for each variable:
")
 print(df.count() , '
')
 print("How many variables has missing values ?
")
 print(df.isnull().any().value_counts())
 print()
print("Pourcentage of missing values for each variable:
")
 summary_list =[100 - df[c].count() /len(df)*100 for c in df.columns]
var_list = [var for var in df.columns]
for i in range(len(summary_list)) :
print("{} : {}".format(var_list[i], np.round(summary_list[i]),2))
print()<groupby>
BS = 24
train_loader = DataLoader(train_dataset, batch_size=BS, shuffle=True, num_workers=2, pin_memory=True)
 test_loader = DataLoader(test_dataset, batch_size=BS, shuffle=False, num_workers=2, pin_memory=True )
def get_mean_cols(df):

 df_mean_cols = df[df.columns[:-1]].mean(axis = 0, skipna = True ).reset_index()
mean_cols = df_mean_cols[0].mean(axis = 0, skipna = True)
 return round(mean_cols )<categorify>
def f1_score(y_true, y_pred, threshold=0.5):
return fbeta_score(y_true, y_pred, 1, threshold)
 def fbeta_score(y_true, y_pred, beta, threshold, eps=1e-9):
beta2 = beta**2
y_pred = torch.ge(y_pred.float() , threshold ).float()
y_true = y_true.float()
true_positive =(y_pred * y_true ).sum(dim=1)
 precision = true_positive.div(y_pred.sum(dim=1 ).add(eps))
recall = true_positive.div(y_true.sum(dim=1 ).add(eps))
return torch.mean(
(precision*recall ).
 div(precision.mul(beta2)+ recall + eps ).
 mul(1 + beta2))
def scale_data(df, test=False, random_state=42):

 img = np.vstack(df['Image'].values)/ 255.
 img = img.astype(np.float32)
 mean_cols = get_mean_cols(df)
 if not test:
keypoints = df[df.columns[:-1]].values
keypoints =(keypoints - mean_cols)/ mean_cols
keypoints = keypoints.astype(np.float32)
 else:
keypoints = None
return img, keypoints, mean_cols<define_variables>
def train_one_epoch(model, train_loader, criterion, optimizer, steps_upd_logging = 250):
model.train() ;
total_loss = 0.0
train_tqdm = tqdm_notebook(train_loader)
 for step,(features, targets)in enumerate(train_tqdm):
try:
features, targets = cuda(features), cuda(targets)
 optimizer.zero_grad()
logits = model(features)
 loss = criterion(logits, targets)
 loss.backward()
optimizer.step()
total_loss += loss.item()
if(step + 1)% steps_upd_logging == 0:
logstr = f'Train loss on step {step + 1} was {round(total_loss /(step + 1), 5)}'
train_tqdm.set_description(logstr)
 kaggle_commit_logger(logstr, need_print=False)
 except:
pass
return total_loss /(step + 1 )
def _random_indices(inputs, ratio, random_state=1234):

 np.random.seed(random_state);
actual_batchsize = inputs.shape[0]
size = int(actual_batchsize * ratio)
 indices = np.random.choice(actual_batchsize, size, replace=False)
 return indices<normalization>
criterion = torch.nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters() , lr=0.0005)
 sheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=0.5, patience=3 )
def rotate(y, inputs, targets, rotate_ratio, angle= None, right_left = 0):

 if angle is None:
angle = np.random.randint(10)
 if right_left != 0:
angle = 360 - angle
for i in range(inputs.shape[0]):
inputs[i, :, :, 0] = sk.rotate(inputs[i, :, :, 0], angle)
 angle = np.radians(angle)
 indices = np.arange(targets.shape[0])
 R = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])
 targets = targets.reshape(len(targets), y.shape[1] // 2, 2)
 targets[indices] = np.dot(targets[indices], R)
 targets = targets.reshape(len(targets), y.shape[1])
 return inputs, targets<concatenate>
%%time
TRAIN_LOGGING_EACH = 500
train_losses = []
valid_losses = []
valid_f1s = []
best_model_f1 = 0.0
best_model = None
best_model_ep = 0
for epoch in range(1, N_EPOCHS + 1):
ep_logstr = f"Starting {epoch} epoch..."
kaggle_commit_logger(ep_logstr)
 tr_loss = train_one_epoch(model, train_loader, criterion, optimizer, TRAIN_LOGGING_EACH)
 train_losses.append(tr_loss)
 tr_loss_logstr = f'Mean train loss: {round(tr_loss,5)}'
kaggle_commit_logger(tr_loss_logstr)
 valid_loss, valid_f1 = validate(model, test_loader, criterion)
 valid_losses.append(valid_loss)
 valid_f1s.append(valid_f1)
 val_loss_logstr = f'Mean valid loss: {round(valid_loss,5)}'
kaggle_commit_logger(val_loss_logstr)
 sheduler.step(valid_loss)
 if valid_f1 >= best_model_f1:
best_model = model
best_model_f1 = valid_f1
best_model_ep = epoch
def flipp(inputs, targets, flip_ratio, flip_indices= None, random_seed=123):

 if flip_indices is None:
flip_indices = [(0, 2),(1, 3),(4, 8),(5, 9),(6, 10),(7, 11), 
(12, 16),(13, 17),(14, 18),(15, 19),(22, 24), 
(23, 25)]
for i in range(inputs.shape[0]):
inputs[i, :, :, :] = inputs[i, :, ::-1, :]
indices = np.arange(inputs.shape[0])
 targets[indices, ::2] = targets[indices, ::2] * -1
for a, b in flip_indices:
targets[indices, a], targets[indices, b] = targets[indices, b], targets[indices, a]
return inputs, targets<concatenate>
torch.save(best_model.state_dict() , 'model' )
def shift_image(X,y,prop=0.1):
X = X.reshape(-1,96,96)
 y = y.reshape(-1,30)
 for i in range(X.shape[0]):
x_ = X[i]
y_ = y[i]
X[i],y[i] = shift_single_image(x_,y_,prop=prop)
 return(X,y )<categorify>
bestmodel_logstr = f'Best f1 is {round(best_model_f1, 5)} on epoch {best_model_ep}'
kaggle_commit_logger(bestmodel_logstr )
def add_noise(inputs, noise_ratio=0.001):
noisy_img = np.zeros(inputs.shape)
 for i in range(inputs.shape[0]):
noise = np.random.randn(96,96,1)
 noisy_img[i] = inputs[i] + noise_ratio*noise
return noisy_img<split>
SAMPLE_SUBMISSION_DF = pd.read_csv(r'.. /input/iwildcam-2020-fgvc7/sample_submission.csv')
 SAMPLE_SUBMISSION_DF.head()
def split_train_validation(X, y, size=0.3, random_state = 69):
X_train, X_validation, y_train, y_validation = train_test_split(X, y, test_size=size, random_state=random_state)
 print("Splitting data into train {} and validation {}".format(X_train.shape, X_validation.shape))
return X_train, X_validation, y_train, y_validation<load_from_csv>
SAMPLE_SUBMISSION_DF.rename(columns={'Id':'file_name','Category':'category_id'}, inplace=True)
 SAMPLE_SUBMISSION_DF['file_name'] = SAMPLE_SUBMISSION_DF['file_name'] + '.jpg'
SAMPLE_SUBMISSION_DF.head()
train_data = load_data(dir_path, 'training.zip')
 test_data = load_data(dir_path, 'test.zip')
 idlookup = load_data(dir_path, 'IdLookupTable.csv')
 sample_submission = load_data(dir_path,'SampleSubmission.csv' )<compute_test_metric>
subm_dataset = IMetDataset(SAMPLE_SUBMISSION_DF,
TEST_IMGS_DIR,
transforms = val_augmentation,
answer_colname=None
)
summary(test_data, test=True )<create_dataframe>
SUMB_BS = 48
subm_dataloader = DataLoader(subm_dataset,
batch_size=SUMB_BS,
shuffle=False,
pin_memory=True )
train_data_copy = train_data.copy()
test_data_copy = test_data.copy()<count_missing_values>
def get_subm_answers(model, subm_dataloader, need_tqdm = False):
model.eval() ;
preds_cat = []
ids = []
with torch.no_grad() :
if need_tqdm:
subm_iterator = tqdm_notebook(subm_dataloader)
 else:
subm_iterator = subm_dataloader
for step,(features, subm_ids)in enumerate(subm_iterator):
features = cuda(features)
 logits = model(features)
 preds_cat.append(torch.sigmoid(logits))
ids += subm_ids
all_preds = torch.cat(preds_cat)
 all_preds = torch.argmax(all_preds, dim=1 ).int().cpu().numpy()
return all_preds, ids
print("Missing values for the train set where simply NaNs were dropped:
")
 print(train_dropna.isnull().any().value_counts())
 print()
print("Missing values for the train set where NaNs filled using the forward technique:
")
 print(train_fill_nan.isnull().any().value_counts())
<prepare_x_and_y>
%%time
best_model.cuda() ;
subm_preds, submids = get_subm_answers(best_model, subm_dataloader, True )
X_train_dropna, y_train_dropna, mean_cols = scale_data(train_dropna)
 X_test_dropna, y_test_dropna, _ = scale_data(train_dropna, test=True)
 X_train_fill_nan, y_train_fill_nan, mean_cols = scale_data(train_fill_nan)
 X_test_fill_nan, y_test_fill_nan, _ = scale_data(train_fill_nan, test=True )<define_variables>
ans_dict = dict(zip(submids, subm_preds.astype(str)) )
flip_ratio = 0.8
rotate_ratio = 0.8
contrast_ratio = 1.2
random_seed = 342
angle = 9
use_flip_transf = True
use_rotation_transf = False
use_brightness_transf = False<create_dataframe>
df_to_process =(
 pd.DataFrame 
.from_dict(ans_dict, orient='index', columns=['Category'])
.reset_index() 
.rename({'index':'Id'}, axis=1)
)
 df_to_process['Id'] = df_to_process['Id'].map(lambda x: str(x)[:-4])
 df_to_process.head()
aug_x_train = X_train_dropna.copy()
aug_y_train = y_train_dropna.copy()<train_model>
def process_one_id(id_classes_str):
if id_classes_str:
return REVERSE_CLASSMAP[int(id_classes_str)]
else:
return id_classes_str
if use_flip_transf:
flipped_img, flipped_kepoints = flipp(aug_x_train, aug_y_train, flip_ratio, None, random_seed)
 print("Shape of flipped images {} and keypoints {}".format(flipped_img.shape, flipped_kepoints.shape))<train_model>
df_to_process['Category'] = df_to_process['Category'].apply(process_one_id)
 df_to_process.head()
<train_model><EOS> 
df_to_process.to_csv('submission.csv', index=False )