Kaggle competition: Cornell Birdcall Identification
<SOS> metric: MeanFScoreBeta Kaggle data source: cornell-birdcall-identification<train_model>
!pip install.. /input/resnest50-fast-package/resnest-0.0.6b20200701/resnest/
class DataGenerator(keras.utils.Sequence):
'Generates data for Keras'
def __init__(self, list_IDs, df, target_df=None, mode='fit',
base_path=TRAIN_IMAGE_PATH,
batch_size=32, dim=(256, 1600), n_channels=CHANNELS,
n_classes=4, random_state=2019, shuffle=True):
self.dim = dim
self.batch_size = batch_size
self.df = df
self.mode = mode
self.base_path = base_path
self.target_df = target_df
self.list_IDs = list_IDs
self.n_channels = n_channels
self.n_classes = n_classes
self.shuffle = shuffle
self.random_state = random_state
self.on_epoch_end()
def __len__(self):
'Denotes the number of batches per epoch'
ret = 0
if(len(self.list_IDs)% self.batch_size)> 0:
ret = int(len(self.list_IDs)/ self.batch_size)+ 1
else:
ret = int(np.floor(len(self.list_IDs)/ self.batch_size))
return ret
def __getitem__(self, index):
'Generate one batch of data'

 start = index * self.batch_size
end = min(len(self.list_IDs),(index + 1)* self.batch_size)
 indexes = self.indexes[start : end]
list_IDs_batch = [self.list_IDs[k] for k in indexes]
X = self.__generate_X(list_IDs_batch)
 if self.mode == 'fit':
y = self.__generate_y(list_IDs_batch)
 return X, y
elif self.mode == 'predict':
return X
else:
raise AttributeError('The mode parameter should be set to "fit" or "predict".')
 def on_epoch_end(self):
'Updates indexes after each epoch'
self.indexes = np.arange(len(self.list_IDs))
if self.shuffle == True:
np.random.seed(self.random_state)
 np.random.shuffle(self.indexes)
 def __generate_X(self, list_IDs_batch):
'Generates data containing batch_size samples'
X = np.empty(( len(list_IDs_batch), *self.dim, self.n_channels))
for i, ID in enumerate(list_IDs_batch):
im_name = self.df['ImageId'].loc[ID]
img_path = f"{self.base_path}/{im_name}"
img = self.__load_rgb(img_path)
 X[i,] = img
return X
def __generate_y(self, list_IDs_batch):
y = np.empty(( len(list_IDs_batch), *self.dim, self.n_classes), dtype=int)
 for i, ID in enumerate(list_IDs_batch):
im_name = self.df['ImageId'].loc[ID]
image_df = self.target_df[self.target_df['ImageId'] == im_name]
rles = image_df['EncodedPixels'].values
masks = build_masks(rles, input_shape=self.dim)
 y[i, ] = masks
return y
def __load_grayscale(self, img_path):

 img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
 img = img.astype(np.float32)/ 255.
 img = np.expand_dims(img, axis=-1)
 return img
def __load_rgb(self, img_path):
img = cv2.imread(img_path)
 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 img = img.astype(np.float32)/ 255.
 return img<train_model>
pd.options.display.max_rows = 500
pd.options.display.max_columns = 500
def test_DataGenerator(index = 0):
BATCH_SIZE = 16
rows = BATCH_SIZE
columns = 1
train_idx = non_missing_train_idx.index
fig = plt.figure(figsize=(16, 4 * BATCH_SIZE))
gen = DataGenerator(
 train_idx,
df=mask_count_df,
target_df=train_df,
batch_size=BATCH_SIZE,
n_classes=5)
 X, y = gen.__getitem__(index)
 print("X.shape :", X.shape)
 print("y.shape :", y.shape)
 ax_idx = 1
for i in range(BATCH_SIZE):
if ax_idx > rows * columns * 2:
break
img = X[i]
img = img * 255
img = img.astype(int)
 fig.add_subplot(rows * 2, columns, ax_idx ).set_title(str(i))
for mask_index in range(4):
mask = y[i, :, :, mask_index]
mask = mask2pad(mask,pad=3)
 mask = mask2contour(mask,width=4)
 y[i, :, :, mask_index] = mask
k = y[i, :, :, mask_index]
img[k == 1, mask_index % 3] = 255
plt.imshow(img)
 ax_idx += 1
fig.add_subplot(rows * 2, columns, ax_idx ).set_title(str(i))
img = X[i]
img = img * 255
img = img.astype(int)
 no_defect_mask = y[i, :, :, 4]
