{"cells":[{"metadata":{"_uuid":"16a0e2d5-1482-48ed-8448-b8f8f6d783bd","_cell_guid":"4a333d20-17f0-41ba-8d3d-ad3acacc7c47","trusted":true},"cell_type":"markdown","source":"Este notebook es una versión de los notebook de [kkiller](https://www.kaggle.com/kneroma/inference-resnest-rfcx-audio-detection) y de [Tarek Hamdi](https://www.kaggle.com/hamditarek/rainforest-connection-analysis-using-librosa).\n\nMi aportación ha sido la traducción y la explicación en español de que es lo que se consigue con este código, utilizando los paquetes de librosa y pytorch principalmente."},{"metadata":{"_uuid":"af601bee-0794-4427-9eb7-1e3d73e5e520","_cell_guid":"8473d248-9fec-4627-9421-54b6f6909c0f","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport sklearn\n\nimport IPython.display as ipd\nimport librosa\nimport librosa.display\nimport soundfile as sf","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b6368edf-022b-443a-95df-ea0ce769737e","_cell_guid":"17ff748e-5ed4-4263-8e2b-586cdb6eaa47","trusted":true},"cell_type":"markdown","source":"### Usaremos los siguientes paquetes de análisis de audio:\n## Librosa\nEs un módulo de Python que analiza señales de audio en general. Incluye lo necesario para crear un sistema MIR (Music Information Retrieval), idóneo para el desarrollo de este análisis. Podemos encontrar la documentación [aquí](https://librosa.org/librosa/), con muchos ejemplos y tutoriales.\n\n## IPython.display.Audio\nQue nos permitirá reproducir el audio directamente desde el \"Notebook\" para facilitar la comprensión del código."},{"metadata":{"_uuid":"b9be44a7-551d-48ce-9056-4243870c2229","_cell_guid":"97663282-e91f-4190-bfd0-95ed5229627f","trusted":true},"cell_type":"markdown","source":"# 1. Carga del archivo de audio"},{"metadata":{"_uuid":"e5ab978e-bcfd-42ff-add3-22fc4f5e518a","_cell_guid":"2c8e6932-946c-4276-a425-0596a19449bc","trusted":true},"cell_type":"code","source":"# De la siguiente manera cargamos el archivo de audio en el Notebook, que será una serie temporal a modo de 'array'\n# con una tasa de muestreo 'sr' de 22 kHZ mono.\n\naudio_test_1 = \"../input/rfcx-species-audio-detection/train/0d25045a9.flac\"\n\n# Seleccioné como ejemplo ese audio por tener 1 especie presente\n\nx , sr = librosa.load(audio_test_1)\n\nprint(type(x), type(sr))\nprint(x.shape, sr)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d5cd714f-e102-457d-9bb5-81faa591c0e3","_cell_guid":"8ba3731b-7d09-40b3-8963-618f10669d6c","trusted":true},"cell_type":"code","source":"# Si nos interesa, podemos cambiar la tasa de muestreo a 44.1 kHZ\n\nlibrosa.load(audio_test_1, sr = 44100)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8cec50e0-c572-42a0-ab33-8e48117564cc","_cell_guid":"a8e4843d-8f52-48ce-8d4c-831294125954","trusted":true},"cell_type":"code","source":"# Para poder escuchar el audio aquí en el 'Notebook' hacemos lo siguiente:\n\nipd.Audio(audio_test_1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f67059e5-066f-4118-b35e-ca6e2a5debb9","_cell_guid":"e7edc5db-6a1b-4ee2-b728-df2cd9dd2487","trusted":true},"cell_type":"markdown","source":"# 2. Generación de Espectrogramas"},{"metadata":{"_uuid":"9dd6b181-ab06-49e6-8e2b-86e29004d96d","_cell_guid":"c19aeba5-88fa-4560-bc0b-f8255b0f575d","trusted":true},"cell_type":"markdown","source":"Un Espectrograma es una manera de representar el audio de manera VISUAL. A lo largo del tiempo que dura dicho audio, se puede representar gráficamente las frecuencias que se han registrado.\n\nEl Espectograma puede mostrarse de distintas formas, ya sea como una gráfica de líneas o como un 'Heatmap'"},{"metadata":{"_uuid":"bde59110-2035-4e6a-a41c-399a91598385","_cell_guid":"3b8dd75b-ebe8-48b2-81f9-91377dffded8","trusted":true},"cell_type":"code","source":"# Mostramos el Espectrograma como una gráfica de líneas.\n# Tiempo vs Frecuencia\n\n%matplotlib inline\n\nplt.figure(figsize=(14, 5))\nlibrosa.display.waveplot(x, sr=sr)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f972f302-d97a-4b00-a0a1-a96e9a953573","_cell_guid":"be799b10-e907-4bf7-9a52-1f91d3db9f7c","trusted":true},"cell_type":"code","source":"# Mostramos el Espectrograma como un'Heatmap'.\n# Tiempo vs Frecuencia\n\nX = librosa.stft(x)\nXdb = librosa.amplitude_to_db(abs(X))\nplt.figure(figsize=(14, 5))\nlibrosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='hz')\nplt.colorbar()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5c4e5a18-b426-493f-be9e-ecb63ae7106c","_cell_guid":"bda0d20f-1f30-40c5-aecf-4a7aad811778","trusted":true},"cell_type":"markdown","source":"Short Time Fourier Transform (stft()) convierte los datos en, como su nombre indica, [transformadas de Fourier de tiempo corto](https://es.wikipedia.org/wiki/Transformada_de_Fourier_de_Tiempo_Reducido), usadas para determinar el contenido en frecuencia sinusoidal y de fase en secciones locales de una señal así como sus cambios con respecto al tiempo.\nSTFT convierte las señales de tal manera que podemos saber la amplitud de la frecuencia dada en un momento dado y además podemos determinar la amplitud de varias frecuencias que se reproducen en un momento dado de una señal de audio.\n\nPor otro lado, specshow() muestra el espectrograma con las siguientes características: El eje vertical muestra las frecuencias (de 0 a 10kHz), y el eje horizontal muestra el tiempo del clip. Como vemos que toda la acción tiene lugar en el fondo del espectro, podemos convertir el eje de frecuencias en uno logarítmico."},{"metadata":{"_uuid":"ec3d1ea2-2cf1-4778-bf8f-705c48ca6984","_cell_guid":"7eda9b83-1f74-420a-85ac-35da5c5d85f8","trusted":true},"cell_type":"code","source":"# Aplicamos la escala logarítimica para centrar la atención el los sonidos a estudiar\n\nlibrosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='log')\nplt.colorbar()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5b5c26ba-6629-4c53-a6bd-6ceb14839659","_cell_guid":"208c9f82-4e69-46e5-8f15-c7e1e990c787","trusted":true},"cell_type":"markdown","source":"# 3. Creación de la señal de Audio"},{"metadata":{"_uuid":"03b40f99-3605-4e99-a921-6df420207e3a","_cell_guid":"493fc952-61ce-44b1-a139-b3be3d0d16ac","trusted":true},"cell_type":"code","source":"sr = 22050 # Tiempo de muestreo\nT = 5.0    # Segundos\nt = np.linspace(0, T, int(T*sr), endpoint=False) # Variable tiempo\nx = 0.5*np.sin(2*np.pi*220*t) # Onda senoidal pura a 220 Hz\n\n# Reproduciendo el audio\nipd.Audio(x, rate=sr) # Generando un NumPy 'array'\n\n# Guardando el audio\nsf.write('tono_0d25045a9_220.wav', x, sr)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"29b1e6f9-01ab-44e1-917e-7fe8ef21c3e1","_cell_guid":"e9d2e8ff-9bcf-40b1-8bcd-f50ac7fb72c7","trusted":true},"cell_type":"code","source":"# El 'spectral_centroid' devolverá un 'array' con el mismo número de \n# columnas que número de 'fotogramas' presentes en la muestra de audio\n\nspectral_centroids = librosa.feature.spectral_centroid(x, sr=sr)[0]\nspectral_centroids.shape\n\n# Calculando la variable de tiempo para la visualización\n\nplt.figure(figsize=(12, 4))\nframes = range(len(spectral_centroids))\nt = librosa.frames_to_time(frames)\n\n# Normalizando el 'centroide espectral' para la visualización\n\ndef normalize(x, axis=0):\n    return sklearn.preprocessing.minmax_scale(x, axis=axis)\n\n# Trazando el 'centroide espectral' a lo largo de la forma de onda\n\nlibrosa.display.waveplot(x, sr=sr, alpha=0.4)\nplt.plot(t, normalize(spectral_centroids), color='b')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"484726b6-633f-401b-8b99-11e403e38216","_cell_guid":"aaea69ec-7450-4a47-a925-09299375b939","trusted":true},"cell_type":"markdown","source":"## Atenuación del espectro de frecuencias"},{"metadata":{"_uuid":"61ea29b0-4fef-4b9f-8905-56dbecbd0138","_cell_guid":"ce4e5ae5-db33-4562-b46b-b3be9eac5789","trusted":true},"cell_type":"markdown","source":"Representa la frecuencia a la que las frecuencias altas descienden a 0. Para obtener dicha frecuencia, hay que calcular la fracción en el espectro en la cual el 85% de la potencia espectral está a bajas frecuencias.\n\nlibrosa.feature.spectral_rolloff() calcula la frecuencia de caida para cada momento de la señal"},{"metadata":{"_uuid":"349119b9-f88a-4ceb-8e9b-f169c92f6678","_cell_guid":"8c7f68c2-4829-40f4-898a-4507cd0ffbc0","trusted":true},"cell_type":"code","source":"spectral_rolloff = librosa.feature.spectral_rolloff(x+0.01, sr=sr)[0]\nplt.figure(figsize=(12, 4))\nlibrosa.display.waveplot(x, sr=sr, alpha=0.4)\nplt.plot(t, normalize(spectral_rolloff), color='black')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"50d6ab2e-23d1-49bf-8a87-cfa579fd1fbe","_cell_guid":"a5ab0fdf-d023-450d-8cae-8ee4fe798f08","trusted":true},"cell_type":"markdown","source":"## Ancho de banda del espectro de frecuencias"},{"metadata":{"_uuid":"2af06f19-dbe5-4416-b611-7a7a39d4f8c5","_cell_guid":"3b820b1c-901a-460e-ae4f-5228c2186070","trusted":true},"cell_type":"markdown","source":"El Ancho de Banda del espectro es el intervalo de longitudes de onda en el que una cantidad espectral no es inferior a la mitad de su valor máximo."},{"metadata":{"_uuid":"05e6cb1a-aa8d-4931-8396-154e2322192c","_cell_guid":"f6785a39-d71a-4903-b235-c31861f2b5f9","trusted":true},"cell_type":"code","source":"spectral_bandwidth_2 = librosa.feature.spectral_bandwidth(x+0.01, sr=sr)[0]\nspectral_bandwidth_3 = librosa.feature.spectral_bandwidth(x+0.01, sr=sr, p=3)[0]\nspectral_bandwidth_4 = librosa.feature.spectral_bandwidth(x+0.01, sr=sr, p=4)[0]\nplt.figure(figsize=(15, 9))\nlibrosa.display.waveplot(x, sr=sr, alpha=0.4)\nplt.plot(t, normalize(spectral_bandwidth_2), color='r')\nplt.plot(t, normalize(spectral_bandwidth_3), color='g')\nplt.plot(t, normalize(spectral_bandwidth_4), color='y')\nplt.legend(('p = 2', 'p = 3', 'p = 4'))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"35466d1f-6b3e-495f-9748-836274913084","_cell_guid":"95ba5758-4d72-4029-a2ad-84e66b93569f","trusted":true},"cell_type":"code","source":"x.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e7d5e9f1-9d59-4194-8898-a96337d1d5df","_cell_guid":"351554d6-f8f1-44b3-9d53-ee31a7855a8d","trusted":true},"cell_type":"code","source":"x, sr = librosa.load(audio_test_1)\n\n# Para centrarnos en un momento específico y ver el comportamiento de las frecuencias, podemos\n# mostrar la gráfica del audio en cuestión para hacerle un zoom en el momento concreto:\n\nplt.figure(figsize=(14, 5))\nlibrosa.display.waveplot(x, sr=sr)\n\n# Aplicamos el zoom, siendo 9000 y 9100 datos registrados en 'x'.\n\n# Dado que 'x' es un \"array\" de 1.323.000 valores, acotando a los valores \n# mencionados, conseguimos hacer zoom a una zona en concreta del audio.\n\n# Haciendo algunos cálculos rápidamente, si la duración total es de 60 segundos\n# y en esos 60 segundos tenemos 1.323.000 valores, el zoom de 9000 a 9100 equivale\n# al periodo de tiempo entre el segundo 0'4081 y el segundo 0'4126.\n\nn0 = 9000\nn1 = 9100\nplt.figure(figsize=(14, 5))\nplt.plot(x[n0:n1])\nplt.grid()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a49a8818-c107-42f2-966f-24953c018cdf","_cell_guid":"b1247ea8-262c-4613-bea4-4211dfeb7766","trusted":true},"cell_type":"code","source":"# Librosa también nos permite calcular fácilmente el número de veces\n# que la onda pasa por cero en el periodo de tiempo determinado\n\nzero_crossings = librosa.zero_crossings(x[n0:n1], pad=False)\nprint(sum(zero_crossings))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"44613d7a-d271-4754-997b-878b79dce897","_cell_guid":"e2ccac44-4323-4ec9-a7ab-91837473a0da","trusted":true},"cell_type":"markdown","source":"# 4. Mel-Frequency Cepstral Coefficients (MFCCs)"},{"metadata":{"_uuid":"c5a24efb-fb18-4678-83c0-21e3e4febde6","_cell_guid":"71cb8e31-9d52-41c1-9117-c7938a682269","trusted":true},"cell_type":"markdown","source":"Los MFCCs son coeﬁcientes para la representación del habla basados en la percepción auditiva humana. Estos surgen de la necesidad, en el área del reconocimiento de audio automático, de extraer características de las componentes de una señal de audio que sean adecuadas para la identificación de contenido relevante, así como obviar todas aquellas que posean información poco valiosa como el ruido de fondo, emociones, volumen, tono, etc."},{"metadata":{"_uuid":"c4d67999-c777-4528-be83-ba4ffc2464fd","_cell_guid":"a8298400-a8d1-4a57-8bd0-bf5d6c5cc947","trusted":true},"cell_type":"code","source":"# Para obtener una gráfica MFCC, se definen los siguientes parámetros:\n\nfs=10  # Siendo 'fs' un escalar > 0 y que define la tasa de muestreo para el eje \"y\" \nmfccs = librosa.feature.mfcc(x, sr = fs)  # Se define la variable mfccs para poder sacar el gráfico, es una matriz\nprint(mfccs.shape)\n(20, 97)\n\n# Utilizando la libreria 'librosa' sacamos el gráfico correspondiente\n\nplt.figure(figsize=(15, 7))\nlibrosa.display.specshow(mfccs, sr = sr, x_axis = 'time')  # Siendo 'sr' la tasa de muestreo utilizada para determinar la escala de tiempo en el eje \"x\".","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"06594dcf-0992-4380-a029-4867a874050a","_cell_guid":"3744de64-0f55-444e-b70f-4ba3917f9002","trusted":true},"cell_type":"code","source":"# Otra herramienta interesante es 'chromagram', pues permite resaltar las características principales del croma\n\nhop_length=12  # La longitud del 'salto', que también se utiliza para determinar la escala de tiempo en el eje \"x\"\nchromagram = librosa.feature.chroma_stft(x, sr = sr, hop_length = hop_length)  # Se define la variable 'chromagram' para poder sacar el gráfico, es una matriz\n\n# Y se obtiene el gráfico con las variables ya definidas\n\nplt.figure(figsize=(15, 5))\nlibrosa.display.specshow(chromagram,\n                         x_axis = 'time', \n                         y_axis = 'chroma',\n                         hop_length = hop_length, \n                         cmap = 'coolwarm'  #'magma', 'gray_r', 'coolwarm'\n                         )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fe1bdc49-f409-46ba-b1e8-4a6877ba4ce3","_cell_guid":"3338e05d-9137-4ba4-a936-ae9985ce2d29","trusted":true},"cell_type":"markdown","source":"# 5. Modelado"},{"metadata":{"_uuid":"921a3e1b-2985-4c60-92d4-ed1b1ec46bad","_cell_guid":"7a1526d8-efc6-4ef4-b1cc-bbe77dd81124","trusted":true},"cell_type":"code","source":"# Trabajando en Linux desde mi ordenador, la manera de instalar el paquete 'resnest' fue utilizando:\n\n#pip install resnest\n\n# Pero para poder subir el Notebook a kaggle, la forma de implementar resnest es la siguiente\n\n!pip install resnest > /dev/null","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2b56aee0-f988-45cf-b8bd-6d1b873fa85f","_cell_guid":"1f831534-dec5-41b8-8b34-8fa462e27795","trusted":true},"cell_type":"code","source":"from pathlib import Path\nimport librosa as lb\n\nimport torch\nfrom  torch.utils.data import Dataset, DataLoader\n\nfrom tqdm.notebook import tqdm\n\nfrom resnest.torch import resnest50","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3096f249-d480-4a60-b101-5776f7884e2a","_cell_guid":"b0ca175d-a5c0-463f-99f6-14642cb210e0","trusted":true},"cell_type":"code","source":"# Se definen en primer lugar algunas variables y se cargan los datos de la competición para \n# implementarles transformaciones mediante unas funciones que se analizarán más adelante\n\nNUM_CLASSES = 24\nSR = 16_000\nDURATION =  60\n\nDATA_ROOT = Path(\"../input/rfcx-species-audio-detection\")\nTRAIN_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/train\")\nTEST_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/test\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"23290430-feca-49d3-807d-ca7478e4be1d","_cell_guid":"9bb9c7cd-c52c-4819-90d1-f8ab19340f58","trusted":true},"cell_type":"code","source":"# Esta primera función crea 'MelSpecComputer', para generar 'melspec',\n# añadiéndole como parámetros para poder utilizar dicha función:\n\nclass MelSpecComputer:\n    def __init__(self, sr, n_mels, fmin, fmax):\n        \n        self.sr = sr  # sr: Tasa de muestreo del eje \"y\"\n        self.n_mels = n_mels  # n_mels: Número de bandas 'Mel' a generar\n        self.fmin = fmin  # fmin: Frecuencia máxima\n        self.fmax = fmax  # fmax: Frecuencia mínima\n\n    def __call__(self, y):\n\n        melspec = lb.feature.melspectrogram(y,\n                                            sr = self.sr,\n                                            n_mels = self.n_mels,\n                                            fmin = self.fmin,\n                                            fmax = self.fmax,\n                                            )\n\n        melspec = lb.power_to_db(melspec).astype(np.float32)\n        \n        return melspec","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eb5377f3-7f67-42c3-a5d3-32d199496674","_cell_guid":"ab50cb1c-b5a5-41e5-8090-2bb52935cdbe","trusted":true},"cell_type":"code","source":"# Esta primera función se encarga de transformar 'X' en 'V', que contendrá\n# la información necesaria dentro del 'array' para pasar de \"mono\" a \"color\"\n\ndef mono_to_color(X, eps=1e-6, mean=None, std=None):\n    \n    X = np.stack([X, X, X], axis=-1)\n\n    # Estandarización\n    mean = mean or X.mean()\n    std = std or X.std()\n    X = (X - mean) / (std + eps)\n\n    # Normalización a [0, 255]\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    \n    else:\n        \n        V = np.zeros_like(X, dtype=np.uint8)\n\n    return V\n\n\n# Esta función se encarga de normalizar la imagen\n\ndef normalize(image, mean=None, std=None):\n    \n    image = image / 255.0\n    \n    if mean is not None and std is not None:\n        \n        image = (image - mean) / std\n        \n    return np.moveaxis(image, 2, 0).astype(np.float32)\n\n# Y esta determinará la longitud de los audios en función de los \n# datos dados por la competición (tmax - tmin)\n\ndef crop_or_pad(y, length, sr, is_train=True):\n    \n    if len(y) < length:\n        \n        y = np.concatenate([y, np.zeros(length - len(y))])\n        \n    elif len(y) > length:\n        \n        if not is_train:\n            \n            start = 0\n            \n        else:\n            \n            start = np.random.randint(len(y) - length)\n\n        y = y[start:start + length]\n\n    y = y.astype(np.float32, copy=False)\n\n    return y","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"732800d5-beb0-4bc5-89f6-8a10b176e448","_cell_guid":"b57bacde-0437-41dd-b6d9-2106ab152f6d","trusted":true},"cell_type":"code","source":"# Una vez definidas las 3 funciones en la celda anterior, el siguiente paso es \n# completar un nuevo dataset 'RFCXDataset' utilizando las funciones anteriores\n# a modo de preparación de los datos que se recogerán en el nuevo dataset\n\nclass RFCXDataset(Dataset):\n\n    def __init__(self, \n                 data, \n                 sr, \n                 n_mels = 128, \n                 fmin = 0, \n                 fmax = None,  \n                 is_train = False,\n                 num_classes = NUM_CLASSES, \n                 root = None, \n                 duration = DURATION) :\n\n        self.data = data\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.is_train = is_train\n\n        self.num_classes = num_classes\n        self.duration = duration\n        self.audio_length = self.duration*self.sr\n        \n        self.root =  root or (TRAIN_AUDIO_ROOT if self.is_train else TEST_AUDIO_ROOT)\n\n        self.wav_transfos = get_wav_transforms() if self.is_train else None\n\n        self.mel_spec_computer = MelSpecComputer(sr=self.sr, n_mels=self.n_mels, fmin=self.fmin, fmax=self.fmax)  # Función definida en la celda anterior\n\n\n    def __len__(self):\n        return len(self.data)\n    \n    def read_index(self, idx, fill_val=1.0, offset=None, use_offset=True):\n        d = self.data.iloc[idx]\n        record, species = d[\"recording_id\"], d[\"species_id\"]\n        try:\n            if use_offset and (self.duration < d[\"duration\"]+1):\n                offset = offset or np.random.uniform(1, int(d[\"duration\"]-self.duration))\n\n            y, _ = lb.load(self.root.joinpath(record).with_suffix(\".flac\").as_posix(),\n                           sr=self.sr, duration=self.duration, offset=offset)\n            \n            if self.wav_transfos is not None:\n                y = self.wav_transfos(y, self.sr)\n            y = crop_or_pad(y, self.audio_length, sr=self.sr)  # Función definida en la celda anterior\n            t = np.zeros(self.num_classes)\n            t[species] = fill_val\n            \n        except Exception as e:\n#             print(e)\n            raise ValueError()  from  e\n            y = np.zeros(self.audio_length)\n            t = np.zeros(self.num_classes)\n        \n        return y,t\n            \n        \n\n    def __getitem__(self, idx):\n\n        y, t = self.read_index(idx)\n        \n        \n        melspec = self.mel_spec_computer(y)  # Función definida en la celda anterior\n        image = mono_to_color(melspec)  # Función definida en la celda anterior\n        image = normalize(image, mean=None, std=None)  # Función definida en la celda anterior\n\n        return image, t","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e693db96-432c-4a28-963b-41986e6fca0f","_cell_guid":"fe6101b0-12f4-4e22-a560-71cfcc7957ee","trusted":true},"cell_type":"code","source":"# Función para obtener la duración de los audios\n\ndef get_duration(audio_name, root=TEST_AUDIO_ROOT):\n    return lb.get_duration(filename=root.joinpath(audio_name).with_suffix(\".flac\"))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5ecb3bf9-7d38-4643-b33b-27d4fade3000","_cell_guid":"0e003916-5e76-45d5-8996-4919dcf82733","trusted":true},"cell_type":"code","source":"# Definición del nuevo dataset, para aplicarle posteriormente la variable definida\n# en las celdas anteriores 'RFCXDataset'\n\ndata = pd.DataFrame({\n    \"recording_id\": [path.stem for path in Path(TEST_AUDIO_ROOT).glob(\"*.flac\")],\n})\ndata[\"species_id\"] = [[] for _ in range(len(data))]\n\nprint(data.shape)\ndata[\"duration\"] = data[\"recording_id\"].apply(get_duration)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a58d12a8-14c4-43f5-9c58-12e2f950873b","_cell_guid":"dd4b98c3-0db1-4085-8e3d-db350ad86029","trusted":true},"cell_type":"markdown","source":"# 6. Inferencia"},{"metadata":{"_uuid":"4ebd917e-e47a-43a2-b30b-b551bd649fc0","_cell_guid":"bee4bb32-1b1a-4c41-812d-96c73ecebf25","trusted":true},"cell_type":"code","source":"# En este último paso, utilizando el paquete 'resnest' y aplicando 'RFCXDataset' a los datos se obtiene,\n# para cada 'recording_id', la probabilidad de cada una de las 23 especies de aparecer en el audio en\n# concreto, que viene a ser el 'dataset' requerido por la competición\n\n# Se definen los parámetros necesarios\n\nTEST_BATCH_SIZE = 40\nTEST_NUM_WORKERS = 2","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9c488356-ad86-4478-a544-2f118a4103ad","_cell_guid":"fcc989b7-231a-4b11-a2fe-61475ca897e5","trusted":true},"cell_type":"code","source":"# Aplicamos las funciones al 'dataset' data\n\ntest_data = RFCXDataset(data=data, sr=SR)\n\n# Utilizamos PyTorch para cargar los datos, iterando sobre 'test_data'\n\ntest_loader = DataLoader(test_data, batch_size=TEST_BATCH_SIZE, num_workers=TEST_NUM_WORKERS)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0c588e23-51f7-40d7-8124-10c9ba77a6d3","_cell_guid":"e5df1b12-c388-4dc3-927c-0eaca609eef2","trusted":true},"cell_type":"markdown","source":"Estas 2 celdas de acontinuación son las que generan los resultados, utilizando el 'dataset' [RFCX Species Detection Public Checkpoints](https://www.kaggle.com/kneroma/kkiller-rfcx-species-detection-public-checkpoints) de Kkiller para evaluar y guardando las predicciones obtenidas en el 'dataset' \"preds\""},{"metadata":{"_uuid":"b2a94bc6-cad4-408b-ba66-5217e1fccfc7","_cell_guid":"34d25dcf-edc0-4541-aa43-81d314decb36","trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nnet = resnest50(pretrained=True).to(device)\nn_features = net.fc.in_features\nnet.fc = torch.nn.Linear(n_features, NUM_CLASSES)\nnet = net.to(device)\nnet.load_state_dict(torch.load(\"../input/kkiller-rfcx-species-detection-public-checkpoints/rfcx_resnest50.pth\", map_location=device))\nnet = net.eval()\nnet","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6f471518-d89f-4aaa-9d9d-ad3f9cd89f39","_cell_guid":"86e94265-b4de-47a1-84b6-e14d2e9e1b53","trusted":true},"cell_type":"code","source":"preds = []\nnet.eval()\nwith torch.no_grad():\n    for (xb, yb) in  tqdm(test_loader):\n        xb, yb = xb.to(device), yb.to(device)\n        o = net(xb)\n        o = torch.sigmoid(o) \n        preds.append(o.detach().cpu().numpy())\npreds = np.vstack(preds)\npreds.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f92662c3-9c04-410e-8ebf-97f0b797e7a5","_cell_guid":"ffd1841a-56ca-4f20-b825-4a2b25f68dcc","trusted":true},"cell_type":"markdown","source":"Finalmente, una vez obtenido \"preds\", definimos el 'dataset' que subiremos a la competición, dándole el formato requerido según las instrucciones de Rainforest Connection, y concluyendo así el Notebook!"},{"metadata":{"_uuid":"5c706fa7-638d-4304-a689-5f884d73566f","_cell_guid":"9a792fbf-0e73-4664-8b64-6c2ef812e20a","trusted":true},"cell_type":"code","source":"sub = pd.DataFrame(preds, columns=[f\"s{i}\" for i in range(24)])\nsub[\"recording_id\"] = data[\"recording_id\"].values[:len(sub)]\nsub = sub[[\"recording_id\"] + [f\"s{i}\" for i in range(24)]]\nprint(sub.shape)\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f618c6c8-51db-43ff-b95e-8a9f2ed7080e","_cell_guid":"85f8f09c-526b-4013-8266-253c0638c516","trusted":true},"cell_type":"code","source":"sub.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}