{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Notes","metadata":{}},{"cell_type":"markdown","source":"I've released a [training kernel](https://www.kaggle.com/kneroma/clean-fast-simple-bird-identifier-training-colab) and an [inference kernel](https://www.kaggle.com/kneroma/clean-fast-simple-bird-identifier-inference). Both of these kernels use a set of pre-computed mels. Which can be found at:\n\n* https://www.kaggle.com/kneroma/kkiller-birdclef-mels-computer-d7-part1\n* https://www.kaggle.com/kneroma/kkiller-birdclef-mels-computer-d7-part2\n* https://www.kaggle.com/kneroma/kkiller-birdclef-mels-computer-d7-part3\n* https://www.kaggle.com/kneroma/kkiller-birdclef-mels-computer-d7-part4\n\nUnfortunately, these mels are static (7s audio extracts) and you can't get any customization from them. Here, I'm releasing the base kernel that generate them in order to allow everyone to be able to play with the params.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport librosa as lb\nimport librosa.display as lbd\nimport soundfile as sf\nfrom  soundfile import SoundFile\nimport pandas as pd\nfrom  IPython.display import Audio\nfrom pathlib import Path\n\nfrom matplotlib import pyplot as plt\n\nfrom tqdm.notebook import tqdm\nimport joblib, json\n\nfrom  sklearn.model_selection  import StratifiedKFold","metadata":{"id":"2dt7oG43VAqc","execution":{"iopub.status.busy":"2023-06-20T04:22:11.860794Z","iopub.execute_input":"2023-06-20T04:22:11.861154Z","iopub.status.idle":"2023-06-20T04:22:11.866318Z","shell.execute_reply.started":"2023-06-20T04:22:11.861122Z","shell.execute_reply":"2023-06-20T04:22:11.865401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PART_ID = 0 # The start index in the below list, by changing it you will compute mels on another subset\nPART_INDEXES = [0,15718, 31436, 47154, 62874] # The train_set is splitted into 4 subsets","metadata":{"id":"fJB9IS2RVAqe","execution":{"iopub.status.busy":"2023-06-20T04:22:11.867999Z","iopub.execute_input":"2023-06-20T04:22:11.868484Z","iopub.status.idle":"2023-06-20T04:22:11.883472Z","shell.execute_reply.started":"2023-06-20T04:22:11.868449Z","shell.execute_reply":"2023-06-20T04:22:11.882020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SR = 32_000\nDURATION = 7 \nSEED = 666\n\nDATA_ROOT = Path(\"../input/birdclef-2021\")\nTRAIN_AUDIO_ROOT = Path(\"/kaggle/input/birdclef2021augmentedaudio/train_augmented_audio\")\nTRAIN_AUDIO_IMAGES_SAVE_ROOT = Path(\"audio_images\") # Where to save the mels images\nTRAIN_AUDIO_IMAGES_SAVE_ROOT.mkdir(exist_ok=True, parents=True)","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:11.884845Z","iopub.execute_input":"2023-06-20T04:22:11.885356Z","iopub.status.idle":"2023-06-20T04:22:11.896279Z","shell.execute_reply.started":"2023-06-20T04:22:11.885312Z","shell.execute_reply":"2023-06-20T04:22:11.894225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_audio_info(filepath):\n    \"\"\"Get some properties from  an audio file\"\"\"\n    with SoundFile(filepath) as f:\n        sr = f.samplerate\n        frames = f.frames\n        duration = float(frames)/sr\n    return {\"frames\": frames, \"sr\": sr, \"duration\": duration}","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:11.899128Z","iopub.execute_input":"2023-06-20T04:22:11.899495Z","iopub.status.idle":"2023-06-20T04:22:11.914822Z","shell.execute_reply.started":"2023-06-20T04:22:11.899459Z","shell.execute_reply":"2023-06-20T04:22:11.913414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def make_df(n_splits=5, seed=SEED, nrows=None):\n    \n    df0 = pd.read_csv(DATA_ROOT/\"train_metadata.csv\", nrows=nrows)\n\n    LABEL_IDS = {label: label_id for label_id,label in enumerate(sorted(df0[\"primary_label\"].unique()))}\n    \n    df = df0.iloc[PART_INDEXES[PART_ID]: PART_INDEXES[PART_ID+1]]\n    print(df)\n\n    df[\"label_id\"] = df[\"primary_label\"].map(LABEL_IDS)\n\n    df[\"filepath\"] = [str(TRAIN_AUDIO_ROOT/primary_label/filename) for primary_label,filename in zip(df.primary_label, df.filename) ]\n\n    pool = joblib.Parallel(4)\n    mapper = joblib.delayed(get_audio_info)\n    tasks = [mapper(filepath) for filepath in df.filepath]\n\n    temp = pd.DataFrame(pool(tqdm(tasks)))\n    print(temp)\n    df = pd.concat([df.reset_index(), temp], axis=1, sort=False)\n    \n    print('pdf.conat', df)\n    print(df.label_id.values)\n    \n    skf = StratifiedKFold(n_splits=n_splits, random_state=seed, shuffle=True)\n    splits = skf.split(np.arange(len(df)), y=df.label_id.values)\n    \n    df[\"fold\"] = -1\n\n    for fold, (train_set, val_set) in enumerate(splits):\n        \n        df.loc[df.index[val_set], \"fold\"] = fold\n\n    return LABEL_IDS, df","metadata":{"id":"Kmh6xx5_NCjJ","outputId":"ad61f09f-6f0e-4204-c658-21112e051785","execution":{"iopub.status.busy":"2023-06-20T04:22:11.916541Z","iopub.execute_input":"2023-06-20T04:22:11.916849Z","iopub.status.idle":"2023-06-20T04:22:11.930788Z","shell.execute_reply.started":"2023-06-20T04:22:11.916810Z","shell.execute_reply":"2023-06-20T04:22:11.929401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LABEL_IDS, df = make_df(nrows=None)\n\ndf.to_csv(\"rich_train_metadata.csv\", index=True)\nwith open(\"LABEL_IDS.json\", \"w\") as f:\n    json.dump(LABEL_IDS, f)\n\nprint(df.shape)\ndf.head()","metadata":{"id":"SRRhx1EAN75G","outputId":"f1688387-b564-4f8d-8895-4490c90d4150","execution":{"iopub.status.busy":"2023-06-20T04:22:11.932266Z","iopub.execute_input":"2023-06-20T04:22:11.932665Z","iopub.status.idle":"2023-06-20T04:22:27.184492Z","shell.execute_reply.started":"2023-06-20T04:22:11.932627Z","shell.execute_reply":"2023-06-20T04:22:27.183572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"fold\"].value_counts()","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.185922Z","iopub.execute_input":"2023-06-20T04:22:27.186422Z","iopub.status.idle":"2023-06-20T04:22:27.194215Z","shell.execute_reply.started":"2023-06-20T04:22:27.186381Z","shell.execute_reply":"2023-06-20T04:22:27.192884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"primary_label\"].value_counts()","metadata":{"id":"ZRz-DwbNVAqg","outputId":"51f26b97-6a1e-4e39-c6fa-5114cfe27a25","execution":{"iopub.status.busy":"2023-06-20T04:22:27.196222Z","iopub.execute_input":"2023-06-20T04:22:27.196615Z","iopub.status.idle":"2023-06-20T04:22:27.213504Z","shell.execute_reply.started":"2023-06-20T04:22:27.196577Z","shell.execute_reply":"2023-06-20T04:22:27.212023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"duration\"].hist(bins=20)","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.215036Z","iopub.execute_input":"2023-06-20T04:22:27.215310Z","iopub.status.idle":"2023-06-20T04:22:27.445478Z","shell.execute_reply.started":"2023-06-20T04:22:27.215283Z","shell.execute_reply":"2023-06-20T04:22:27.444008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"duration\"].quantile(np.arange(0, 1, 0.01)).plot()","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.448025Z","iopub.execute_input":"2023-06-20T04:22:27.448304Z","iopub.status.idle":"2023-06-20T04:22:27.622778Z","shell.execute_reply.started":"2023-06-20T04:22:27.448274Z","shell.execute_reply":"2023-06-20T04:22:27.620710Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"xh4hfWZhuglm"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MelSpecComputer:\n    def __init__(self, sr, n_mels, fmin, fmax, **kwargs):\n        self.sr = sr\n        self.n_mels = n_mels\n        self.fmin = fmin\n        self.fmax = fmax\n        kwargs[\"n_fft\"] = kwargs.get(\"n_fft\", self.sr//10)\n        kwargs[\"hop_length\"] = kwargs.get(\"hop_length\", self.sr//(10*4))\n        self.kwargs = kwargs\n\n    def __call__(self, y):\n\n        melspec = lb.feature.melspectrogram(\n            y, sr=self.sr, n_mels=self.n_mels, fmin=self.fmin, fmax=self.fmax, **self.kwargs,\n        )\n\n        melspec = lb.power_to_db(melspec).astype(np.float32)\n        return melspec","metadata":{"id":"7NZq43qTVAqi","execution":{"iopub.status.busy":"2023-06-20T04:22:27.624413Z","iopub.execute_input":"2023-06-20T04:22:27.624885Z","iopub.status.idle":"2023-06-20T04:22:27.632817Z","shell.execute_reply.started":"2023-06-20T04:22:27.624844Z","shell.execute_reply":"2023-06-20T04:22:27.631904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mono_to_color(X, eps=1e-6, mean=None, std=None):\n    mean = mean or X.mean()\n    std = std or X.std()\n    X = (X - mean) / (std + eps)\n    \n    _min, _max = X.min(), X.max()\n\n    if (_max - _min) > eps:\n        V = np.clip(X, _min, _max)\n        V = 255 * (V - _min) / (_max - _min)\n        V = V.astype(np.uint8)\n    else:\n        V = np.zeros_like(X, dtype=np.uint8)\n\n    return V\n\ndef crop_or_pad(y, length, is_train=True, start=None):\n    if len(y) < length:\n        y = np.concatenate([y, np.zeros(length - len(y))])\n        \n        n_repeats = length // len(y)\n        epsilon = length % len(y)\n        \n        y = np.concatenate([y]*n_repeats + [y[:epsilon]])\n        \n    elif len(y) > length:\n        if not is_train:\n            start = start or 0\n        else:\n            start = start or np.random.randint(len(y) - length)\n\n        y = y[start:start + length]\n\n    return y","metadata":{"id":"-Nlw4E5UVAqi","execution":{"iopub.status.busy":"2023-06-20T04:22:27.634015Z","iopub.execute_input":"2023-06-20T04:22:27.634268Z","iopub.status.idle":"2023-06-20T04:22:27.650660Z","shell.execute_reply.started":"2023-06-20T04:22:27.634241Z","shell.execute_reply":"2023-06-20T04:22:27.648784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class AudioToImage:\n    def __init__(self, sr=SR, n_mels=128, fmin=0, fmax=None, duration=DURATION, step=None, res_type=\"kaiser_fast\", resample=True):\n\n        self.sr = sr\n        self.n_mels = n_mels\n        self.fmin = fmin\n        self.fmax = fmax or self.sr//2\n\n        self.duration = duration\n        self.audio_length = self.duration*self.sr\n        self.step = step or self.audio_length\n        \n        self.res_type = res_type\n        self.resample = resample\n\n        self.mel_spec_computer = MelSpecComputer(sr=self.sr, n_mels=self.n_mels, fmin=self.fmin,\n                                                 fmax=self.fmax)\n        \n    def audio_to_image(self, audio):\n        melspec = self.mel_spec_computer(audio) \n        image = mono_to_color(melspec)\n#         image = normalize(image, mean=None, std=None)\n        return image\n\n    def __call__(self, row, save=True):\n#       max_audio_duration = 10*self.duration\n#       init_audio_length = max_audio_duration*row.sr\n        \n#       start = 0 if row.duration <  max_audio_duration else np.random.randint(row.frames - init_audio_length)\n    \n      audio, orig_sr = sf.read(row.filepath, dtype=\"float32\")\n\n      if self.resample and orig_sr != self.sr:\n        audio = lb.resample(audio, orig_sr, self.sr, res_type=self.res_type)\n        \n      audios = [audio[i:i+self.audio_length] for i in range(0, max(1, len(audio) - self.audio_length + 1), self.step)]\n      audios[-1] = crop_or_pad(audios[-1] , length=self.audio_length)\n      images = [self.audio_to_image(audio) for audio in audios]\n      images = np.stack(images)\n        \n      if save:\n        path = TRAIN_AUDIO_IMAGES_SAVE_ROOT/f\"{row.primary_label}/{row.filename}.npy\"\n        path.parent.mkdir(exist_ok=True, parents=True)\n        np.save(str(path), images)\n      else:\n        return  row.filename, images","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.652624Z","iopub.execute_input":"2023-06-20T04:22:27.652998Z","iopub.status.idle":"2023-06-20T04:22:27.668978Z","shell.execute_reply.started":"2023-06-20T04:22:27.652955Z","shell.execute_reply":"2023-06-20T04:22:27.667723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_audios_as_images(df):\n    pool = joblib.Parallel(2)\n    \n    converter = AudioToImage(step=int(DURATION*0.666*SR))\n    mapper = joblib.delayed(converter)\n    tasks = [mapper(row) for row in df.itertuples(False)]\n    \n    pool(tqdm(tasks))","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.670856Z","iopub.execute_input":"2023-06-20T04:22:27.671264Z","iopub.status.idle":"2023-06-20T04:22:27.688279Z","shell.execute_reply.started":"2023-06-20T04:22:27.671226Z","shell.execute_reply":"2023-06-20T04:22:27.686446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_audios_as_images(df)","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:27.689954Z","iopub.execute_input":"2023-06-20T04:22:27.690389Z","iopub.status.idle":"2023-06-20T04:22:42.978266Z","shell.execute_reply.started":"2023-06-20T04:22:27.690351Z","shell.execute_reply":"2023-06-20T04:22:42.975920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"row = df.loc[df.duration.idxmax()]\nmels = np.load(str((TRAIN_AUDIO_IMAGES_SAVE_ROOT/row.primary_label/row.filename).as_posix() + \".npy\"))\nprint(mels.shape)","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:42.979620Z","iopub.status.idle":"2023-06-20T04:22:42.980050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lbd.specshow(mels[0])","metadata":{"execution":{"iopub.status.busy":"2023-06-20T04:22:42.981164Z","iopub.status.idle":"2023-06-20T04:22:42.981532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}