img[no_defect_mask > 0, 0] = 255
plt.imshow(img)
 ax_idx += 1
plt.show()
test_DataGenerator(TEST_INDEX )<split>
def set_seed(seed: int = 42)-> None:
random.seed(seed)
 np.random.seed(seed)
 os.environ["PYTHONHASHSEED"] = str(seed)
 torch.manual_seed(seed)
 torch.cuda.manual_seed(seed)
 @contextmanager
def timer(name: str)-> tp.Iterator[None]:

 t0 = time.time()
print("[{}] start".format(name))
yield
print("[{}] done in {:.0f} s".format(name, time.time() - t0))
BATCH_SIZE = 8
train_idx, val_idx = train_test_split(
 mask_count_df.index,
random_state=2019,
test_size=0.15 
)
 train_generator = DataGenerator(
 train_idx,
df=mask_count_df,
target_df=train_df,
batch_size=BATCH_SIZE,
n_classes=5)
 val_generator = DataGenerator(
 val_idx,
df=mask_count_df,
target_df=train_df,
batch_size=BATCH_SIZE,
n_classes=5 )<compute_test_metric>
set_seed(1213 )
def dice_coef(y_true, y_pred, smooth=1):
print(y_true.shape, y_pred.shape)
 y_true_f = K.flatten(y_true)
 y_pred_f = K.flatten(y_pred)
 intersection = K.sum(y_true_f * y_pred_f)
 return(2.* intersection + smooth)/(K.sum(y_true_f)+ K.sum(y_pred_f)+ smooth )<import_modules>
ROOT = Path.cwd().parent
INPUT_ROOT = ROOT / "input"
RAW_DATA = INPUT_ROOT / "birdsong-recognition"
TEST_AUDIO_DIR = RAW_DATA / "test_audio"
<choose_model_class>
train = pd.read_csv(RAW_DATA / "train.csv" )
<load_pretrained>
if not TEST_AUDIO_DIR.exists() :
TEST_AUDIO_DIR = INPUT_ROOT / "birdcall-check" / "test_audio"
test = pd.read_csv(INPUT_ROOT / "birdcall-check" / "test.csv")
 else:
test = pd.read_csv(RAW_DATA / "test.csv" )
def get_pretrained_model() :

 model_json_file_name = MODEL_NAME.split('.')[0] + ".json"
json_file = open(model_json_file_name, "r")
 loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
 loaded_model.load_weights(MODEL_NAME)
 loaded_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
 print("Loaded Model Input => Output : ", loaded_model.input_shape, " ======> ", loaded_model.output_shape)
 return loaded_model 
<init_hyperparams>
sub = pd.read_csv(".. /input/birdsong-recognition/sample_submission.csv")
 sub.to_csv(
 "submission.csv", index=False
)
model = get_pretrained_model()
check_df = mask_count_df.sample(10)
 gen = DataGenerator(
 check_df.index,
df=mask_count_df,
target_df=train_df,
batch_size=BATCH_SIZE,
n_classes=5,
shuffle=False)
 predict = model.predict_generator(gen )<categorify>
TARGET_SR = 32000
model_config: tp.Dict[str, tp.Union[str, int, bool]] = {
"base_model_name": "resnest50_fast_1s1x64d",
"pretrained": False,
"num_classes": 264,
"trained_weights": ".. /input/training-birdsong-baseline-resnest50-fast/best_model.pth",
}
melspectrogram_parameters = {"n_mels": 128, "fmin": 20, "fmax": 16000}
def get_one_hot(targets, nb_classes):
res = np.eye(nb_classes)[np.array(targets ).reshape(-1)]
return res.reshape(list(targets.shape)+[nb_classes])
 def pred_to_onehot(pred):
retval = np.argmax(pred, axis=-1)
 retval = get_one_hot(retval.reshape(-1), 5)
 retval = retval.reshape(pred.shape)
 return retval<init_hyperparams>
