Kaggle competition: Cornell Birdcall Identification
<SOS> metric: MeanFScoreBeta Kaggle data source: cornell-birdcall-identification<define_variables>
!pip install librosa
new_train_runs3 = [2484, 3062, 2290, 3517, 3293, 2651, 3767,
2029, 2558, 3580, 1874, 3373, 2514, 2308, 3160, 3161, 3613, 2511,
2469, 2990, 2780, 3756, 2376, 2616, 2540, 2039, 2219, 3743, 3198,
2584, 2752, 2304, 2887, 2841, 3480, 2517, 3020, 3424, 2027, 2652,
2648, 3433, 2359, 3392, 3164, 3798, 3642, 2713, 3405, 3673, 2369,
3411, 3595, 2242, 2307, 1897, 2834, 2350, 3795, 2948, 1856, 3486,
3353, 1966]
train_runs[third_double_surface] = train_runs[third_double_surface][0:-len(new_train_runs3)]
train_runs.append(np.array(new_train_runs3))<define_variables>
import numpy as np
import pandas as pd
import os
fourth_double_surface = 0
for i in range(0, len(train_runs)) :
for x in train_runs[i]:
if x==3501:
print(i)
 fourth_double_surface = i<filter>
audio_data = '/kaggle/input/birdsong-recognition/train_audio/nutwoo/XC462016.mp3'
x , sr = librosa.load(audio_data)
 print(type(x), type(sr))
print(x.shape, sr )
train_runs[fourth_double_surface]<prepare_x_and_y>
librosa.load(audio_data, sr=44100 )
new_train_runs4 = [3501, 2785]
train_runs[fourth_double_surface] = train_runs[fourth_double_surface][0:-len(new_train_runs4)]
train_runs.append(np.array(new_train_runs4))<feature_engineering>
ipd.Audio(audio_data )
df_train_y = pd.DataFrame()
df_train_y['run_id'] = 0
df_train_y['run_pos'] = 0
for run_id in range(len(train_runs)) :
for run_pos in range(len(train_runs[run_id])) :
series_id = train_runs[run_id][run_pos]
df_train_y.at[ series_id, 'run_id' ] = run_id
df_train_y.at[ series_id, 'run_pos' ] = run_pos
df_train_y.tail()<feature_engineering>
%matplotlib inline
plt.figure(figsize=(14, 5))
librosa.display.waveplot(x, sr=sr )
df_train_y['index'] = df_train_y.index
df_train_y = df_train_y.sort_values('index')
 df_train_y.rename(columns={'index':'series_id'}, inplace=True)
 df_train_y['run_id'] = df_train_y['run_id'].apply(lambda x: int(x))
df_train_y['run_pos'] = df_train_y['run_pos'].apply(lambda x: int(x))
df_train_y.tail()<split>
sr = 22050
T = 5.0
t = np.linspace(0, T, int(T*sr), endpoint=False)
 x = 0.5*np.sin(2*np.pi*220*t)
 ipd.Audio(x, rate=sr)
 librosa.output.write_wav('tone_220.wav', x, sr )
run_id_train = df_train_y['run_id'][0:3810].values
run_id_test = df_train_y['run_id'][3810:7626].values<categorify>
zero_crossings = librosa.zero_crossings(x[n0:n1], pad=False)
 print(sum(zero_crossings))
data_target['run_id'] = run_id_train
mapping_leak = {}
for i in range(0,3810):
cur_data = data_target.iloc[i]
mapping_leak.update({cur_data['run_id']: cur_data['surface']})
 unknown_run = []
ans_test = []
known_series = []
unknown_series = []
for i in range(0,3816):
if run_id_test[i] in mapping_leak:
ans_test.append(mapping_leak[run_id_test[i]])
 known_series.append(i)
 else:
ans_test.append('unknown')
 unknown_series.append(i)
 unknown_run.append(run_id_test[i] )<load_from_csv>
import cv2
import audioread
import logging
import os
import random
import time
import warnings
import librosa
import numpy as np
import pandas as pd
import soundfile as sf
import torch
import torch.nn as nn
import torch.cuda
import torch.nn.functional as F
import torch.utils.data as data
from contextlib import contextmanager
from pathlib import Path
from typing import Optional
from fastprogress import progress_bar
from sklearn.metrics import f1_score
from torchvision import models
sub = pd.read_csv(PATH+"/sample_submission.csv")
 sub['surface'] = ans_test
sub.head()<load_from_csv>
def set_seed(seed: int = 42):
random.seed(seed)
 np.random.seed(seed)
 os.environ["PYTHONHASHSEED"] = str(seed)
 torch.manual_seed(seed)
 torch.cuda.manual_seed(seed)
 torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = True
def get_logger(out_file=None):
logger = logging.getLogger()
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
 logger.handlers = []
logger.setLevel(logging.INFO)
 handler = logging.StreamHandler()
handler.setFormatter(formatter)
 handler.setLevel(logging.INFO)
 logger.addHandler(handler)
 if out_file is not None:
