{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "Cb4espuLKJiA" }, "source": [ "##### Copyright 2021 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2023-10-27T05:52:28.082781Z", "iopub.status.busy": "2023-10-27T05:52:28.082357Z", "iopub.status.idle": "2023-10-27T05:52:28.085988Z", "shell.execute_reply": "2023-10-27T05:52:28.085428Z" }, "id": "DjZQV2njKJ3U" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "mTL0TERThT6z" }, "source": [ "\n", " \n", " \n", " \n", " \n", " \n", "
\n", " View on TensorFlow.org\n", " \n", " Run in Google Colab\n", " \n", " View on GitHub\n", " \n", " Download notebook\n", " \n", " See TF Hub model\n", "
" ] }, { "cell_type": "markdown", "metadata": { "id": "K2madPFAGHb3" }, "source": [ "# Transfer learning with YAMNet for environmental sound classification\n", "\n", "[YAMNet](https://tfhub.dev/google/yamnet/1) is a pre-trained deep neural network that can predict audio events from [521 classes](https://github.com/tensorflow/models/blob/master/research/audioset/yamnet/yamnet_class_map.csv), such as laughter, barking, or a siren. \n", "\n", " In this tutorial you will learn how to:\n", "\n", "- Load and use the YAMNet model for inference.\n", "- Build a new model using the YAMNet embeddings to classify cat and dog sounds.\n", "- Evaluate and export your model.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "5Mdp2TpBh96Y" }, "source": [ "## Import TensorFlow and other libraries\n" ] }, { "cell_type": "markdown", "metadata": { "id": "zCcKYqu_hvKe" }, "source": [ "Start by installing [TensorFlow I/O](https://www.tensorflow.org/io), which will make it easier for you to load audio files off disk." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:52:28.089668Z", "iopub.status.busy": "2023-10-27T05:52:28.089092Z", "iopub.status.idle": "2023-10-27T05:52:59.059468Z", "shell.execute_reply": "2023-10-27T05:52:59.058385Z" }, "id": "urBpRWDHTHHU" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\r\n", "tensorflow-datasets 4.9.3 requires protobuf>=3.20, but you have protobuf 3.19.6 which is incompatible.\r\n", "tensorflow-metadata 1.14.0 requires protobuf<4.21,>=3.20.3, but you have protobuf 3.19.6 which is incompatible.\u001b[0m\u001b[31m\r\n", "\u001b[0m" ] } ], "source": [ "!pip install -q \"tensorflow==2.11.*\"\n", "# tensorflow_io 0.28 is compatible with TensorFlow 2.11\n", "!pip install -q \"tensorflow_io==0.28.*\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:52:59.064124Z", "iopub.status.busy": "2023-10-27T05:52:59.063530Z", "iopub.status.idle": "2023-10-27T05:53:01.618126Z", "shell.execute_reply": "2023-10-27T05:53:01.617418Z" }, "id": "7l3nqdWVF-kC" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2023-10-27 05:52:59.905244: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2023-10-27 05:53:00.569783: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:00.569881: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:00.569891: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] } ], "source": [ "import os\n", "\n", "from IPython import display\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "\n", "import tensorflow as tf\n", "import tensorflow_hub as hub\n", "import tensorflow_io as tfio" ] }, { "cell_type": "markdown", "metadata": { "id": "v9ZhybCnt_bM" }, "source": [ "## About YAMNet\n", "\n", "[YAMNet](https://github.com/tensorflow/models/tree/master/research/audioset/yamnet) is a pre-trained neural network that employs the [MobileNetV1](https://arxiv.org/abs/1704.04861) depthwise-separable convolution architecture. It can use an audio waveform as input and make independent predictions for each of the 521 audio events from the [AudioSet](http://g.co/audioset) corpus.\n", "\n", "Internally, the model extracts \"frames\" from the audio signal and processes batches of these frames. This version of the model uses frames that are 0.96 second long and extracts one frame every 0.48 seconds .\n", "\n", "The model accepts a 1-D float32 Tensor or NumPy array containing a waveform of arbitrary length, represented as single-channel (mono) 16 kHz samples in the range `[-1.0, +1.0]`. This tutorial contains code to help you convert WAV files into the supported format.\n", "\n", "The model returns 3 outputs, including the class scores, embeddings (which you will use for transfer learning), and the log mel [spectrogram](https://www.tensorflow.org/tutorials/audio/simple_audio#spectrogram). You can find more details [here](https://tfhub.dev/google/yamnet/1).\n", "\n", "One specific use of YAMNet is as a high-level feature extractor - the 1,024-dimensional embedding output. You will use the base (YAMNet) model's input features and feed them into your shallower model consisting of one hidden `tf.keras.layers.Dense` layer. Then, you will train the network on a small amount of data for audio classification _without_ requiring a lot of labeled data and training end-to-end. (This is similar to [transfer learning for image classification with TensorFlow Hub](https://www.tensorflow.org/tutorials/images/transfer_learning_with_hub) for more information.)\n", "\n", "First, you will test the model and see the results of classifying audio. You will then construct the data pre-processing pipeline.\n", "\n", "### Loading YAMNet from TensorFlow Hub\n", "\n", "You are going to use a pre-trained YAMNet from [Tensorflow Hub](https://tfhub.dev/) to extract the embeddings from the sound files.\n", "\n", "Loading a model from TensorFlow Hub is straightforward: choose the model, copy its URL, and use the `load` function.\n", "\n", "Note: to read the documentation of the model, use the model URL in your browser." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:01.622541Z", "iopub.status.busy": "2023-10-27T05:53:01.621963Z", "iopub.status.idle": "2023-10-27T05:53:06.081346Z", "shell.execute_reply": "2023-10-27T05:53:06.080619Z" }, "id": "06CWkBV5v3gr" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2023-10-27 05:53:02.611471: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:02.611570: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublas.so.11'; dlerror: libcublas.so.11: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:02.611631: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublasLt.so.11'; dlerror: libcublasLt.so.11: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:02.611689: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcufft.so.10'; dlerror: libcufft.so.10: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:02.666048: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcusparse.so.11'; dlerror: libcusparse.so.11: cannot open shared object file: No such file or directory\n", "2023-10-27 05:53:02.666240: W tensorflow/core/common_runtime/gpu/gpu_device.cc:1934] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.\n", "Skipping registering GPU devices...\n" ] } ], "source": [ "yamnet_model_handle = 'https://tfhub.dev/google/yamnet/1'\n", "yamnet_model = hub.load(yamnet_model_handle)" ] }, { "cell_type": "markdown", "metadata": { "id": "GmrPJ0GHw9rr" }, "source": [ "With the model loaded, you can follow the [YAMNet basic usage tutorial](https://www.tensorflow.org/hub/tutorials/yamnet) and download a sample WAV file to run the inference.\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:06.085803Z", "iopub.status.busy": "2023-10-27T05:53:06.085161Z", "iopub.status.idle": "2023-10-27T05:53:06.211731Z", "shell.execute_reply": "2023-10-27T05:53:06.211123Z" }, "id": "C5i6xktEq00P" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://storage.googleapis.com/audioset/miaow_16k.wav\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/215546 [>.............................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "215546/215546 [==============================] - 0s 0us/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "./test_data/miaow_16k.wav\n" ] } ], "source": [ "testing_wav_file_name = tf.keras.utils.get_file('miaow_16k.wav',\n", " 'https://storage.googleapis.com/audioset/miaow_16k.wav',\n", " cache_dir='./',\n", " cache_subdir='test_data')\n", "\n", "print(testing_wav_file_name)" ] }, { "cell_type": "markdown", "metadata": { "id": "mBm9y9iV2U_-" }, "source": [ "You will need a function to load audio files, which will also be used later when working with the training data. (Learn more about reading audio files and their labels in [Simple audio recognition](https://www.tensorflow.org/tutorials/audio/simple_audio#reading_audio_files_and_their_labels).\n", "\n", "Note: The returned `wav_data` from `load_wav_16k_mono` is already normalized to values in the `[-1.0, 1.0]` range (for more information, go to [YAMNet's documentation on TF Hub](https://tfhub.dev/google/yamnet/1))." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:06.215420Z", "iopub.status.busy": "2023-10-27T05:53:06.214799Z", "iopub.status.idle": "2023-10-27T05:53:06.219782Z", "shell.execute_reply": "2023-10-27T05:53:06.219118Z" }, "id": "Xwc9Wrdg2EtY" }, "outputs": [], "source": [ "# Utility functions for loading audio files and making sure the sample rate is correct.\n", "\n", "@tf.function\n", "def load_wav_16k_mono(filename):\n", " \"\"\" Load a WAV file, convert it to a float tensor, resample to 16 kHz single-channel audio. \"\"\"\n", " file_contents = tf.io.read_file(filename)\n", " wav, sample_rate = tf.audio.decode_wav(\n", " file_contents,\n", " desired_channels=1)\n", " wav = tf.squeeze(wav, axis=-1)\n", " sample_rate = tf.cast(sample_rate, dtype=tf.int64)\n", " wav = tfio.audio.resample(wav, rate_in=sample_rate, rate_out=16000)\n", " return wav" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:06.222945Z", "iopub.status.busy": "2023-10-27T05:53:06.222542Z", "iopub.status.idle": "2023-10-27T05:53:07.139882Z", "shell.execute_reply": "2023-10-27T05:53:07.139110Z" }, "id": "FRqpjkwB0Jjw" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.\n", "Instructions for updating:\n", "Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.\n", "Instructions for updating:\n", "Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "testing_wav_data = load_wav_16k_mono(testing_wav_file_name)\n", "\n", "_ = plt.plot(testing_wav_data)\n", "\n", "# Play the audio file.\n", "display.Audio(testing_wav_data, rate=16000)" ] }, { "cell_type": "markdown", "metadata": { "id": "6z6rqlEz20YB" }, "source": [ "### Load the class mapping\n", "\n", "It's important to load the class names that YAMNet is able to recognize. The mapping file is present at `yamnet_model.class_map_path()` in the CSV format." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:07.144212Z", "iopub.status.busy": "2023-10-27T05:53:07.143667Z", "iopub.status.idle": "2023-10-27T05:53:07.160140Z", "shell.execute_reply": "2023-10-27T05:53:07.159416Z" }, "id": "6Gyj23e_3Mgr" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Speech\n", "Child speech, kid speaking\n", "Conversation\n", "Narration, monologue\n", "Babbling\n", "Speech synthesizer\n", "Shout\n", "Bellow\n", "Whoop\n", "Yell\n", "Children shouting\n", "Screaming\n", "Whispering\n", "Laughter\n", "Baby laughter\n", "Giggle\n", "Snicker\n", "Belly laugh\n", "Chuckle, chortle\n", "Crying, sobbing\n", "...\n" ] } ], "source": [ "class_map_path = yamnet_model.class_map_path().numpy().decode('utf-8')\n", "class_names =list(pd.read_csv(class_map_path)['display_name'])\n", "\n", "for name in class_names[:20]:\n", " print(name)\n", "print('...')" ] }, { "cell_type": "markdown", "metadata": { "id": "5xbycDnT40u0" }, "source": [ "### Run inference\n", "\n", "YAMNet provides frame-level class-scores (i.e., 521 scores for every frame). In order to determine clip-level predictions, the scores can be aggregated per-class across frames (e.g., using mean or max aggregation). This is done below by `scores_np.mean(axis=0)`. Finally, to find the top-scored class at the clip-level, you take the maximum of the 521 aggregated scores.\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:07.163484Z", "iopub.status.busy": "2023-10-27T05:53:07.162930Z", "iopub.status.idle": "2023-10-27T05:53:07.447375Z", "shell.execute_reply": "2023-10-27T05:53:07.446624Z" }, "id": "NT0otp-A4Y3u" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The main sound is: Animal\n", "The embeddings shape: (13, 1024)\n" ] } ], "source": [ "scores, embeddings, spectrogram = yamnet_model(testing_wav_data)\n", "class_scores = tf.reduce_mean(scores, axis=0)\n", "top_class = tf.math.argmax(class_scores)\n", "inferred_class = class_names[top_class]\n", "\n", "print(f'The main sound is: {inferred_class}')\n", "print(f'The embeddings shape: {embeddings.shape}')" ] }, { "cell_type": "markdown", "metadata": { "id": "YBaLNg5H5IWa" }, "source": [ "Note: The model correctly inferred an animal sound. Your goal in this tutorial is to increase the model's accuracy for specific classes. Also, notice that the model generated 13 embeddings, 1 per frame." ] }, { "cell_type": "markdown", "metadata": { "id": "fmthELBg1A2-" }, "source": [ "## ESC-50 dataset\n", "\n", "The [ESC-50 dataset](https://github.com/karolpiczak/ESC-50#repository-content) ([Piczak, 2015](https://www.karolpiczak.com/papers/Piczak2015-ESC-Dataset.pdf)) is a labeled collection of 2,000 five-second long environmental audio recordings. The dataset consists of 50 classes, with 40 examples per class.\n", "\n", "Download the dataset and extract it. \n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:53:07.451121Z", "iopub.status.busy": "2023-10-27T05:53:07.450832Z", "iopub.status.idle": "2023-10-27T05:54:05.063024Z", "shell.execute_reply": "2023-10-27T05:54:05.062029Z" }, "id": "MWobqK8JmZOU" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://github.com/karoldvl/ESC-50/archive/master.zip\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/Unknown - 0s 0us/step" ] } ], "source": [ "_ = tf.keras.utils.get_file('esc-50.zip',\n", " 'https://github.com/karoldvl/ESC-50/archive/master.zip',\n", " cache_dir='./',\n", " cache_subdir='datasets',\n", " extract=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "qcruxiuX1cO5" }, "source": [ "### Explore the data\n", "\n", "The metadata for each file is specified in the csv file at `./datasets/ESC-50-master/meta/esc50.csv`\n", "\n", "and all the audio files are in `./datasets/ESC-50-master/audio/`\n", "\n", "You will create a pandas `DataFrame` with the mapping and use that to have a clearer view of the data.\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.067487Z", "iopub.status.busy": "2023-10-27T05:54:05.067025Z", "iopub.status.idle": "2023-10-27T05:54:05.080694Z", "shell.execute_reply": "2023-10-27T05:54:05.080110Z" }, "id": "jwmLygPrMAbH" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
filenamefoldtargetcategoryesc10src_filetake
01-100032-A-0.wav10dogTrue100032A
11-100038-A-14.wav114chirping_birdsFalse100038A
21-100210-A-36.wav136vacuum_cleanerFalse100210A
31-100210-B-36.wav136vacuum_cleanerFalse100210B
41-101296-A-19.wav119thunderstormFalse101296A
\n", "
" ], "text/plain": [ " filename fold target category esc10 src_file take\n", "0 1-100032-A-0.wav 1 0 dog True 100032 A\n", "1 1-100038-A-14.wav 1 14 chirping_birds False 100038 A\n", "2 1-100210-A-36.wav 1 36 vacuum_cleaner False 100210 A\n", "3 1-100210-B-36.wav 1 36 vacuum_cleaner False 100210 B\n", "4 1-101296-A-19.wav 1 19 thunderstorm False 101296 A" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "esc50_csv = './datasets/ESC-50-master/meta/esc50.csv'\n", "base_data_path = './datasets/ESC-50-master/audio/'\n", "\n", "pd_data = pd.read_csv(esc50_csv)\n", "pd_data.head()" ] }, { "cell_type": "markdown", "metadata": { "id": "7d4rHBEQ2QAU" }, "source": [ "### Filter the data\n", "\n", "Now that the data is stored in the `DataFrame`, apply some transformations:\n", "\n", "- Filter out rows and use only the selected classes - `dog` and `cat`. If you want to use any other classes, this is where you can choose them.\n", "- Amend the filename to have the full path. This will make loading easier later.\n", "- Change targets to be within a specific range. In this example, `dog` will remain at `0`, but `cat` will become `1` instead of its original value of `5`." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.084289Z", "iopub.status.busy": "2023-10-27T05:54:05.083662Z", "iopub.status.idle": "2023-10-27T05:54:05.096047Z", "shell.execute_reply": "2023-10-27T05:54:05.095430Z" }, "id": "tFnEoQjgs14I" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
filenamefoldtargetcategoryesc10src_filetake
0./datasets/ESC-50-master/audio/1-100032-A-0.wav10dogTrue100032A
14./datasets/ESC-50-master/audio/1-110389-A-0.wav10dogTrue110389A
157./datasets/ESC-50-master/audio/1-30226-A-0.wav10dogTrue30226A
158./datasets/ESC-50-master/audio/1-30344-A-0.wav10dogTrue30344A
170./datasets/ESC-50-master/audio/1-32318-A-0.wav10dogTrue32318A
175./datasets/ESC-50-master/audio/1-34094-A-5.wav11catFalse34094A
176./datasets/ESC-50-master/audio/1-34094-B-5.wav11catFalse34094B
229./datasets/ESC-50-master/audio/1-47819-A-5.wav11catFalse47819A
230./datasets/ESC-50-master/audio/1-47819-B-5.wav11catFalse47819B
231./datasets/ESC-50-master/audio/1-47819-C-5.wav11catFalse47819C
\n", "
" ], "text/plain": [ " filename fold target category \\\n", "0 ./datasets/ESC-50-master/audio/1-100032-A-0.wav 1 0 dog \n", "14 ./datasets/ESC-50-master/audio/1-110389-A-0.wav 1 0 dog \n", "157 ./datasets/ESC-50-master/audio/1-30226-A-0.wav 1 0 dog \n", "158 ./datasets/ESC-50-master/audio/1-30344-A-0.wav 1 0 dog \n", "170 ./datasets/ESC-50-master/audio/1-32318-A-0.wav 1 0 dog \n", "175 ./datasets/ESC-50-master/audio/1-34094-A-5.wav 1 1 cat \n", "176 ./datasets/ESC-50-master/audio/1-34094-B-5.wav 1 1 cat \n", "229 ./datasets/ESC-50-master/audio/1-47819-A-5.wav 1 1 cat \n", "230 ./datasets/ESC-50-master/audio/1-47819-B-5.wav 1 1 cat \n", "231 ./datasets/ESC-50-master/audio/1-47819-C-5.wav 1 1 cat \n", "\n", " esc10 src_file take \n", "0 True 100032 A \n", "14 True 110389 A \n", "157 True 30226 A \n", "158 True 30344 A \n", "170 True 32318 A \n", "175 False 34094 A \n", "176 False 34094 B \n", "229 False 47819 A \n", "230 False 47819 B \n", "231 False 47819 C " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_classes = ['dog', 'cat']\n", "map_class_to_id = {'dog':0, 'cat':1}\n", "\n", "filtered_pd = pd_data[pd_data.category.isin(my_classes)]\n", "\n", "class_id = filtered_pd['category'].apply(lambda name: map_class_to_id[name])\n", "filtered_pd = filtered_pd.assign(target=class_id)\n", "\n", "full_path = filtered_pd['filename'].apply(lambda row: os.path.join(base_data_path, row))\n", "filtered_pd = filtered_pd.assign(filename=full_path)\n", "\n", "filtered_pd.head(10)" ] }, { "cell_type": "markdown", "metadata": { "id": "BkDcBS-aJdCz" }, "source": [ "### Load the audio files and retrieve embeddings\n", "\n", "Here you'll apply the `load_wav_16k_mono` and prepare the WAV data for the model.\n", "\n", "When extracting embeddings from the WAV data, you get an array of shape `(N, 1024)` where `N` is the number of frames that YAMNet found (one for every 0.48 seconds of audio)." ] }, { "cell_type": "markdown", "metadata": { "id": "AKDT5RomaDKO" }, "source": [ "Your model will use each frame as one input. Therefore, you need to create a new column that has one frame per row. You also need to expand the labels and the `fold` column to proper reflect these new rows.\n", "\n", "The expanded `fold` column keeps the original values. You cannot mix frames because, when performing the splits, you might end up having parts of the same audio on different splits, which would make your validation and test steps less effective." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.099335Z", "iopub.status.busy": "2023-10-27T05:54:05.099114Z", "iopub.status.idle": "2023-10-27T05:54:05.111402Z", "shell.execute_reply": "2023-10-27T05:54:05.110555Z" }, "id": "u5Rq3_PyKLtU" }, "outputs": [ { "data": { "text/plain": [ "(TensorSpec(shape=(), dtype=tf.string, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None))" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "filenames = filtered_pd['filename']\n", "targets = filtered_pd['target']\n", "folds = filtered_pd['fold']\n", "\n", "main_ds = tf.data.Dataset.from_tensor_slices((filenames, targets, folds))\n", "main_ds.element_spec" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.114895Z", "iopub.status.busy": "2023-10-27T05:54:05.114289Z", "iopub.status.idle": "2023-10-27T05:54:05.256661Z", "shell.execute_reply": "2023-10-27T05:54:05.256071Z" }, "id": "rsEfovDVAHGY" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "data": { "text/plain": [ "(TensorSpec(shape=, dtype=tf.float32, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None))" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def load_wav_for_map(filename, label, fold):\n", " return load_wav_16k_mono(filename), label, fold\n", "\n", "main_ds = main_ds.map(load_wav_for_map)\n", "main_ds.element_spec" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.260019Z", "iopub.status.busy": "2023-10-27T05:54:05.259414Z", "iopub.status.idle": "2023-10-27T05:54:05.432291Z", "shell.execute_reply": "2023-10-27T05:54:05.431670Z" }, "id": "k0tG8DBNAHcE" }, "outputs": [ { "data": { "text/plain": [ "(TensorSpec(shape=(1024,), dtype=tf.float32, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None),\n", " TensorSpec(shape=(), dtype=tf.int64, name=None))" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# applies the embedding extraction model to a wav data\n", "def extract_embedding(wav_data, label, fold):\n", " ''' run YAMNet to extract embedding from the wav data '''\n", " scores, embeddings, spectrogram = yamnet_model(wav_data)\n", " num_embeddings = tf.shape(embeddings)[0]\n", " return (embeddings,\n", " tf.repeat(label, num_embeddings),\n", " tf.repeat(fold, num_embeddings))\n", "\n", "# extract embedding\n", "main_ds = main_ds.map(extract_embedding).unbatch()\n", "main_ds.element_spec" ] }, { "cell_type": "markdown", "metadata": { "id": "ZdfPIeD0Qedk" }, "source": [ "### Split the data\n", "\n", "You will use the `fold` column to split the dataset into train, validation and test sets.\n", "\n", "ESC-50 is arranged into five uniformly-sized cross-validation `fold`s, such that clips from the same original source are always in the same `fold` - find out more in the [ESC: Dataset for Environmental Sound Classification](https://www.karolpiczak.com/papers/Piczak2015-ESC-Dataset.pdf) paper.\n", "\n", "The last step is to remove the `fold` column from the dataset since you're not going to use it during training.\n" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.435991Z", "iopub.status.busy": "2023-10-27T05:54:05.435532Z", "iopub.status.idle": "2023-10-27T05:54:05.518530Z", "shell.execute_reply": "2023-10-27T05:54:05.517931Z" }, "id": "1ZYvlFiVsffC" }, "outputs": [], "source": [ "cached_ds = main_ds.cache()\n", "train_ds = cached_ds.filter(lambda embedding, label, fold: fold < 4)\n", "val_ds = cached_ds.filter(lambda embedding, label, fold: fold == 4)\n", "test_ds = cached_ds.filter(lambda embedding, label, fold: fold == 5)\n", "\n", "# remove the folds column now that it's not needed anymore\n", "remove_fold_column = lambda embedding, label, fold: (embedding, label)\n", "\n", "train_ds = train_ds.map(remove_fold_column)\n", "val_ds = val_ds.map(remove_fold_column)\n", "test_ds = test_ds.map(remove_fold_column)\n", "\n", "train_ds = train_ds.cache().shuffle(1000).batch(32).prefetch(tf.data.AUTOTUNE)\n", "val_ds = val_ds.cache().batch(32).prefetch(tf.data.AUTOTUNE)\n", "test_ds = test_ds.cache().batch(32).prefetch(tf.data.AUTOTUNE)" ] }, { "cell_type": "markdown", "metadata": { "id": "v5PaMwvtcAIe" }, "source": [ "## Create your model\n", "\n", "You did most of the work!\n", "Next, define a very simple [Sequential](https://www.tensorflow.org/guide/keras/sequential_model) model with one hidden layer and two outputs to recognize cats and dogs from sounds.\n" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.522080Z", "iopub.status.busy": "2023-10-27T05:54:05.521664Z", "iopub.status.idle": "2023-10-27T05:54:05.767219Z", "shell.execute_reply": "2023-10-27T05:54:05.766572Z" }, "id": "JYCE0Fr1GpN3" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"my_model\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Layer (type) Output Shape Param # \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense (Dense) (None, 512) 524800 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_1 (Dense) (None, 2) 1026 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Total params: 525,826\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Trainable params: 525,826\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Non-trainable params: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] } ], "source": [ "my_model = tf.keras.Sequential([\n", " tf.keras.layers.Input(shape=(1024), dtype=tf.float32,\n", " name='input_embedding'),\n", " tf.keras.layers.Dense(512, activation='relu'),\n", " tf.keras.layers.Dense(len(my_classes))\n", "], name='my_model')\n", "\n", "my_model.summary()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.774050Z", "iopub.status.busy": "2023-10-27T05:54:05.773324Z", "iopub.status.idle": "2023-10-27T05:54:05.786707Z", "shell.execute_reply": "2023-10-27T05:54:05.786068Z" }, "id": "l1qgH35HY0SE" }, "outputs": [], "source": [ "my_model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", " optimizer=\"adam\",\n", " metrics=['accuracy'])\n", "\n", "callback = tf.keras.callbacks.EarlyStopping(monitor='loss',\n", " patience=3,\n", " restore_best_weights=True)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:05.790079Z", "iopub.status.busy": "2023-10-27T05:54:05.789666Z", "iopub.status.idle": "2023-10-27T05:54:10.905865Z", "shell.execute_reply": "2023-10-27T05:54:10.904756Z" }, "id": "T3sj84eOZ3pk" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/Unknown - 4s 4s/step - loss: 0.9121 - accuracy: 0.0625" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 14/Unknown - 4s 4ms/step - loss: 0.7774 - accuracy: 0.7679" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 5s 42ms/step - loss: 0.7971 - accuracy: 0.7750 - val_loss: 1.2405 - val_accuracy: 0.8625\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 1.0615 - accuracy: 0.8750" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - ETA: 0s - loss: 0.5425 - accuracy: 0.8875" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 0s 5ms/step - loss: 0.5425 - accuracy: 0.8875 - val_loss: 0.2145 - val_accuracy: 0.9187\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.1802 - accuracy: 0.9062" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 0s 5ms/step - loss: 0.2448 - accuracy: 0.9021 - val_loss: 0.2020 - val_accuracy: 0.9125\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.2989 - accuracy: 0.7812" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 0s 5ms/step - loss: 0.2630 - accuracy: 0.9000 - val_loss: 0.2601 - val_accuracy: 0.9125\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.5643 - accuracy: 0.8125" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 0s 4ms/step - loss: 0.3721 - accuracy: 0.9146 - val_loss: 0.9568 - val_accuracy: 0.8750\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.6629 - accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - 0s 5ms/step - loss: 0.4284 - accuracy: 0.9167 - val_loss: 0.2955 - val_accuracy: 0.9125\n" ] } ], "source": [ "history = my_model.fit(train_ds,\n", " epochs=20,\n", " validation_data=val_ds,\n", " callbacks=callback)" ] }, { "cell_type": "markdown", "metadata": { "id": "OAbraYKYpdoE" }, "source": [ "Let's run the `evaluate` method on the test data just to be sure there's no overfitting." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:10.910100Z", "iopub.status.busy": "2023-10-27T05:54:10.909461Z", "iopub.status.idle": "2023-10-27T05:54:11.066169Z", "shell.execute_reply": "2023-10-27T05:54:11.065474Z" }, "id": "H4Nh5nec3Sky" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/Unknown - 0s 127ms/step - loss: 0.0970 - accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "5/5 [==============================] - 0s 5ms/step - loss: 0.2311 - accuracy: 0.9062\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Loss: 0.23105616867542267\n", "Accuracy: 0.90625\n" ] } ], "source": [ "loss, accuracy = my_model.evaluate(test_ds)\n", "\n", "print(\"Loss: \", loss)\n", "print(\"Accuracy: \", accuracy)" ] }, { "cell_type": "markdown", "metadata": { "id": "cid-qIrIpqHS" }, "source": [ "You did it!" ] }, { "cell_type": "markdown", "metadata": { "id": "nCKZonrJcXab" }, "source": [ "## Test your model\n", "\n", "Next, try your model on the embedding from the previous test using YAMNet only.\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:11.069966Z", "iopub.status.busy": "2023-10-27T05:54:11.069511Z", "iopub.status.idle": "2023-10-27T05:54:11.103911Z", "shell.execute_reply": "2023-10-27T05:54:11.103146Z" }, "id": "79AFpA3_ctCF" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The main sound is: cat\n" ] } ], "source": [ "scores, embeddings, spectrogram = yamnet_model(testing_wav_data)\n", "result = my_model(embeddings).numpy()\n", "\n", "inferred_class = my_classes[result.mean(axis=0).argmax()]\n", "print(f'The main sound is: {inferred_class}')" ] }, { "cell_type": "markdown", "metadata": { "id": "k2yleeev645r" }, "source": [ "## Save a model that can directly take a WAV file as input\n", "\n", "Your model works when you give it the embeddings as input.\n", "\n", "In a real-world scenario, you'll want to use audio data as a direct input.\n", "\n", "To do that, you will combine YAMNet with your model into a single model that you can export for other applications.\n", "\n", "To make it easier to use the model's result, the final layer will be a `reduce_mean` operation. When using this model for serving (which you will learn about later in the tutorial), you will need the name of the final layer. If you don't define one, TensorFlow will auto-define an incremental one that makes it hard to test, as it will keep changing every time you train the model. When using a raw TensorFlow operation, you can't assign a name to it. To address this issue, you'll create a custom layer that applies `reduce_mean` and call it `'classifier'`.\n" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:11.107678Z", "iopub.status.busy": "2023-10-27T05:54:11.107073Z", "iopub.status.idle": "2023-10-27T05:54:11.111411Z", "shell.execute_reply": "2023-10-27T05:54:11.110761Z" }, "id": "QUVCI2Suunpw" }, "outputs": [], "source": [ "class ReduceMeanLayer(tf.keras.layers.Layer):\n", " def __init__(self, axis=0, **kwargs):\n", " super(ReduceMeanLayer, self).__init__(**kwargs)\n", " self.axis = axis\n", "\n", " def call(self, input):\n", " return tf.math.reduce_mean(input, axis=self.axis)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:11.114511Z", "iopub.status.busy": "2023-10-27T05:54:11.114256Z", "iopub.status.idle": "2023-10-27T05:54:20.714211Z", "shell.execute_reply": "2023-10-27T05:54:20.713444Z" }, "id": "zE_Npm0nzlwc" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:absl:Found untraced functions such as _update_step_xla while saving (showing 1 of 1). These functions will not be directly callable after loading.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: ./dogs_and_cats_yamnet/assets\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: ./dogs_and_cats_yamnet/assets\n" ] } ], "source": [ "saved_model_path = './dogs_and_cats_yamnet'\n", "\n", "input_segment = tf.keras.layers.Input(shape=(), dtype=tf.float32, name='audio')\n", "embedding_extraction_layer = hub.KerasLayer(yamnet_model_handle,\n", " trainable=False, name='yamnet')\n", "_, embeddings_output, _ = embedding_extraction_layer(input_segment)\n", "serving_outputs = my_model(embeddings_output)\n", "serving_outputs = ReduceMeanLayer(axis=0, name='classifier')(serving_outputs)\n", "serving_model = tf.keras.Model(input_segment, serving_outputs)\n", "serving_model.save(saved_model_path, include_optimizer=False)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:20.718070Z", "iopub.status.busy": "2023-10-27T05:54:20.717809Z", "iopub.status.idle": "2023-10-27T05:54:20.855159Z", "shell.execute_reply": "2023-10-27T05:54:20.854269Z" }, "id": "y-0bY5FMme1C" }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.keras.utils.plot_model(serving_model)" ] }, { "cell_type": "markdown", "metadata": { "id": "btHQDN9mqxM_" }, "source": [ "Load your saved model to verify that it works as expected." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:20.858881Z", "iopub.status.busy": "2023-10-27T05:54:20.858600Z", "iopub.status.idle": "2023-10-27T05:54:25.899633Z", "shell.execute_reply": "2023-10-27T05:54:25.898933Z" }, "id": "KkYVpJS72WWB" }, "outputs": [], "source": [ "reloaded_model = tf.saved_model.load(saved_model_path)" ] }, { "cell_type": "markdown", "metadata": { "id": "4BkmvvNzq49l" }, "source": [ "And for the final test: given some sound data, does your model return the correct result?" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:25.903709Z", "iopub.status.busy": "2023-10-27T05:54:25.903453Z", "iopub.status.idle": "2023-10-27T05:54:26.199203Z", "shell.execute_reply": "2023-10-27T05:54:26.198485Z" }, "id": "xeXtD5HO28y-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The main sound is: cat\n" ] } ], "source": [ "reloaded_results = reloaded_model(testing_wav_data)\n", "cat_or_dog = my_classes[tf.math.argmax(reloaded_results)]\n", "print(f'The main sound is: {cat_or_dog}')" ] }, { "cell_type": "markdown", "metadata": { "id": "ZRrOcBYTUgwn" }, "source": [ "If you want to try your new model on a serving setup, you can use the 'serving_default' signature." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:26.203019Z", "iopub.status.busy": "2023-10-27T05:54:26.202384Z", "iopub.status.idle": "2023-10-27T05:54:26.406752Z", "shell.execute_reply": "2023-10-27T05:54:26.406030Z" }, "id": "ycC8zzDSUG2s" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The main sound is: cat\n" ] } ], "source": [ "serving_results = reloaded_model.signatures['serving_default'](testing_wav_data)\n", "cat_or_dog = my_classes[tf.math.argmax(serving_results['classifier'])]\n", "print(f'The main sound is: {cat_or_dog}')\n" ] }, { "cell_type": "markdown", "metadata": { "id": "da7blblCHs8c" }, "source": [ "## (Optional) Some more testing\n", "\n", "The model is ready.\n", "\n", "Let's compare it to YAMNet on the test dataset." ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:26.410675Z", "iopub.status.busy": "2023-10-27T05:54:26.410029Z", "iopub.status.idle": "2023-10-27T05:54:26.885973Z", "shell.execute_reply": "2023-10-27T05:54:26.885289Z" }, "id": "vDf5MASIIN1z" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "./datasets/ESC-50-master/audio/5-203128-A-0.wav\n", "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:Using a while_loop for converting IO>AudioResample cause there is no registered converter for this op.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Waveform values: [-5.1828759e-09 1.5151235e-08 -1.1082188e-08 ... 4.9873297e-03\n", " 5.2141696e-03 4.2495923e-03]\n" ] }, { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "test_pd = filtered_pd.loc[filtered_pd['fold'] == 5]\n", "row = test_pd.sample(1)\n", "filename = row['filename'].item()\n", "print(filename)\n", "waveform = load_wav_16k_mono(filename)\n", "print(f'Waveform values: {waveform}')\n", "_ = plt.plot(waveform)\n", "\n", "display.Audio(waveform, rate=16000)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2023-10-27T05:54:26.889257Z", "iopub.status.busy": "2023-10-27T05:54:26.888990Z", "iopub.status.idle": "2023-10-27T05:54:27.190216Z", "shell.execute_reply": "2023-10-27T05:54:27.189409Z" }, "id": "eYUzFxYJIcE1" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[YAMNet] The main sound is: Animal (0.9544865489006042)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "[Your model] The main sound is: dog (0.999213457107544)\n" ] } ], "source": [ "# Run the model, check the output.\n", "scores, embeddings, spectrogram = yamnet_model(waveform)\n", "class_scores = tf.reduce_mean(scores, axis=0)\n", "top_class = tf.math.argmax(class_scores)\n", "inferred_class = class_names[top_class]\n", "top_score = class_scores[top_class]\n", "print(f'[YAMNet] The main sound is: {inferred_class} ({top_score})')\n", "\n", "reloaded_results = reloaded_model(waveform)\n", "your_top_class = tf.math.argmax(reloaded_results)\n", "your_inferred_class = my_classes[your_top_class]\n", "class_probabilities = tf.nn.softmax(reloaded_results, axis=-1)\n", "your_top_score = class_probabilities[your_top_class]\n", "print(f'[Your model] The main sound is: {your_inferred_class} ({your_top_score})')" ] }, { "cell_type": "markdown", "metadata": { "id": "g8Tsym8Rq-0V" }, "source": [ "## Next steps\n", "\n", "You have created a model that can classify sounds from dogs or cats. With the same idea and a different dataset you can try, for example, building an [acoustic identifier of birds](https://www.kaggle.com/c/birdclef-2021/) based on their singing.\n", "\n", "Share your project with the TensorFlow team on social media!\n" ] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "transfer_learning_audio.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.18" } }, "nbformat": 4, "nbformat_minor": 0 }