BIRD_CODE = {
"aldfly": 0,
"ameavo": 1,
"amebit": 2,
"amecro": 3,
"amegfi": 4,
"amekes": 5,
"amepip": 6,
"amered": 7,
"amerob": 8,
"amewig": 9,
"amewoo": 10,
"amtspa": 11,
"annhum": 12,
"astfly": 13,
"baisan": 14,
"baleag": 15,
"balori": 16,
"banswa": 17,
"barswa": 18,
"bawwar": 19,
"belkin1": 20,
"belspa2": 21,
"bewwre": 22,
"bkbcuc": 23,
"bkbmag1": 24,
"bkbwar": 25,
"bkcchi": 26,
"bkchum": 27,
"bkhgro": 28,
"bkpwar": 29,
"bktspa": 30,
"blkpho": 31,
"blugrb1": 32,
"blujay": 33,
"bnhcow": 34,
"boboli": 35,
"bongul": 36,
"brdowl": 37,
"brebla": 38,
"brespa": 39,
"brncre": 40,
"brnthr": 41,
"brthum": 42,
"brwhaw": 43,
"btbwar": 44,
"btnwar": 45,
"btywar": 46,
"buffle": 47,
"buggna": 48,
"buhvir": 49,
"bulori": 50,
"bushti": 51,
"buwtea": 52,
"buwwar": 53,
"cacwre": 54,
"calgul": 55,
"calqua": 56,
"camwar": 57,
"cangoo": 58,
"canwar": 59,
"canwre": 60,
"carwre": 61,
"casfin": 62,
"caster1": 63,
"casvir": 64,
"cedwax": 65,
"chispa": 66,
"chiswi": 67,
"chswar": 68,
"chukar": 69,
"clanut": 70,
"cliswa": 71,
"comgol": 72,
"comgra": 73,
"comloo": 74,
"commer": 75,
"comnig": 76,
"comrav": 77,
"comred": 78,
"comter": 79,
"comyel": 80,
"coohaw": 81,
"coshum": 82,
"cowscj1": 83,
"daejun": 84,
"doccor": 85,
"dowwoo": 86,
"dusfly": 87,
"eargre": 88,
"easblu": 89,
"easkin": 90,
"easmea": 91,
"easpho": 92,
"eastow": 93,
"eawpew": 94,
"eucdov": 95,
"eursta": 96,
"evegro": 97,
"fiespa": 98,
"fiscro": 99,
"foxspa": 100,
"gadwal": 101,
"gcrfin": 102,
"gnttow": 103,
"gnwtea": 104,
"gockin": 105,
"gocspa": 106,
"goleag": 107,
"grbher3": 108,
"grcfly": 109,
"greegr": 110,
"greroa": 111,
"greyel": 112,
"grhowl": 113,
"grnher": 114,
"grtgra": 115,
"grycat": 116,
"gryfly": 117,
"haiwoo": 118,
"hamfly": 119,
"hergul": 120,
"herthr": 121,
"hoomer": 122,
"hoowar": 123,
"horgre": 124,
"horlar": 125,
"houfin": 126,
"houspa": 127,
"houwre": 128,
"indbun": 129,
"juntit1": 130,
"killde": 131,
"labwoo": 132,
"larspa": 133,
"lazbun": 134,
"leabit": 135,
"leafly": 136,
"leasan": 137,
"lecthr": 138,
"lesgol": 139,
"lesnig": 140,
"lesyel": 141,
"lewwoo": 142,
"linspa": 143,
"lobcur": 144,
"lobdow": 145,
"logshr": 146,
"lotduc": 147,
"louwat": 148,
"macwar": 149,
"magwar": 150,
"mallar3": 151,
"marwre": 152,
"merlin": 153,
"moublu": 154,
"mouchi": 155,
"moudov": 156,
"norcar": 157,
"norfli": 158,
"norhar2": 159,
"normoc": 160,
"norpar": 161,
"norpin": 162,
"norsho": 163,
"norwat": 164,
"nrwswa": 165,
"nutwoo": 166,
"olsfly": 167,
"orcwar": 168,
"osprey": 169,
"ovenbi1": 170,
"palwar": 171,
"pasfly": 172,
"pecsan": 173,
"perfal": 174,
"phaino": 175,
"pibgre": 176,
"pilwoo": 177,
"pingro": 178,
"pinjay": 179,
"pinsis": 180,
"pinwar": 181,
"plsvir": 182,
"prawar": 183,
"purfin": 184,
"pygnut": 185,
"rebmer": 186,
"rebnut": 187,
"rebsap": 188,
"rebwoo": 189,
"redcro": 190,
"redhea": 191,
"reevir1": 192,
"renpha": 193,
"reshaw": 194,
"rethaw": 195,
"rewbla": 196,
"ribgul": 197,
"rinduc": 198,
"robgro": 199,
"rocpig": 200,
"rocwre": 201,
"rthhum": 202,
"ruckin": 203,
"rudduc": 204,
"rufgro": 205,
"rufhum": 206,
"rusbla": 207,
"sagspa1": 208,
"sagthr": 209,
"savspa": 210,
"saypho": 211,
"scatan": 212,
"scoori": 213,
"semplo": 214,
"semsan": 215,
"sheowl": 216,
"shshaw": 217,
"snobun": 218,
"snogoo": 219,
"solsan": 220,
"sonspa": 221,
"sora": 222,
"sposan": 223,
"spotow": 224,
"stejay": 225,
"swahaw": 226,
"swaspa": 227,
"swathr": 228,
"treswa": 229,
"truswa": 230,
"tuftit": 231,
"tunswa": 232,
"veery": 233,
"vesspa": 234,
"vigswa": 235,
"warvir": 236,
"wesblu": 237,
"wesgre": 238,
"weskin": 239,
"wesmea": 240,
"wessan": 241,
"westan": 242,
"wewpew": 243,
"whbnut": 244,
"whcspa": 245,
"whfibi": 246,
"whtspa": 247,
"whtswi": 248,
"wilfly": 249,
"wilsni1": 250,
"wiltur": 251,
"winwre3": 252,
"wlswar": 253,
"wooduc": 254,
"wooscj2": 255,
"woothr": 256,
"y00475": 257,
"yebfly": 258,
"yebsap": 259,
"yehbla": 260,
"yelwar": 261,
"yerwar": 262,
"yetvir": 263,
}
INV_BIRD_CODE = {v: k for k, v in BIRD_CODE.items() }
def show_test_prediction_head(n=60):
def clear_memory() :
clear_session()
for i in range(20):
gc.collect()
clear_memory()
TEST_BATCH_SIZE = n
test_df = get_test_df()
test_images_df = get_test_imgs_df()
batch_idx = list(range(0, min(test_images_df.shape[0], TEST_BATCH_SIZE)))
 print("running: ", 0, " - ", min(test_images_df.shape[0], TEST_BATCH_SIZE))
