{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":25954,"databundleVersionId":2091745,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\nPART_ID - Индекс в массиве PART_INDEXES.\nБудут подсчитываться спектрограммы для звуковых файлов с индексами из \nпромежутка PART_INDEXES[PART_ID]:PART_INDEXES[PART_ID+1]\n'''\nPART_ID = 0\nPART_INDEXES = [0, 15718, 31436, 47154, 62874]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SR = 32000 # Частота дискретизации звуковых файлов\nDURATION = 7 # Длительность сигнала в секундах\nSEED = 666 # число для формирования случайной величины\n\nDATA_ROOT = Path('/kaggle/input/birdclef-2021')\nAUDIO_ROOT = Path('/kaggle/input/birdclef-2021/train_short_audio')\nAUDIO_IMAGES_SAVE_ROOT = Path('audio_images') # Директория для сохранения спектрограмм\nAUDIO_IMAGES_SAVE_ROOT.mkdir(exist_ok=True, parents=True)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_audio_info(filepath):\n    \"\"\"Функция получения свойств звукового сигнала из аудиофайла.\"\"\"\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":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import display","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_df(n_splits=5, seed=SEED, nrows=None):\n    df = pd.read_csv(DATA_ROOT/'train_metadata.csv', nrows=nrows)\n    LABEL_IDS = {\n        label: label_id\n        for label_id, label in enumerate(sorted(df['primary_label'].unique()))\n    }\n    df = df.iloc[PART_INDEXES[PART_ID]: PART_INDEXES[PART_ID+1]]\n    df['label_id'] = df['primary_label'].map(LABEL_IDS)\n    df['filepath'] = [\n        str(AUDIO_ROOT/primary_label/filename) \n        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    df = df.reset_index(drop=True)\n    df = pd.concat([df, pd.DataFrame(pool(tqdm(tasks)))], axis=1, sort=False)\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    df['fold'] = -1\n\n    for fold, (train_set, val_set) in enumerate(splits):\n        df.loc[df.index[val_set], 'fold'] = fold\n\n    return LABEL_IDS, df","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"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":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\"fold\"].value_counts()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\"primary_label\"].value_counts()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\"duration\"].hist(bins=20)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\"duration\"].quantile(np.arange(0, 1, 0.01)).plot()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"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        melspec = lb.feature.melspectrogram(\n            y=y,\n            sr=self.sr,\n            n_mels=self.n_mels,\n            fmin=self.fmin,\n            fmax=self.fmax,\n            **self.kwargs,\n        )\n        melspec = lb.power_to_db(melspec).astype(np.float32)\n        return melspec","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"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    _min, _max = X.min(), X.max()\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_repeats = length // len(y)\n        epsilon = length % len(y)\n        y = np.concatenate([y]*n_repeats + [y[:epsilon]])\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":{"trusted":true},"outputs":[],"execution_count":null},{"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        self.sr = sr\n        self.n_mels = n_mels\n        self.fmin = fmin\n        self.fmax = fmax or self.sr // 2\n        self.duration = duration\n        self.audio_length = self.duration*self.sr\n        self.step = step or self.audio_length\n        self.res_type = res_type\n        self.resample = resample\n        self.mel_spec_computer = MelSpecComputer(\n            sr=self.sr, \n            n_mels=self.n_mels, \n            fmin=self.fmin,\n            fmax=self.fmax\n        )\n\n    def audio_to_image(self, audio):\n        melspec = self.mel_spec_computer(audio) \n        image = mono_to_color(melspec)\n        return image\n\n    def __call__(self, row, save=True):\n      audio, orig_sr = sf.read(row.filepath, dtype='float32')\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 = [\n          audio[i:i+self.audio_length]\n          for i in range(0, max(1, len(audio) - self.audio_length + 1), self.step)\n      ]\n      audios[-1] = crop_or_pad(audios[-1] , length=self.audio_length)\n      images = [\n          self.audio_to_image(audio)\n          for audio in audios\n      ]\n      images = np.stack(images)\n        \n      if save:\n        path = 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":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_audios_as_images(df):\n    pool = joblib.Parallel(2)\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    pool(tqdm(tasks))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"get_audios_as_images(df)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"row = df.loc[df.duration.idxmax()]\nmels = np.load(str((AUDIO_IMAGES_SAVE_ROOT/row.primary_label/row.filename).as_posix() + \".npy\"))\nprint(mels.shape)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lbd.specshow(mels[0])","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}