{"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":"# Сразу оговорюсь\n> В этом компетишене я использовала другие ноты, гитхаб, гугл, яндекс и arxiv.org\n","metadata":{}},{"cell_type":"markdown","source":"# Подготовка\n> Импорт всего что нужно и не очень. Загрузка данных, необходимые функции","metadata":{}},{"cell_type":"code","source":"# вспомогательные\nimport math, os, re, warnings, random \n# наша основаная библиотека\nimport tensorflow as tf \n# нампи без него никак\nimport numpy as np \n# пандас как и нампи \nimport pandas as pd \n# это библиотека загрузки и обработки звуков\nimport librosa\n# функции ввода-вывода тензорфлоу\nimport tensorflow.io \n# библиотека Каггла, она нам нужна чтобы получить пути до данных\nfrom kaggle_datasets import KaggleDatasets  \n# рисунки графики и красота\nimport matplotlib.pyplot as plt \n# ещё рисунки графики и красота для звуков\nfrom IPython.display import Audio \n# мы будем использовать керас\nfrom tensorflow.keras import Model, layers \n# будем разбивать данные на фолды\nfrom sklearn.model_selection import KFold \n#\nimport tensorflow.keras.backend as K # \n# колбэки для ранней остановки, промежуточных сохранений и контроля lr\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler \n# уровни нейросеть из кераса, которые нам понадобятся, как дополнительные скорее, в основном мы будем пользоваться ResNet50\nfrom tensorflow.keras.layers import GlobalAveragePooling2D, Input, Dense, Dropout, GaussianNoise\n# ResNet50 основная модель, которую мы будем использовать,\n# она хороша зарекомендовала себя для распознования изображений\n# у неё хорошая эффективность цена/качество\n# мы будем использовать её для распознавания звуков\n# в качестве функции потерь мы будем использовать кросс-энетропию\n# вообще мы могли попробовать создавать и свои модели\n# c учётом особенностей данных и наших требований, но времени нет на это\nfrom tensorflow.keras.applications import ResNet50\n# во многих решенных нотах на каггле используются efficientnet модели\n# но я не настолько хорошо их знаю, чтобы сейчас разбираться с ней ещё\n# import efficientnet.keras as efn\nimport seaborn as sns # это знаменитая библиотека для графиков, тепловых карт и т.д.","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.428201Z","iopub.execute_input":"2021-11-27T10:28:17.428499Z","iopub.status.idle":"2021-11-27T10:28:17.437178Z","shell.execute_reply.started":"2021-11-27T10:28:17.428472Z","shell.execute_reply":"2021-11-27T10:28:17.436179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# выводим версию текущей сборки TF\n# это скорее перестраховка, в данном случае\nprint(tf.__version__)","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.438868Z","iopub.execute_input":"2021-11-27T10:28:17.439103Z","iopub.status.idle":"2021-11-27T10:28:17.45675Z","shell.execute_reply.started":"2021-11-27T10:28:17.439077Z","shell.execute_reply":"2021-11-27T10:28:17.455791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# получаем данные истинно позитивной тренинговой выборки\n# есть ещё и ложно-позитивная, но я её не трогала, т.к. не знаю что с ней делать. \n#Из опыта музыкальных дисктантов и изучения ин. языков, я могу предположить, что она нужна \n#для лучшего распознавания схожих звуков, но не знаю, как это делать\ntraindf = pd.read_csv(r'../input/rfcx-species-audio-detection/train_tp.csv')\ntraindf.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.458004Z","iopub.execute_input":"2021-11-27T10:28:17.458569Z","iopub.status.idle":"2021-11-27T10:28:17.486508Z","shell.execute_reply.started":"2021-11-27T10:28:17.458534Z","shell.execute_reply":"2021-11-27T10:28:17.48562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"raw","source":"","metadata":{"execution":{"iopub.status.busy":"2021-11-25T21:02:51.182286Z","iopub.execute_input":"2021-11-25T21:02:51.182637Z","iopub.status.idle":"2021-11-25T21:02:51.213476Z","shell.execute_reply.started":"2021-11-25T21:02:51.182552Z","shell.execute_reply":"2021-11-25T21:02:51.212863Z"}}},{"cell_type":"code","source":"# функции получения фич формата tfrecords из значений\n# максимально стандартный код\n# он вроде бы родом из официального мануала даже\n\n# в этой функции мы получаем фичу с типом BytesList\ndef _bytes_feature(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    if isinstance(value, type(tf.constant(0))):\n        value = value.numpy() # BytesList won't unpack a string from an EagerTensor.\n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))\n\n# в этой функции мы получаем фичу с типом FloatList\ndef _float_feature(value):\n    \"\"\"Returns a float_list from a float / double.\"\"\"\n    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))\n\n# в этой функции мы сериализуем данные переданные в функцию\n# в строчку для будущей записи в файл формата tfrecords\n# каждая строка данных там иммет тип tf.train.Example так что делаем через неё\ndef serialize_example(wav, recording_id, target, song_id, tmin,fmin, tmax, fmax):\n    feature = {\n      'wav': _bytes_feature(wav),\n      'recording_id': _bytes_feature(recording_id),\n      'target': _float_feature(target),\n      'song_id': _float_feature(song_id),\n      'tmin': _float_feature(tmin),\n      'fmin' : _float_feature(fmin),\n      'tmax': _float_feature(tmax),\n      'fmax' : _float_feature(fmax),\n    }\n    example_proto = tf.train.Example(features=tf.train.Features(feature=feature))\n    \n    return example_proto.SerializeToString() \n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.488038Z","iopub.execute_input":"2021-11-27T10:28:17.48861Z","iopub.status.idle":"2021-11-27T10:28:17.497645Z","shell.execute_reply.started":"2021-11-27T10:28:17.488582Z","shell.execute_reply":"2021-11-27T10:28:17.497007Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import StratifiedKFold\n# здесь мы должны были создать новые файлики tfrecords\n# для тренировки нейросети, но не получилось\n# проблема в том, что TPU может читать данные только из input\n# а прямого доступа к input нет\n# по умолчанию файлики создаются в папке output\n# по этому я сделала отдельный ноте, который создал файлики для тренировки\n# и подключили результаты его выполнения, как исходные(input) для этого ноте\n# и так сработало :)\n\n\n# tfrec_num = 0\n# kfold = StratifiedKFold(n_splits=10, shuffle=False)\n# for fold, (train_idx, test_idx) in enumerate(kfold.split(traindf['recording_id'], traindf['species_id'])):\n#     x_train , y_train = traindf['recording_id'][test_idx] , traindf['species_id'][test_idx]\n   \n#     with tf.io.TFRecordWriter('tp%.2i-%.2i.tfrec'%(tfrec_num, len(test_idx))) as writer:\n#         print('Writing_tfrecords ',fold)\n#         for recording_id , true_value in zip(x_train, y_train): \n#             wav, _ = librosa.load(f'../input/rfcx-species-audio-detection/train/{recording_id}.flac', sr = None)\n#             label_info = traindf.loc[traindf['recording_id'] == str(recording_id)].values[0]\n#             wav = tf.audio.encode_wav(tf.reshape(wav,(wav.shape[0], 1)) ,sample_rate = 48000)\n#             recording_id = label_info[0].encode()\n#             target = label_info[1]\n#             song_id = label_info[2]\n#             tmin = label_info[3]\n#             fmin = label_info[4]\n#             tmax = label_info[5]\n#             fmax = label_info[6]\n#             example = serialize_example(wav, recording_id, target, song_id, tmin,fmin, tmax, fmax)\n#             writer.write(example)\n#     tfrec_num += 1\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.498905Z","iopub.execute_input":"2021-11-27T10:28:17.49961Z","iopub.status.idle":"2021-11-27T10:28:17.514813Z","shell.execute_reply.started":"2021-11-27T10:28:17.499568Z","shell.execute_reply":"2021-11-27T10:28:17.513894Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# максимально стандартный код для всех блокнотов на Каггле\n# мы подключаем TPU или distribute стратегию в зависимости от доступности\n# distribute может работать как с GPU так и с CPU \n\n# TPU or GPU detection\n# Detect hardware, return appropriate distribution strategy\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print(f'Running on TPU {tpu.master()}')\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy()\n\nAUTO = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:17.536385Z","iopub.execute_input":"2021-11-27T10:28:17.536809Z","iopub.status.idle":"2021-11-27T10:28:25.649768Z","shell.execute_reply.started":"2021-11-27T10:28:17.536781Z","shell.execute_reply":"2021-11-27T10:28:25.6489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# здесь мы получаем список файлов с путями для нужных нам данных\n# в данном случае frog-song-data - это то что мы расчитали\n# в другом блокноте для тренинговых данных\nTRAIN_DATA_DIR = 'frog-song-data'\nTRAIN_GCS_PATH =  KaggleDatasets().get_gcs_path(TRAIN_DATA_DIR)\nFILENAMES = tf.io.gfile.glob(TRAIN_GCS_PATH + '/tp*.tfrec')","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:25.651376Z","iopub.execute_input":"2021-11-27T10:28:25.651613Z","iopub.status.idle":"2021-11-27T10:28:45.72169Z","shell.execute_reply.started":"2021-11-27T10:28:25.651586Z","shell.execute_reply":"2021-11-27T10:28:45.719809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#а это наши тетсовые данные, они загружаются как и предыдущие\nTEST_DATA_DIR = 'rfcx-species-audio-detection'\nTEST_GCS_PATH =  KaggleDatasets().get_gcs_path(TEST_DATA_DIR)\nTEST_FILES = tf.io.gfile.glob(TEST_GCS_PATH + '/tfrecords/test/*.tfrec')","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:45.72318Z","iopub.execute_input":"2021-11-27T10:28:45.723433Z","iopub.status.idle":"2021-11-27T10:28:46.282522Z","shell.execute_reply.started":"2021-11-27T10:28:45.723407Z","shell.execute_reply":"2021-11-27T10:28:46.281606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# последний номер в имени сгенерированного файла означает номер семпла\n# мы считаем число семплов через число файлов\n# не очень красивый ход... но рабочий\nn = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in FILENAMES]\nprint(f\"Total number of rows :{np.sum(n)}\")\nno_of_training_samples=np.sum(n)","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.284592Z","iopub.execute_input":"2021-11-27T10:28:46.28493Z","iopub.status.idle":"2021-11-27T10:28:46.292045Z","shell.execute_reply.started":"2021-11-27T10:28:46.284887Z","shell.execute_reply":"2021-11-27T10:28:46.290962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# устанавливаем парметры наших скриптов\nCUT = 10\n# окно в сек. для всех дорожек\nTIME = 10\n# число эпох\nEPOCHS = 25\n# размер батча\nGLOBAL_BATCH_SIZE = 4 * REPLICAS\n# шаг оптимизатора базовый(он будет меняться)\nLEARNING_RATE = 0.0015\n# параметр отжига(перегрева) функция колбэк, которая будет менять на lr \nWARMUP_LEARNING_RATE = 1e-5\n# параметр отжига(перегрева) функция колбэк, число эпох где lr может расти\nWARMUP_EPOCHS = int(EPOCHS*0.1)\nPATIENCE = 8\n# за сколько шагов загружаем данные в TPU\nSTEPS_PER_EPOCH = 64\n#Количество фолдов, по которым будем обучать\nN_FOLDS = 5\nNUM_TRAINING_SAMPLES = no_of_training_samples","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.294298Z","iopub.execute_input":"2021-11-27T10:28:46.294565Z","iopub.status.idle":"2021-11-27T10:28:46.31204Z","shell.execute_reply.started":"2021-11-27T10:28:46.294534Z","shell.execute_reply":"2021-11-27T10:28:46.311215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ещё параметры\n# это параметры спектрограммы, мы будем вытаскивать дополнительную информацию\n# из звука для его распознования и это как бы основная задача и проблема\n# именно здесь будут запрятаны основные не однозначности и непонятности\nclass params:\n    # это число байт в секунду для нашей аудио записи\n    sample_rate = 48000\n    # это размер окна раскладываемое в Фурье в секундах\n    stft_window_seconds: float = 0.025\n    stft_hop_seconds: float = 0.005\n    # длинна окна в байтах = sample_rate * stft_window_seconds\n    frame_length: int =  1200    \n    # мелы - как хорошо, что я ходила в музыкалку в детстве\n    # но даже это не всегда спасает :)\n    # мелы - это величина в музыки, она логарифмически связана с частотой\n    mel_bands: int = 512\n    mel_min_hz: float = 50.0\n    mel_max_hz: float = 24000.0\n    log_offset: float = 0.001\n    patch_window_seconds: float = 0.96\n    patch_hop_seconds: float = 0.48\n\n  \n    patch_frames =  int(round(patch_window_seconds / stft_hop_seconds))\n\n  \n    patch_bands = mel_bands\n    height = mel_bands\n    width = 2000\n    # число классов для классификации\n    num_classes: int = 24\n    # защита от оверифитинга, но это не самые главный способ в нашем случае\n    # добавление уровня dropout для \"забывания\" старых нейронных связей\n    # это хорошо\n    # но главное, это слой GaussianNoise\n    # он добавляет шум нормального распределения к данным input\n    # это позволяет нам НЕ обучать нашу модель на шуме\n    # который бы иначе повторялся на каждой эпохе\n    dropout = 0.35\n    #вообще должен быть softmax, но почему-то sigmoid работает лучше, пока не понимаю\n    classifier_activation: str = 'sigmoid'","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.31347Z","iopub.execute_input":"2021-11-27T10:28:46.314398Z","iopub.status.idle":"2021-11-27T10:28:46.326178Z","shell.execute_reply.started":"2021-11-27T10:28:46.314358Z","shell.execute_reply":"2021-11-27T10:28:46.325298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# описываем фичи в экзамплах(стрчоках) это нужно, чтобы позже с ними работать\nclassifier_activation: str = 'sigmoid'\nfeature_description = {\n    'wav': tf.io.FixedLenFeature([], tf.string),\n    'recording_id': tf.io.FixedLenFeature([], tf.string ),\n    'target' : tf.io.FixedLenFeature([], tf.float32),\n    'song_id': tf.io.FixedLenFeature([], tf.float32),\n     'tmin' : tf.io.FixedLenFeature([], tf.float32),\n     'fmin' : tf.io.FixedLenFeature([], tf.float32),\n     'tmax' : tf.io.FixedLenFeature([], tf.float32),\n     'fmax' : tf.io.FixedLenFeature([], tf.float32),\n}\nfeature_dtype = {\n    'wav': tf.float32,\n    'recording_id': tf.string,\n    'target': tf.float32,\n    'song_id': tf.float32,\n    't_min': tf.float32,\n    'f_min': tf.float32,\n    't_max': tf.float32,\n    'f_max':tf.float32,\n}","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.327927Z","iopub.execute_input":"2021-11-27T10:28:46.328308Z","iopub.status.idle":"2021-11-27T10:28:46.343885Z","shell.execute_reply.started":"2021-11-27T10:28:46.328241Z","shell.execute_reply":"2021-11-27T10:28:46.343147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Обработка и подготовка данных\n> Получение дополнительной информации из звука (спектограммы, мелограммы). Сворачивание данных(спектограммы, мелограммы) в прямоугольные тензоры для обработки как картинок","metadata":{}},{"cell_type":"code","source":"# функция преобразования сырого звука в спектрограмму\n# но наша спекторграмма будет не по Гц, а по мелам\ndef waveform_to_log_mel_spectrogram(waveform,target_or_rec_id):\n    \"\"\"Compute log mel spectrogram patches of a 1-D waveform.\"\"\"\n    # я решила оставить оригинальные коментарии\n    # waveform has shape [<# samples>]\n\n    # Convert waveform into spectrogram using a Short-Time Fourier Transform.\n    # Note that tf.signal.stft() uses a periodic Hann window by default.\n    \n    # Получаем параметры окна для передачи данных в tf.signal.stft\n    # для получения спектограммы мощности звука от Гц пока в Герцах\n    window_length_samples = int(round(params.sample_rate * params.stft_window_seconds))\n    hop_length_samples = int(round(params.sample_rate * params.stft_hop_seconds))\n    fft_length = 2 ** int(np.ceil(np.log(window_length_samples) / np.log(2.0)))\n    num_spectrogram_bins = fft_length // 2 + 1\n    # передаём параметры и получаем спектрограмму (Герцы)\n    spectogram=tf.signal.stft(signals=waveform,frame_length=params.frame_length,frame_step=hop_length_samples,fft_length= fft_length)\n    magnitude_spectrogram = tf.abs(spectogram)\n    # magnitude_spectrogram has shape [<# STFT frames>, num_spectrogram_bins]\n\n    # Convert spectrogram into log mel spectrogram\n    # теперь конвертируем спектограмму из Герц в мелы\n    linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix(\n        num_mel_bins=params.mel_bands,\n        num_spectrogram_bins=num_spectrogram_bins,\n        sample_rate=params.sample_rate,\n        lower_edge_hertz=params.mel_min_hz,\n        upper_edge_hertz=params.mel_max_hz)\n    \n    mel_spectrogram = tf.matmul(magnitude_spectrogram, linear_to_mel_weight_matrix)\n    \n    log_mel = tf.math.log(mel_spectrogram + params.log_offset)\n    log_mel = tf.transpose(log_mel)\n    log_mel_spectrogram = tf.reshape(log_mel , [tf.shape(log_mel)[0] ,tf.shape(log_mel)[1],1])  \n    # ура, теперь у нас есть спектограмма в мелах\n    # важно заметить, что все операции по конвертации мы делали при помощи функций TF\n    # а это значит, что при компилляции будет сохранен граф взаимосвязи этих функций нативно\n    # т.е. все эти операции будут преобразованы в тензорные преобразования TF\n    # что очень важно, т.к. операции тензорных преобразований будут неразрывны загружаться в TPU\\GPU\n    # сейчас для нас это может и не иметь какого-то дикого эффекта, но при работе модели в проде\n    # это скажется очень сильно в т.ч.и на неочевидном её поведении\n    # надо стараться не выходить за пределы функций TF\n    # даже в преобразовании данных =)\n    \n    # Frame spectrogram (shape [<# STFT frames>, params.mel_bands]) into patches\n    # (the input examples). Only complete frames are emitted, so if there is\n    # less than params.patch_window_seconds of waveform then nothing is emitted\n    # (to avoid this, zero-pad before processing).\n    spectrogram_hop_length_samples = int(round(params.sample_rate * params.stft_hop_seconds))\n    spectrogram_sample_rate = params.sample_rate / spectrogram_hop_length_samples\n    patch_window_length_samples = int(round(spectrogram_sample_rate * params.patch_window_seconds))\n    patch_hop_length_samples = int(round(spectrogram_sample_rate * params.patch_hop_seconds))\n    features = tf.signal.frame(signal=log_mel_spectrogram,frame_length=patch_window_length_samples,frame_step=patch_hop_length_samples,axis=0)\n    # features has shape [<# patches>, <# STFT frames in an patch>, params.mel_bands]\n    return log_mel_spectrogram, target_or_rec_id","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.345572Z","iopub.execute_input":"2021-11-27T10:28:46.345806Z","iopub.status.idle":"2021-11-27T10:28:46.363917Z","shell.execute_reply.started":"2021-11-27T10:28:46.34578Z","shell.execute_reply":"2021-11-27T10:28:46.362829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Это все изменение изображений для того, чтобы увеличить нашу выбоку, количество данных\n# чтобы модель лучше обучалась, лучше распознавая картинки спектограммы\n\ndef frequency_masking(mel_spectrogram):\n    \n    frequency_masking_para = 80, \n    frequency_mask_num = 2\n    \n    fbank_size = tf.shape(mel_spectrogram)\n#     print(fbank_size)\n    n, v = fbank_size[0], fbank_size[1]\n\n    for i in range(frequency_mask_num):\n        f = tf.random.uniform([], minval=0, maxval= tf.squeeze(frequency_masking_para), dtype=tf.int32)\n        v = tf.cast(v, dtype=tf.int32)\n        f0 = tf.random.uniform([], minval=0, maxval= tf.squeeze(v-f), dtype=tf.int32)\n\n        # warped_mel_spectrogram[f0:f0 + f, :] = 0\n        mask = tf.concat((tf.ones(shape=(n, v - f0 - f,1)),\n                          tf.zeros(shape=(n, f,1)),\n                          tf.ones(shape=(n, f0,1)),\n                          ),1)\n        mel_spectrogram = mel_spectrogram * mask\n    return tf.cast(mel_spectrogram, dtype=tf.float32)\n\n\ndef time_masking(mel_spectrogram):\n    time_masking_para = 40, \n    time_mask_num = 1\n    \n    fbank_size = tf.shape(mel_spectrogram)\n    n, v = fbank_size[0], fbank_size[1]\n\n   \n    for i in range(time_mask_num):\n        t = tf.random.uniform([], minval=0, maxval=tf.squeeze(time_masking_para), dtype=tf.int32)\n        t0 = tf.random.uniform([], minval=0, maxval= n-t, dtype=tf.int32)\n\n        # mel_spectrogram[:, t0:t0 + t] = 0\n        mask = tf.concat((tf.ones(shape=(n-t0-t, v,1)),\n                          tf.zeros(shape=(t, v,1)),\n                          tf.ones(shape=(t0, v,1)),\n                          ), 0)\n        \n        mel_spectrogram = mel_spectrogram * mask\n    return tf.cast(mel_spectrogram, dtype=tf.float32)\n\n\n\ndef random_brightness(image):\n    return tf.image.random_brightness(image, 0.2)\n\ndef random_gamma(image):\n    return tf.image.random_contrast(image, lower = 0.1, upper = 0.3)\n\ndef random_flip_right(image):\n    return tf.image.random_flip_left_right(image)\n\ndef random_flip_up_down(image):\n    return tf.image.random_flip_left_right(image)\n\navailable_ops = [\n          frequency_masking ,\n          time_masking, \n          random_brightness, \n          random_flip_up_down,\n          random_flip_right \n         ]\n\n#выбираем от нуля до трех преобразований\ndef apply_augmentation(image, target):\n    num_layers = int(np.random.uniform(low = 0, high = 3))\n    \n    for layer_num in range(num_layers):\n        op_to_select = tf.random.uniform([], maxval=len(available_ops), dtype=tf.int32, seed = seed)\n        for (i, op_name) in enumerate(available_ops):\n            image = tf.cond(\n            tf.equal(i, op_to_select),\n            lambda selected_func=op_name,: selected_func(\n                image),\n            lambda: image)\n    return image, target","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.365526Z","iopub.execute_input":"2021-11-27T10:28:46.36593Z","iopub.status.idle":"2021-11-27T10:28:46.387923Z","shell.execute_reply.started":"2021-11-27T10:28:46.365803Z","shell.execute_reply":"2021-11-27T10:28:46.38689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# преобразуем в картинку для распознавания\ndef preprocess(image, target_or_rec_id):\n    \n    image = tf.image.grayscale_to_rgb(image)\n    image = tf.image.resize(image, [params.height,params.width])\n    image = tf.image.per_image_standardization(image)\n    return image , target_or_rec_id\n\n# мы обрезаем наши wav (кодированные записи) по нашим доп параметра tmin max, fmin max и возвращаем \n# и возвращаем только данные, содержащие закодированный wav  и target\ndef read_labeled_tfrecord(example_proto):\n    # Обратно разделяем строчки на столбцы\n    sample = tf.io.parse_single_example(example_proto, feature_description)\n    wav, _ = tf.audio.decode_wav(sample['wav'], desired_channels=1) # mono\n    # каст гарантирует, что будет тип float\n    target = tf.cast(sample['target'],tf.float32)\n    #делаем матрицу классов, как процедура дамми переменных, только с тензорными операциями\n    target = tf.squeeze(tf.one_hot([target,], depth = params.num_classes), axis = 0)\n    \n    tmin = tf.cast(sample['tmin'], tf.float32)\n    fmin = tf.cast(sample['fmin'], tf.float32)\n    tmax = tf.cast(sample['tmax'], tf.float32)\n    fmax = tf.cast(sample['fmax'], tf.float32)\n    # Макс и мин получаем в байтах\n    tmax_s = tmax * tf.cast(params.sample_rate, tf.float32)\n    tmin_s = tmin * tf.cast(params.sample_rate, tf.float32)\n    # считаем байты\n    cut_s = tf.cast(CUT * params.sample_rate, tf.float32)\n    all_s = tf.cast(60 * params.sample_rate, tf.float32)\n    tsize_s = tmax_s - tmin_s\n    #сколько надо отрезать слева\n    cut_min = tf.cast(\n    tf.maximum(0.0, \n        tf.minimum(tmin_s - (cut_s - tsize_s) / 2,\n                   tf.minimum(tmax_s + (cut_s - tsize_s) / 2, all_s) - cut_s)\n    ), tf.int32\n      )\n    #сколько надо отрезать справа\n    cut_max = cut_min + CUT * params.sample_rate\n    wav = tf.squeeze(wav[cut_min : cut_max] )\n    \n    return wav, target\n\n# Это функция для загрузки тестовых данных\ndef read_unlabeled_tfrecord(example):\n    feature_description = {\n    'recording_id': tf.io.FixedLenFeature([], tf.string),\n    'audio_wav': tf.io.FixedLenFeature([], tf.string),\n    }\n    sample = tf.io.parse_single_example(example, feature_description)\n    wav, _ = tf.audio.decode_wav(sample['audio_wav'], desired_channels=1) # mono\n    recording_id = tf.reshape(tf.cast(sample['recording_id'] , tf.string), [1])\n#     wav = tf.squeeze(wav)\n\n# Обрезаем тестовое аудио\n    def _cut_audio(i):\n        _sample = {\n            'audio_wav': tf.reshape(wav[i*params.sample_rate*TIME:(i+1)*params.sample_rate*TIME], [params.sample_rate*TIME]),\n            'recording_id': sample['recording_id']\n        }\n        return _sample\n\n    return tf.map_fn(_cut_audio, tf.range(60//TIME), dtype={\n        'audio_wav': tf.float32,\n        'recording_id': tf.string\n    })","metadata":{"execution":{"iopub.status.busy":"2021-11-27T13:37:49.779666Z","iopub.execute_input":"2021-11-27T13:37:49.781186Z","iopub.status.idle":"2021-11-27T13:37:49.841541Z","shell.execute_reply.started":"2021-11-27T13:37:49.780965Z","shell.execute_reply":"2021-11-27T13:37:49.840488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# это функция загрузки данных по массиву файлов из tfrecords\ndef load_dataset(filenames, labeled = True, ordered = False , training = True):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # Diregarding data order. Order does not matter since we will be shuffling the data anyway\n    ignore_order = tf.data.Options()\n    if not ordered:\n        # disable order, increase speed\n        ignore_order.experimental_deterministic = False\n        \n#     GCS_PATH = KaggleDatasets().get_gcs_path('audio-note-generated')\n#     print(\"GCS_PATH: \"+GCS_PATH)\n    # automatically interleaves reads from multiple files\n    \n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads = AUTO )\n    # use data as soon as it streams in, rather than in its original order\n    # Возвращаем черем map ко всем значениям датасета функцию и возвращаем результаты выполнения\n    # Возвращвется wav и target\n    dataset = dataset.map(read_labeled_tfrecord , num_parallel_calls = AUTO )\n    #превращаем в мел спектограмму\n    dataset = dataset.map(waveform_to_log_mel_spectrogram , num_parallel_calls = AUTO)   \n    if training:\n        # применяем орментацию (портим данные) для лувчшего качества\n        dataset = dataset.map(apply_augmentation, num_parallel_calls = AUTO)\n        # делаем картинку\n    dataset = dataset.map(preprocess, num_parallel_calls = AUTO)\n    return dataset\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.410702Z","iopub.execute_input":"2021-11-27T10:28:46.411237Z","iopub.status.idle":"2021-11-27T10:28:46.427413Z","shell.execute_reply.started":"2021-11-27T10:28:46.411201Z","shell.execute_reply":"2021-11-27T10:28:46.42672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# обертка для функции выше с разбитием на батчи, чтобы загрузить в TPU\ndef get_dataset(filenames, training = True):\n    if training:\n        dataset = load_dataset(filenames , training = True)\n        dataset = dataset.shuffle(256).repeat()\n        dataset = dataset.batch(GLOBAL_BATCH_SIZE, drop_remainder = True)\n    else:\n        dataset = load_dataset(filenames , training = False)\n        dataset = dataset.batch(GLOBAL_BATCH_SIZE).cache()\n    \n    dataset = dataset.prefetch(AUTO)\n    return dataset\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.428544Z","iopub.execute_input":"2021-11-27T10:28:46.429239Z","iopub.status.idle":"2021-11-27T10:28:46.444045Z","shell.execute_reply.started":"2021-11-27T10:28:46.429188Z","shell.execute_reply":"2021-11-27T10:28:46.442853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# стандартная функция установки ядер случайных величин, чтобы случайные величины всегды были одинаковыми\ndef seed_everything(seed=0):\n    random.seed(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\n\nseed = 123\nseed_everything(seed)\nwarnings.filterwarnings('ignore')\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.445494Z","iopub.execute_input":"2021-11-27T10:28:46.446036Z","iopub.status.idle":"2021-11-27T10:28:46.456778Z","shell.execute_reply.started":"2021-11-27T10:28:46.445998Z","shell.execute_reply":"2021-11-27T10:28:46.456061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# это я чисто тестила, у меня эта функция заработала не сразу, мягко говоря\ntrain_dataset = get_dataset(FILENAMES, training = True)\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:46.460293Z","iopub.execute_input":"2021-11-27T10:28:46.460783Z","iopub.status.idle":"2021-11-27T10:28:48.209752Z","shell.execute_reply.started":"2021-11-27T10:28:46.460747Z","shell.execute_reply":"2021-11-27T10:28:48.209012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Определение метрики и колбэка для всего","metadata":{}},{"cell_type":"code","source":"# здесь мы создаём метрику для нашей модели(не ошибку), просто метрику\n# она сделана по описанию компетишина, такой она применяется при выборе места участника\n# чем эта метрика выше, тем лучше место, максимум = 1 и минимум = 0\n# однако её алгоритм не обычен для меня, я не уверена, что она прямо удовлетворяет\n# условиям метрики \ndef _one_sample_positive_class_precisions(example):\n    y_true, y_pred = example\n    y_true = tf.reshape(y_true, tf.shape(y_pred))\n    retrieved_classes = tf.argsort(y_pred, direction='DESCENDING')\n#     shape = tf.shape(retrieved_classes)\n    class_rankings = tf.argsort(retrieved_classes)\n    retrieved_class_true = tf.gather(y_true, retrieved_classes)\n    retrieved_cumulative_hits = tf.math.cumsum(tf.cast(retrieved_class_true, tf.float32))\n\n    idx = tf.where(y_true)[:, 0]\n    i = tf.boolean_mask(class_rankings, y_true)\n    r = tf.gather(retrieved_cumulative_hits, i)\n    c = 1 + tf.cast(i, tf.float32)\n    precisions = r / c\n\n    dense = tf.scatter_nd(idx[:, None], precisions, [y_pred.shape[0]])\n    return dense\n\n# @tf.function\nclass LWLRAP(tf.keras.metrics.Metric):\n    def __init__(self, num_classes, name='lwlrap'):\n        super().__init__(name=name)\n\n        self._precisions = self.add_weight(\n            name='per_class_cumulative_precision',\n            shape=[num_classes],\n            initializer='zeros',\n        )\n\n        self._counts = self.add_weight(\n            name='per_class_cumulative_count',\n            shape=[num_classes],\n            initializer='zeros',\n        )\n\n    def update_state(self, y_true, y_pred, sample_weight=None):\n        precisions = tf.map_fn(\n            fn=_one_sample_positive_class_precisions,\n            elems=(y_true, y_pred),\n            dtype=(tf.float32),\n        )\n\n        increments = tf.cast(precisions > 0, tf.float32)\n        total_increments = tf.reduce_sum(increments, axis=0)\n        total_precisions = tf.reduce_sum(precisions, axis=0)\n\n        self._precisions.assign_add(total_precisions)\n        self._counts.assign_add(total_increments)        \n\n    def result(self):\n        per_class_lwlrap = self._precisions / tf.maximum(self._counts, 1.0)\n        per_class_weight = self._counts / tf.reduce_sum(self._counts)\n        overall_lwlrap = tf.reduce_sum(per_class_lwlrap * per_class_weight)\n        return overall_lwlrap\n\n    def reset_states(self):\n        self._precisions.assign(self._precisions * 0)\n        self._counts.assign(self._counts * 0)\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:48.211567Z","iopub.execute_input":"2021-11-27T10:28:48.212051Z","iopub.status.idle":"2021-11-27T10:28:48.229639Z","shell.execute_reply.started":"2021-11-27T10:28:48.211996Z","shell.execute_reply":"2021-11-27T10:28:48.228718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"https://github.com/Tony607/Keras_Bag_of_Tricks/blob/master/warmup_cosine_decay_scheduler.py\n\nhttps://arxiv.org/abs/1608.03983","metadata":{}},{"cell_type":"code","source":"# это хак из Keras_Bag_of_Tricks помогает контролировать lr\n# вроде бы это должно приводить к лучшей сходимости\n# в начале мы позволяем lr росте до warmup_steps\n# а после lr падает причём в соответствии с куском синусоиды\n# ниже будет график с примером\ndef cosine_decay_with_warmup(global_step,\n                             learning_rate_base,\n                             total_steps,\n                             warmup_learning_rate=0.0,\n                             warmup_steps= 0,\n                             hold_base_rate_steps=0):\n \n    if total_steps < warmup_steps:\n        raise ValueError('total_steps must be larger or equal to '\n                     'warmup_steps.')\n    learning_rate = 0.5 * learning_rate_base * (1 + tf.cos(\n        np.pi *\n        (tf.cast(global_step, tf.float32) - warmup_steps - hold_base_rate_steps\n        ) / float(total_steps - warmup_steps - hold_base_rate_steps)))\n    if hold_base_rate_steps > 0:\n        learning_rate = tf.where(\n          global_step > warmup_steps + hold_base_rate_steps,\n          learning_rate, learning_rate_base)\n    if warmup_steps > 0:\n        if learning_rate_base < warmup_learning_rate:\n            raise ValueError('learning_rate_base must be larger or equal to '\n                         'warmup_learning_rate.')\n        slope = (learning_rate_base - warmup_learning_rate) / warmup_steps\n        warmup_rate = slope * tf.cast(global_step,\n                                    tf.float32) + warmup_learning_rate\n        learning_rate = tf.where(global_step < warmup_steps, warmup_rate,\n                               learning_rate)\n    return tf.where(global_step > total_steps, 0.0, learning_rate,\n                    name='learning_rate')\n\n\n#dummy example\nrng = [i for i in range(int(EPOCHS * STEPS_PER_EPOCH))]\nWARMUP_STEPS =  int(WARMUP_EPOCHS * STEPS_PER_EPOCH)\ny = [cosine_decay_with_warmup(x , LEARNING_RATE, len(rng), 1e-5, WARMUP_STEPS) for x in rng]\n\nsns.set(style='whitegrid')\nfig, ax = plt.subplots(figsize=(20, 6))\nplt.plot(rng, y)\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:48.231188Z","iopub.execute_input":"2021-11-27T10:28:48.231509Z","iopub.status.idle":"2021-11-27T10:28:56.265858Z","shell.execute_reply.started":"2021-11-27T10:28:48.231472Z","shell.execute_reply":"2021-11-27T10:28:56.265033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# to apply learning rate schedule stepwise we need to subclass keras callback\n# if we would have applied lr schedule epoch wise then it is not needed we can only call class learningrateschedule \n# это callback обертка над функцией выше, она нужна, чтобы керас съел это как callback\nclass WarmUpCosineDecayScheduler(tf.keras.callbacks.Callback):\n\n    def __init__(self,\n                 learning_rate_base,\n                 total_steps,\n                 global_step_init=0,\n                 warmup_learning_rate=0.0,\n                 warmup_steps=0,\n                 hold_base_rate_steps=0,\n                 verbose=0):\n\n        super(WarmUpCosineDecayScheduler, self).__init__()\n        self.learning_rate_base = learning_rate_base\n        self.total_steps = total_steps\n        self.global_step = global_step_init\n        self.warmup_learning_rate = warmup_learning_rate\n        self.warmup_steps = warmup_steps\n        self.hold_base_rate_steps = hold_base_rate_steps\n        self.verbose = verbose\n        self.learning_rates = []\n\n    def on_batch_end(self, batch, logs=None):\n        self.global_step = self.global_step + 1\n        lr = K.get_value(self.model.optimizer.lr)\n        self.learning_rates.append(lr)\n\n    def on_batch_begin(self, batch, logs=None):\n        lr = cosine_decay_with_warmup(global_step=self.global_step,\n                                      learning_rate_base=self.learning_rate_base,\n                                      total_steps=self.total_steps,\n                                      warmup_learning_rate=self.warmup_learning_rate,\n                                      warmup_steps=self.warmup_steps,\n                                      hold_base_rate_steps=self.hold_base_rate_steps)\n        K.set_value(self.model.optimizer.lr, lr)\n        if self.verbose > 0:\n            print('\\nBatch %05d: setting learning '\n                  'rate to %s.' % (self.global_step + 1, lr.numpy()))\n            \n\ntotal_steps = int(EPOCHS * STEPS_PER_EPOCH)\n# Compute the number of warmup batches or steps.\nwarmup_steps = int(WARMUP_EPOCHS * STEPS_PER_EPOCH)\nwarmup_learning_rate = WARMUP_LEARNING_RATE\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:56.267354Z","iopub.execute_input":"2021-11-27T10:28:56.267673Z","iopub.status.idle":"2021-11-27T10:28:56.27927Z","shell.execute_reply.started":"2021-11-27T10:28:56.267631Z","shell.execute_reply":"2021-11-27T10:28:56.27864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#А это собственно наша модель \ndef ResNet50_MODEL():\n    waveform = Input(shape=(None,None,3), dtype=tf.float32)\n    noisy_waveform = GaussianNoise(0.2)(waveform)\n    model = ResNet50(include_top=False, weights='imagenet',) \n    model_output = model(noisy_waveform)\n    model_output = GlobalAveragePooling2D()(model_output)\n    dense = Dropout(params.dropout)(model_output)\n    predictions = Dense(params.num_classes, activation = params.classifier_activation )(dense)\n    model = Model(\n      name='ResNet50', inputs=waveform,\n      outputs=[predictions])\n    return model\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:56.280276Z","iopub.execute_input":"2021-11-27T10:28:56.280981Z","iopub.status.idle":"2021-11-27T10:28:56.295246Z","shell.execute_reply.started":"2021-11-27T10:28:56.280942Z","shell.execute_reply":"2021-11-27T10:28:56.294395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# создаем модель и компилируем с оптимизатором\n# бинарной кросэнтропией как функцией потерь\n# бинарная кросэтропия выбрана потому что у нас простая класификация\n# для каждого из классов есть только два возможных варианта\n# либо звук принадлежит этому классу, либо нет\n# и метрикой компетишена LWLRAP\ndef get_model():\n    with strategy.scope():\n        model = ResNet50_MODEL()\n        model.summary()\n        model.compile(optimizer = 'adam',\n                                loss = tf.keras.losses.BinaryCrossentropy(label_smoothing = 0.1),\n                                metrics = [LWLRAP(num_classes = params.num_classes),\n                                ])\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:56.296812Z","iopub.execute_input":"2021-11-27T10:28:56.297405Z","iopub.status.idle":"2021-11-27T10:28:56.31121Z","shell.execute_reply.started":"2021-11-27T10:28:56.297368Z","shell.execute_reply":"2021-11-27T10:28:56.310307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nskf = KFold(n_splits=N_FOLDS, shuffle=True, random_state=seed)\noof_pred = []; oof_labels = []; history_list = []\n\nfor fold,(idxT, idxV) in enumerate(skf.split(np.arange(10))):\n    if tpu: tf.tpu.experimental.initialize_tpu_system(tpu)\n    print(f'\\nFOLD: {fold+1}')\n    print(f'TRAIN: {idxT} VALID: {idxV}')\n\n    # Create train and validation sets\n    TRAIN_FILENAMES = [FILENAMES[x] for x in idxT]\n    VALID_FILENAMES = [FILENAMES[x] for x in idxV]\n    np.random.shuffle(TRAIN_FILENAMES)\n    \n    train_dataset =  get_dataset(TRAIN_FILENAMES, training=True,)\n    validation_data= get_dataset(VALID_FILENAMES, training=False) \n    model = get_model()\n\n    model_path = f'RFCX_model_fold {fold}.h5'\n    early_stopping = EarlyStopping(monitor = 'val_lwlrap', mode = 'max', \n                       patience = PATIENCE, restore_best_weights=True, verbose=1)\n\n    # Create the Learning rate scheduler.\n    cosine_warm_up_lr = WarmUpCosineDecayScheduler(learning_rate_base= LEARNING_RATE,\n                                    total_steps= total_steps,\n                                    warmup_learning_rate= warmup_learning_rate,\n                                    warmup_steps= warmup_steps,\n                                    hold_base_rate_steps=0)\n\n    ## TRAIN\n    history = model.fit(train_dataset, \n                        steps_per_epoch=STEPS_PER_EPOCH, \n                        callbacks=[early_stopping, cosine_warm_up_lr], \n                        epochs=EPOCHS,  \n                        validation_data = validation_data,\n                        verbose = 2).history\n\n    history_list.append(history)\n    # Save last model weights\n    model.save_weights(model_path)\n\n# OOF predictions\n#     ds_valid = get_dataset(VALID_FILENAMES, training = False)\n#     oof_labels.append([target.numpy() for frame, target in iter(ds_valid.unbatch())])\n#     x_oof = ds_valid.map(lambda frames, target: frames)\n#     oof_pred.append(np.argmax(model.predict(x_oof), axis=-1))\n\n    ## RESULTS\n#     print(f\"#### FOLD {fold+1} OOF Accuracy = {np.max(history['val_lwlrap']):.3f}\")\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T10:28:56.312595Z","iopub.execute_input":"2021-11-27T10:28:56.313337Z","iopub.status.idle":"2021-11-27T11:21:26.69533Z","shell.execute_reply.started":"2021-11-27T10:28:56.313293Z","shell.execute_reply":"2021-11-27T11:21:26.694435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def plot_history(history):\n#     plt.figure(figsize=(8,3))\n#     plt.subplot(1,2,1)\n#     plt.plot(history[\"loss\"])\n#     plt.plot(history[\"val_loss\"])\n#     plt.legend(['Train', 'Test'], loc='upper left')\n#     plt.title(\"loss\")\n\n#     plt.subplot(1,2,2)\n#     plt.plot(history[\"lwlrap\"])\n#     plt.plot(history[\"val_lwlrap\"])\n#     plt.legend(['Train', 'Test'], loc='upper left')\n#     plt.title(\"lwlrap\")\n    \n# for hist in history_list:\n#     plot_history(hist)\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T11:21:26.696946Z","iopub.execute_input":"2021-11-27T11:21:26.697311Z","iopub.status.idle":"2021-11-27T11:21:26.702479Z","shell.execute_reply.started":"2021-11-27T11:21:26.697238Z","shell.execute_reply":"2021-11-27T11:21:26.701623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_test_dataset(filenames, training = False):\n    \n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads = AUTO )  \n    dataset = dataset.map(read_unlabeled_tfrecord , num_parallel_calls = AUTO ).unbatch()\n    dataset = dataset.map(lambda spec : waveform_to_log_mel_spectrogram(spec['audio_wav'], spec['recording_id']) , num_parallel_calls = AUTO)\n    dataset = dataset.map(preprocess, num_parallel_calls = AUTO)\n    return dataset.batch(GLOBAL_BATCH_SIZE*4).cache()\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T11:21:26.703828Z","iopub.execute_input":"2021-11-27T11:21:26.704058Z","iopub.status.idle":"2021-11-27T11:21:26.722149Z","shell.execute_reply.started":"2021-11-27T11:21:26.704028Z","shell.execute_reply":"2021-11-27T11:21:26.721472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predict = []\n\ntest_data = get_test_dataset(TEST_FILES, training = False)\ntest_audio = test_data.map(lambda frames, recording_id: frames)\n\nfor fold in range(N_FOLDS):\n    model.load_weights(f'./RFCX_model_fold {fold}.h5')\n    test_predict.append(model.predict(test_audio, verbose = 1 ))\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T11:21:26.723549Z","iopub.execute_input":"2021-11-27T11:21:26.724134Z","iopub.status.idle":"2021-11-27T11:24:27.020319Z","shell.execute_reply.started":"2021-11-27T11:21:26.724089Z","shell.execute_reply":"2021-11-27T11:24:27.019207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Загружаем sample submission, чтобы потом заменить на наши предсказанные значения, чтобы были в нужном формате для сабмишена\nSUB = pd.read_csv('../input/rfcx-species-audio-detection/sample_submission.csv')\n\npredict = np.array(test_predict).reshape(N_FOLDS, len(SUB), 60 // TIME, params.num_classes)\npredict = np.mean(np.max(predict ,axis = 2) , axis = 0)\n# predict = np.mean(predict, axis =  0)\n\nrecording_id = test_data.map(lambda frames, recording_id: recording_id).unbatch()\n# # all in one batch\ntest_ids = next(iter(recording_id.batch(len(SUB) * 60 // TIME))).numpy().astype('U').reshape(len(SUB), 60 // TIME)\n\npred_df = pd.DataFrame({ 'recording_id' : test_ids[:, 0],\n             **{f's{i}' : predict[:, i] for i in range(params.num_classes)} })\n","metadata":{"execution":{"iopub.status.busy":"2021-11-27T11:24:27.022707Z","iopub.execute_input":"2021-11-27T11:24:27.022958Z","iopub.status.idle":"2021-11-27T11:24:27.16098Z","shell.execute_reply.started":"2021-11-27T11:24:27.022928Z","shell.execute_reply":"2021-11-27T11:24:27.159975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_df.sort_values('recording_id', inplace = True) \npred_df.to_csv('submission.csv', index = False)  ","metadata":{"execution":{"iopub.status.busy":"2021-11-27T11:24:27.163283Z","iopub.execute_input":"2021-11-27T11:24:27.163636Z","iopub.status.idle":"2021-11-27T11:24:27.26305Z","shell.execute_reply.started":"2021-11-27T11:24:27.163592Z","shell.execute_reply":"2021-11-27T11:24:27.262172Z"},"trusted":true},"execution_count":null,"outputs":[]}]}