model = get_pretrained_model()
test_generator = DataGenerator(
 batch_idx,
df=test_images_df,
base_path = TEST_IMAGE_PATH,
target_df=test_df,
mode = 'predict',
batch_size=TEST_BATCH_SIZE,
shuffle=False,
n_classes=5)
 src_generator = DataGenerator(
 batch_idx,
df=test_images_df,
base_path = TEST_IMAGE_PATH,
target_df=test_df,
batch_size=TEST_BATCH_SIZE,
shuffle=False,
n_classes=5)
 X, _ = src_generator.__getitem__(0)
 predict = model.predict_generator(test_generator)
 pred = pred_to_onehot(predict)
 columns = 1
rows = TEST_BATCH_SIZE
fig = plt.figure(figsize=(12, 3 * rows))
ax_idx = 1
for i in range(rows):
if ax_idx > rows * columns:
break
fig.add_subplot(rows, columns, ax_idx ).set_title(str(i))
img = X[i]
img = img * 255
img = img.astype(int)
 for mask_index in range(4):
k = pred[i, :, :, mask_index]
img[k == 1, mask_index % 3] = 255
plt.imshow(img)
 ax_idx += 1
plt.show() 
<define_variables>
def get_model(args: tp.Dict)-> nn.Module:

 model = getattr(resnest_torch, args["base_model_name"] )(pretrained=args["pretrained"])
 del model.fc
model.fc = nn.Sequential(
 nn.Linear(2048, 1024),
nn.ReLU() ,
nn.Dropout(p=0.2),
nn.Linear(1024, 1024),
nn.ReLU() ,
nn.Dropout(p=0.2),
nn.Linear(1024, args["num_classes"]), 
)
 state_dict = torch.load(args["trained_weights"])
 model.load_state_dict(state_dict)
 device = torch.device("cuda")
 model.to(device)
 model.eval()
return model
def clear_memory() :
clear_session()
for i in range(20):
gc.collect()
clear_memory()
TEST_BATCH_SIZE = 100
df_submit = []
MIN_MASK_PIXEL_THRESHOLD = 3500
test_df = get_test_df()
test_images_df = get_test_imgs_df()
for batch_start in range(0, test_images_df.shape[0], TEST_BATCH_SIZE):
batch_idx = list(range(batch_start, min(test_images_df.shape[0], batch_start + TEST_BATCH_SIZE)))
 print("running: ", batch_start, " - ", min(test_images_df.shape[0], batch_start + TEST_BATCH_SIZE))