fh = logging.FileHandler(out_file)
 fh.setFormatter(formatter)
 fh.setLevel(logging.INFO)
 logger.addHandler(fh)
 logger.info("logger set up")
 return logger
@contextmanager
def timer(name: str, logger: Optional[logging.Logger] = None):
t0 = time.time()
msg = f"[{name}] start"
if logger is None:
print(msg)
 else:
logger.info(msg)
 yield
msg = f"[{name}] done in {time.time() - t0:.2f} s"
if logger is None:
print(msg)
 else:
logger.info(msg )
best = pd.read_csv('.. /input/robots-best-submission/mybest0.73.csv')
 map_best_ans = {}
for i in range(0, best.shape[0]):
map_best_ans.update({best.iloc[i]['series_id'] : best.iloc[i]['surface'] } )<define_variables>
logger = get_logger("main.log")
 set_seed(1213 )
result = []
for i in range(0, sub.shape[0]):
if(sub.surface[i] == 'unknown'):
result.append(map_best_ans[i])
 else:
result.append(sub.surface[i] )<save_to_csv>
TARGET_SR = 32000
TEST = Path(".. /input/birdsong-recognition/test_audio" ).exists()
sub.surface = result
sub.to_csv('submission3.csv', index=False)
 sub.head()<count_values>
if TEST:
DATA_DIR = Path(".. /input/birdsong-recognition/")
 else:
DATA_DIR = Path(".. /input/birdcall-check/")
 test = pd.read_csv(DATA_DIR / "test.csv")
 test_audio = DATA_DIR / "test_audio"
test.head()
sub.surface.value_counts()<set_options>
sub = pd.read_csv(".. /input/birdsong-recognition/sample_submission.csv")
 sub.to_csv("submission.csv", index=False )
gc.collect()<load_from_csv>
class ResNet(nn.Module):
def __init__(self, base_model_name: str, pretrained=False,
num_classes=264):
super().__init__()
base_model = models.__getattribute__(base_model_name )(
 pretrained=pretrained)
 layers = list(base_model.children())[:-2]
layers.append(nn.AdaptiveMaxPool2d(1))
self.encoder = nn.Sequential(*layers)
 in_features = base_model.fc.in_features
self.classifier = nn.Sequential(
 nn.Linear(in_features, 1024), nn.ReLU() , nn.Dropout(p=0.2),
nn.Linear(1024, 1024), nn.ReLU() , nn.Dropout(p=0.2),
nn.Linear(1024, num_classes))
def forward(self, x):
batch_size = x.size(0)
 x = self.encoder(x ).view(batch_size, -1)
 x = self.classifier(x)
 multiclass_proba = F.softmax(x, dim=1)
 multilabel_proba = F.sigmoid(x)
 return {
"logits": x,
"multiclass_proba": multiclass_proba,
"multilabel_proba": multilabel_proba
}
X_train=pd.read_csv('.. /input/X_train.csv')
 y_train=pd.read_csv('.. /input/y_train.csv')
 X_test=pd.read_csv('.. /input/X_test.csv')
 y_test=pd.read_csv('.. /input/sample_submission.csv' )<concatenate>
model_config = {
"base_model_name": "resnet50",
"pretrained": False,
"num_classes": 264
}
melspectrogram_parameters = {
"n_mels": 128,
"fmin": 20,
"fmax": 16000
}
weights_path = ".. /input/birdcall-resnet50-init-weights/best.pth"
def quaternion_to_euler(x, y, z, w):
t0 = +2.0 *(w * x + y * z)
 t1 = +1.0 - 2.0 *(x * x + y * y)
 X = math.atan2(t0, t1)
 t2 = +2.0 *(w * y - z * x)
 t2 = +1.0 if t2 > +1.0 else t2
t2 = -1.0 if t2 < -1.0 else t2
Y = math.asin(t2)
 t3 = +2.0 *(w * z + x * y)
 t4 = +1.0 - 2.0 *(y * y + z * z)
 Z = math.atan2(t3, t4)
 return X, Y, Z<feature_engineering>
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 perform_euler_factors_calculation(df):
df['total_angular_velocity'] = np.sqrt(np.square(df['angular_velocity_X'])+ np.square(df['angular_velocity_Y'])+ np.square(df['angular_velocity_Z']))
df['total_linear_acceleration'] = np.sqrt(np.square(df['linear_acceleration_X'])+ np.square(df['linear_acceleration_Y'])+ np.square(df['linear_acceleration_Z']))
df['total_xyz'] = np.sqrt(np.square(df['orientation_X'])+ np.square(df['orientation_Y'])+
np.square(df['orientation_Z']))
df['acc_vs_vel'] = df['total_linear_acceleration'] / df['total_angular_velocity']
x, y, z, w = df['orientation_X'].tolist() , df['orientation_Y'].tolist() , df['orientation_Z'].tolist() , df['orientation_W'].tolist()
nx, ny, nz = [], [], []
for i in range(len(x)) :
xx, yy, zz = quaternion_to_euler(x[i], y[i], z[i], w[i])
 nx.append(xx)
 ny.append(yy)
 nz.append(zz)
 df['euler_x'] = nx
