{ "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": "2024-08-16T07:49:32.384401Z", "iopub.status.busy": "2024-08-16T07:49:32.384186Z", "iopub.status.idle": "2024-08-16T07:49:32.387925Z", "shell.execute_reply": "2024-08-16T07:49:32.387353Z" }, "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": "2024-08-16T07:49:32.391331Z", "iopub.status.busy": "2024-08-16T07:49:32.391105Z", "iopub.status.idle": "2024-08-16T07:50:04.250667Z", "shell.execute_reply": "2024-08-16T07:50:04.249596Z" }, "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.15.0 requires protobuf<4.21,>=3.20.3; python_version < \"3.11\", but you have protobuf 3.19.6 which is incompatible.\r\n", "tf-keras 2.17.0 requires tensorflow<2.18,>=2.17, but you have tensorflow 2.11.1 which is incompatible.\u001b[0m\u001b[31m\r\n", "\u001b[0m" ] }, { "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", "tf-keras 2.17.0 requires tensorflow<2.18,>=2.17, but you have tensorflow 2.11.1 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": "2024-08-16T07:50:04.254963Z", "iopub.status.busy": "2024-08-16T07:50:04.254666Z", "iopub.status.idle": "2024-08-16T07:50:06.716149Z", "shell.execute_reply": "2024-08-16T07:50:06.715446Z" }, "id": "7l3nqdWVF-kC" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-08-16 07:50:05.130184: 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": [ "2024-08-16 07:50:05.790784: 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", "2024-08-16 07:50:05.790880: 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", "2024-08-16 07:50:05.790890: 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": "2024-08-16T07:50:06.720287Z", "iopub.status.busy": "2024-08-16T07:50:06.719840Z", "iopub.status.idle": "2024-08-16T07:50:11.698005Z", "shell.execute_reply": "2024-08-16T07:50:11.697273Z" }, "id": "06CWkBV5v3gr" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-08-16 07:50:08.202191: 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", "2024-08-16 07:50:08.202307: 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", "2024-08-16 07:50:08.202368: 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", "2024-08-16 07:50:08.202426: 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", "2024-08-16 07:50:08.258250: 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", "2024-08-16 07:50:08.258451: 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": "2024-08-16T07:50:11.702570Z", "iopub.status.busy": "2024-08-16T07:50:11.702302Z", "iopub.status.idle": "2024-08-16T07:50:11.811422Z", "shell.execute_reply": "2024-08-16T07:50:11.810773Z" }, "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": "2024-08-16T07:50:11.814583Z", "iopub.status.busy": "2024-08-16T07:50:11.814341Z", "iopub.status.idle": "2024-08-16T07:50:11.819324Z", "shell.execute_reply": "2024-08-16T07:50:11.818652Z" }, "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": "2024-08-16T07:50:11.822192Z", "iopub.status.busy": "2024-08-16T07:50:11.821959Z", "iopub.status.idle": "2024-08-16T07:50:12.727924Z", "shell.execute_reply": "2024-08-16T07:50:12.727244Z" }, "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": "2024-08-16T07:50:12.731557Z", "iopub.status.busy": "2024-08-16T07:50:12.731307Z", "iopub.status.idle": "2024-08-16T07:50:12.747972Z", "shell.execute_reply": "2024-08-16T07:50:12.747289Z" }, "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": "2024-08-16T07:50:12.751819Z", "iopub.status.busy": "2024-08-16T07:50:12.751242Z", "iopub.status.idle": "2024-08-16T07:50:13.035232Z", "shell.execute_reply": "2024-08-16T07:50:13.034415Z" }, "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": "2024-08-16T07:50:13.039340Z", "iopub.status.busy": "2024-08-16T07:50:13.038651Z", "iopub.status.idle": "2024-08-16T07:50:59.494905Z", "shell.execute_reply": "2024-08-16T07:50:59.494073Z" }, "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": "2024-08-16T07:50:59.499315Z", "iopub.status.busy": "2024-08-16T07:50:59.499033Z", "iopub.status.idle": "2024-08-16T07:50:59.512237Z", "shell.execute_reply": "2024-08-16T07:50:59.511604Z" }, "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": "2024-08-16T07:50:59.515716Z", "iopub.status.busy": "2024-08-16T07:50:59.515159Z", "iopub.status.idle": "2024-08-16T07:50:59.528342Z", "shell.execute_reply": "2024-08-16T07:50:59.527769Z" }, "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": "2024-08-16T07:50:59.531772Z", "iopub.status.busy": "2024-08-16T07:50:59.531177Z", "iopub.status.idle": "2024-08-16T07:50:59.542994Z", "shell.execute_reply": "2024-08-16T07:50:59.542395Z" }, "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": "2024-08-16T07:50:59.546293Z", "iopub.status.busy": "2024-08-16T07:50:59.545725Z", "iopub.status.idle": "2024-08-16T07:50:59.683862Z", "shell.execute_reply": "2024-08-16T07:50:59.683193Z" }, "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": "2024-08-16T07:50:59.687209Z", "iopub.status.busy": "2024-08-16T07:50:59.686616Z", "iopub.status.idle": "2024-08-16T07:50:59.858117Z", "shell.execute_reply": "2024-08-16T07:50:59.857512Z" }, "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": "2024-08-16T07:50:59.861591Z", "iopub.status.busy": "2024-08-16T07:50:59.860989Z", "iopub.status.idle": "2024-08-16T07:50:59.942555Z", "shell.execute_reply": "2024-08-16T07:50:59.941901Z" }, "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": "2024-08-16T07:50:59.946354Z", "iopub.status.busy": "2024-08-16T07:50:59.945765Z", "iopub.status.idle": "2024-08-16T07:50:59.994118Z", "shell.execute_reply": "2024-08-16T07:50:59.993410Z" }, "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": "2024-08-16T07:50:59.999565Z", "iopub.status.busy": "2024-08-16T07:50:59.999084Z", "iopub.status.idle": "2024-08-16T07:51:00.012586Z", "shell.execute_reply": "2024-08-16T07:51:00.011992Z" }, "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": "2024-08-16T07:51:00.016205Z", "iopub.status.busy": "2024-08-16T07:51:00.015727Z", "iopub.status.idle": "2024-08-16T07:51:05.236993Z", "shell.execute_reply": "2024-08-16T07:51:05.236285Z" }, "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.7612 - accuracy: 0.4688" ] }, { "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.8120 - accuracy: 0.8482" ] }, { "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 41ms/step - loss: 0.7740 - accuracy: 0.8479 - val_loss: 0.2178 - val_accuracy: 0.9125\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.0733 - 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\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "15/15 [==============================] - ETA: 0s - loss: 0.2999 - accuracy: 0.8917" ] }, { "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.2999 - accuracy: 0.8917 - val_loss: 0.1892 - 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.2268 - 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 5ms/step - loss: 0.3008 - accuracy: 0.8958 - val_loss: 0.2612 - val_accuracy: 0.9187\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/20\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/15 [=>............................] - ETA: 0s - loss: 0.1377 - accuracy: 0.9688" ] }, { "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.4578 - accuracy: 0.9187 - val_loss: 0.2650 - 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.1726 - 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.7745 - accuracy: 0.9187 - val_loss: 1.2726 - val_accuracy: 0.8750\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": "2024-08-16T07:51:05.241173Z", "iopub.status.busy": "2024-08-16T07:51:05.240522Z", "iopub.status.idle": "2024-08-16T07:51:05.396368Z", "shell.execute_reply": "2024-08-16T07:51:05.395694Z" }, "id": "H4Nh5nec3Sky" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/Unknown - 0s 126ms/step - loss: 0.2066 - 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\r", "5/5 [==============================] - 0s 5ms/step - loss: 0.2313 - accuracy: 0.8875\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Loss: 0.23130321502685547\n", "Accuracy: 0.887499988079071\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": "2024-08-16T07:51:05.400243Z", "iopub.status.busy": "2024-08-16T07:51:05.399645Z", "iopub.status.idle": "2024-08-16T07:51:05.435290Z", "shell.execute_reply": "2024-08-16T07:51:05.434260Z" }, "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": "2024-08-16T07:51:05.439252Z", "iopub.status.busy": "2024-08-16T07:51:05.438627Z", "iopub.status.idle": "2024-08-16T07:51:05.443112Z", "shell.execute_reply": "2024-08-16T07:51:05.442362Z" }, "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": "2024-08-16T07:51:05.446747Z", "iopub.status.busy": "2024-08-16T07:51:05.446130Z", "iopub.status.idle": "2024-08-16T07:51:15.010478Z", "shell.execute_reply": "2024-08-16T07:51:15.009684Z" }, "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": "2024-08-16T07:51:15.014940Z", "iopub.status.busy": "2024-08-16T07:51:15.014649Z", "iopub.status.idle": "2024-08-16T07:51:15.156430Z", "shell.execute_reply": "2024-08-16T07:51:15.155108Z" }, "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": "2024-08-16T07:51:15.161011Z", "iopub.status.busy": "2024-08-16T07:51:15.160428Z", "iopub.status.idle": "2024-08-16T07:51:20.187458Z", "shell.execute_reply": "2024-08-16T07:51:20.186733Z" }, "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": "2024-08-16T07:51:20.191625Z", "iopub.status.busy": "2024-08-16T07:51:20.191377Z", "iopub.status.idle": "2024-08-16T07:51:20.480407Z", "shell.execute_reply": "2024-08-16T07:51:20.479528Z" }, "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": "2024-08-16T07:51:20.484508Z", "iopub.status.busy": "2024-08-16T07:51:20.483890Z", "iopub.status.idle": "2024-08-16T07:51:20.687532Z", "shell.execute_reply": "2024-08-16T07:51:20.686494Z" }, "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": "2024-08-16T07:51:20.691623Z", "iopub.status.busy": "2024-08-16T07:51:20.691089Z", "iopub.status.idle": "2024-08-16T07:51:21.155976Z", "shell.execute_reply": "2024-08-16T07:51:21.155227Z" }, "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": "2024-08-16T07:51:21.159482Z", "iopub.status.busy": "2024-08-16T07:51:21.159224Z", "iopub.status.idle": "2024-08-16T07:51:21.459287Z", "shell.execute_reply": "2024-08-16T07:51:21.458558Z" }, "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.9998296499252319)\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.19" } }, "nbformat": 4, "nbformat_minor": 0 }