model = get_pretrained_model()
test_generator = DataGenerator(
 batch_idx,
df=test_images_df,
base_path = TEST_IMAGE_PATH,
target_df=test_df,
mode = 'predict',
batch_size=BATCH_SIZE,
shuffle=False,
n_classes=5)
 predict = model.predict_generator(test_generator)
 pred = pred_to_onehot(predict)
 for index, bindex, in enumerate(batch_idx):
fname = test_images_df['ImageId'].loc[bindex]
image_df = test_df[test_df['ImageId'] == fname]
pred_masks = pred[index, ]
for mask_index in range(4):
pixelcnt = np.count_nonzero(pred_masks[:,:,mask_index])
 if pixelcnt < MIN_MASK_PIXEL_THRESHOLD:
pred_masks[:,:,mask_index] = 0
pred_masks = pred_masks[:, :, :-1]
pred_rles = build_rles(pred_masks)
 image_df['EncodedPixels'] = pred_rles
df_submit.append(image_df)
 clear_memory()
df_submit = pd.concat(df_submit)
 print(df_submit.shape[0])
 df_submit.head()<save_to_csv>
def prediction_for_clip(
 test_df: pd.DataFrame,
clip: np.ndarray,
model: nn.Module,
mel_params: tp.Dict[str, int],
threshold: float = 0.5, 
)-> tp.Dict[str, str]:

 assert clip.ndim == 1
pd.testing.assert_index_equal(
 test_df.columns, pd.Index(["site", "row_id", "seconds", "audio_id"])
)
 dataset = TestDataset(
 df=test_df, clip=clip, img_size=224, melspectrogram_parameters=mel_params 
)
 loader = data.DataLoader(dataset, batch_size=1, shuffle=False)
 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 model.eval()
prediction_dict = {}
for image, row_id, site in progress_bar(loader):
assert image.ndim == 4
batch_size, channels, frequency, time = image.shape
assert(batch_size, channels, frequency)==(1, 3, 224)
 assert len(row_id)== 1
assert len(site)== 1 
(site,)= site 
(row_id,)= row_id
image = image.to(device)
 with torch.no_grad() :
prediction = torch.sigmoid(model(image))
proba = prediction.detach().cpu().numpy().reshape(-1)
 assert proba.shape ==(264,)
 events = proba >= threshold
labels = np.argwhere(events ).reshape(-1 ).tolist()
if len(labels)== 0:
prediction_dict[row_id] = "nocall"
else:
labels_str_list = list(map(lambda x: INV_BIRD_CODE[x], labels))
label_string = " ".join(labels_str_list)
 prediction_dict[row_id] = label_string
return prediction_dict
df_submit[['ImageId_ClassId', 'EncodedPixels']].to_csv('submission.csv', index=False )<import_modules>
def prediction(
 test_df: pd.DataFrame,
test_audio: Path,
model_config: tp.Dict[str, tp.Union[str, int, bool]],
mel_params: tp.Dict[str, int],
target_sr: int,
threshold: float = 0.5, 
)-> pd.DataFrame:

 model = get_model(model_config)
 unique_audio_id = test_df.audio_id.unique()
prediction_dfs = []
for audio_id in unique_audio_id:
with timer(f"Loading {audio_id}"), warnings.catch_warnings() :
warnings.simplefilter("ignore", UserWarning)
 clip, _ = librosa.load(
 test_audio /(audio_id + ".mp3"),
sr=target_sr,
mono=True,
res_type="kaiser_fast", 
)
 test_df_for_audio_id = test_df.query(f"audio_id == '{audio_id}'")
 test_df_for_audio_id = test_df_for_audio_id.reset_index(drop=True)
 with timer(f"Prediction on {audio_id}"):
prediction_dict = prediction_for_clip(
 test_df_for_audio_id,
clip=clip,
model=model,
mel_params=mel_params,
threshold=threshold, 
)
 row_id = list(prediction_dict.keys())
 birds = list(prediction_dict.values())
 prediction_df = pd.DataFrame({"row_id": row_id, "birds": birds})
 prediction_dfs.append(prediction_df)
 prediction_df = pd.concat(prediction_dfs, axis=0, sort=False ).reset_index(drop=True)
 assert len(prediction_df)== len(test_df)
 return prediction_df
<import_modules><EOS> 
submission = prediction(
 test_df=test,
test_audio=TEST_AUDIO_DIR,
model_config=model_config,
mel_params=melspectrogram_parameters,
target_sr=TARGET_SR,
threshold=0.6, 
)
 submission.to_csv("submission.csv", index=False )