df['euler_y'] = ny
df['euler_z'] = nz
df['total_angle'] = np.sqrt(np.square(df['euler_x'])+ np.square(df['euler_y'])+ np.square(df['euler_z']))
df['angle_vs_acc'] = df['total_angle'] / df['total_linear_acceleration']
df['angle_vs_vel'] = df['total_angle'] / df['total_angular_velocity']
return df<create_dataframe>
def get_model(config: dict, weights_path: str):
model = ResNet(**config)
 checkpoint = torch.load(weights_path)
 model.load_state_dict(checkpoint["model_state_dict"])
 device = torch.device("cuda")
 model.to(device)
 model.eval()
return model
def perform_feature_engineering(df):
df_out = pd.DataFrame()
for col in df.columns:
if col in ['row_id', 'series_id', 'measurement_number']:
continue
df_out[col + '_mean'] = df.groupby(['series_id'])[col].mean()
df_out[col + '_min'] = df.groupby(['series_id'])[col].min()
df_out[col + '_max'] = df.groupby(['series_id'])[col].max()
df_out[col + '_std'] = df.groupby(['series_id'])[col].std()
df_out[col + '_mad'] = df.groupby(['series_id'])[col].mad()
df_out[col + '_med'] = df.groupby(['series_id'])[col].median()
df_out[col + '_skew'] = df.groupby(['series_id'])[col].skew()
df_out[col + '_range'] = df_out[col + '_max'] - df_out[col + '_min']
df_out[col + '_max_to_min'] = df_out[col + '_max'] / df_out[col + '_min']
df_out[col + '_mean_abs_change'] = df.groupby('series_id')[col].apply(lambda x: np.mean(np.abs(np.diff(x))))
df_out[col + '_mean_change_of_abs_change'] = df.groupby('series_id')[col].apply(lambda x: np.mean(np.diff(np.abs(np.diff(x)))))
 df_out[col + '_abs_max'] = df.groupby('series_id')[col].apply(lambda x: np.max(np.abs(x)))
 df_out[col + '_abs_min'] = df.groupby('series_id')[col].apply(lambda x: np.min(np.abs(x)))
 df_out[col + '_abs_mean'] = df.groupby('series_id')[col].apply(lambda x: np.mean(np.abs(x)))
 df_out[col + '_abs_std'] = df.groupby('series_id')[col].apply(lambda x: np.std(np.abs(x)))
 df_out[col + '_abs_avg'] =(df_out[col + '_abs_min'] + df_out[col + '_abs_max'])/2
df_out[col + '_abs_range'] = df_out[col + '_abs_max'] - df_out[col + '_abs_min']
return df_out<compute_test_metric>
def prediction_for_clip(test_df: pd.DataFrame,
clip: np.ndarray,
model: ResNet,
mel_params: dict,
threshold=0.55):
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):
site = site[0]
row_id = row_id[0]
if site in {"site_1", "site_2"}:
image = image.to(device)
 with torch.no_grad() :
prediction = model(image)
 proba = prediction["multilabel_proba"].detach().cpu().numpy().reshape(-1)
 events = proba >= threshold
labels = np.argwhere(events ).reshape(-1 ).tolist()
else:
image = image.squeeze(0)
 batch_size = 16
whole_size = image.size(0)
 if whole_size % batch_size == 0:
n_iter = whole_size // batch_size
else:
n_iter = whole_size // batch_size + 1
all_events = set()
for batch_i in range(n_iter):
batch = image[batch_i * batch_size:(batch_i + 1)* batch_size]
if batch.ndim == 3:
batch = batch.unsqueeze(0)
 batch = batch.to(device)
 with torch.no_grad() :
prediction = model(batch)
 proba = prediction["multilabel_proba"].detach().cpu().numpy()
events = proba >= threshold
for i in range(len(events)) :
event = events[i, :]
labels = np.argwhere(event ).reshape(-1 ).tolist()
for label in labels:
all_events.add(label)
 labels = list(all_events)
 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
X_test = perform_euler_factors_calculation(X_test )<feature_engineering>
def prediction(test_df: pd.DataFrame,
test_audio: Path,
model_config: dict,
mel_params: dict,
weights_path: str,
threshold=0.5):
model = get_model(model_config, weights_path)
 unique_audio_id = test_df.audio_id.unique()
warnings.filterwarnings("ignore")
 prediction_dfs = []
for audio_id in unique_audio_id:
with timer(f"Loading {audio_id}", logger):
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}'" ).reset_index(drop=True)
 with timer(f"Prediction on {audio_id}", logger):
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)
 return prediction_df
<feature_engineering><EOS> 
submission = prediction(test_df=test,
test_audio=test_audio,
model_config=model_config,
mel_params=melspectrogram_parameters,
weights_path=weights_path,
threshold=0.85)
 submission.to_csv("submission.csv", index=False )