{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":9695886,"sourceType":"datasetVersion","datasetId":5925315},{"sourceId":9696045,"sourceType":"datasetVersion","datasetId":5928523}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-22T20:01:00.672855Z","iopub.execute_input":"2024-10-22T20:01:00.673406Z","iopub.status.idle":"2024-10-22T20:01:01.252542Z","shell.execute_reply.started":"2024-10-22T20:01:00.673349Z","shell.execute_reply":"2024-10-22T20:01:01.251313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install birdnet --user","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:01:01.255172Z","iopub.execute_input":"2024-10-22T20:01:01.255909Z","iopub.status.idle":"2024-10-22T20:01:52.814566Z","shell.execute_reply.started":"2024-10-22T20:01:01.255848Z","shell.execute_reply":"2024-10-22T20:01:52.812849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from birdnet import SpeciesPredictions, predict_species_within_audio_file","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:01:52.816950Z","iopub.execute_input":"2024-10-22T20:01:52.817489Z","iopub.status.idle":"2024-10-22T20:02:00.473531Z","shell.execute_reply.started":"2024-10-22T20:01:52.817434Z","shell.execute_reply":"2024-10-22T20:02:00.471978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path\nimport soundfile as sf\nimport numpy as np\nfrom birdnet import SpeciesPredictions, predict_species_within_audio_file\n\ndef convert_to_mono(audio_path):\n    \"\"\"\n    Load an audio file and convert it to mono if necessary.\n    Returns the mono audio data and sample rate.\n    \"\"\"\n    print(f\"Reading audio file from: {audio_path}\")\n    audio_data, sample_rate = sf.read(audio_path)\n    \n    print(f\"Audio shape: {audio_data.shape}\")\n    print(f\"Sample rate: {sample_rate}\")\n    \n    if len(audio_data.shape) > 1:\n        print(\"Converting stereo to mono...\")\n        # Convert to mono by averaging channels\n        mono_audio = np.mean(audio_data, axis=1)\n    else:\n        print(\"Audio is already mono\")\n        mono_audio = audio_data\n    \n    temp_path = Path('/kaggle/working') / f\"temp_mono_{audio_path.name}\"\n    print(f\"Saving temporary mono file to: {temp_path}\")\n    sf.write(temp_path, mono_audio, sample_rate)\n    \n    return temp_path\n\ntry:\n    audio_path = Path(\"/kaggle/input/bird-sound/XC101288.ogg\")\n    \n    mono_audio_path = convert_to_mono(audio_path)\n    \n    print(\"Processing with BirdNET...\")\n    predictions = SpeciesPredictions(predict_species_within_audio_file(mono_audio_path))\n    \n    prediction, confidence = list(predictions[(0.0, 3.0)].items())[0]\n    print(f\"predicted '{prediction}' with a confidence of {confidence:.2f}\")\n    \n    mono_audio_path.unlink()\n    print(\"Temporary file cleaned up\")\n    \nexcept Exception as e:\n    print(f\"An error occurred: {str(e)}\")\n    import traceback\n    print(\"Full error traceback:\")\n    print(traceback.format_exc())","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:02:00.477376Z","iopub.execute_input":"2024-10-22T20:02:00.478533Z","iopub.status.idle":"2024-10-22T20:02:23.070375Z","shell.execute_reply.started":"2024-10-22T20:02:00.478467Z","shell.execute_reply":"2024-10-22T20:02:23.067982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prediction, confidence = list(predictions[(0.0, 3.0)].items())[0]\nprint(f\"predicted '{prediction}' with a confidence of {confidence:.2f}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:02:23.077126Z","iopub.execute_input":"2024-10-22T20:02:23.077537Z","iopub.status.idle":"2024-10-22T20:02:23.089726Z","shell.execute_reply.started":"2024-10-22T20:02:23.077496Z","shell.execute_reply":"2024-10-22T20:02:23.088254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Testing Out the TFLite version","metadata":{}},{"cell_type":"code","source":"!pip install tensorflow-model-optimization","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:02:23.091354Z","iopub.execute_input":"2024-10-22T20:02:23.091865Z","iopub.status.idle":"2024-10-22T20:02:38.257838Z","shell.execute_reply.started":"2024-10-22T20:02:23.091806Z","shell.execute_reply":"2024-10-22T20:02:38.256109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\n\n\ndef estimate_model_memory_usage(tflite_model_path):\n    \"\"\"\n    Estimate the memory requirements of a TFLite model.\n\n    Args:\n        tflite_model_path (str): Path to the TFLite model file\n\n    Returns:\n        dict: Dictionary containing memory estimates\n    \"\"\"\n    with open(tflite_model_path, 'rb') as f:\n        model_content = f.read()\n\n    interpreter = tf.lite.Interpreter(model_content=model_content)\n    interpreter.allocate_tensors()\n\n    input_details = interpreter.get_input_details()\n    output_details = interpreter.get_output_details()\n    tensor_details = interpreter.get_tensor_details()\n\n    # Calculate input tensors memory\n    input_memory = 0\n    for tensor in input_details:\n        shape = np.prod(tensor['shape'])  # Multiply all shape dimensions\n        dtype_size = np.dtype(tensor['dtype']).itemsize\n        input_memory += shape * dtype_size\n\n    # Calculate output tensors memory\n    output_memory = 0\n    for tensor in output_details:\n        shape = np.prod(tensor['shape'])\n        dtype_size = np.dtype(tensor['dtype']).itemsize\n        output_memory += shape * dtype_size\n\n    # Calculate total model size\n    model_size = len(model_content)\n\n    # Calculate tensor arena size (approximate)\n    tensor_arena_size = 0\n    for tensor in tensor_details:\n        shape = np.prod(tensor['shape'])\n        dtype_size = np.dtype(tensor['dtype']).itemsize\n        tensor_arena_size += shape * dtype_size\n\n    memory_info = {\n        'input_memory_bytes': input_memory,\n        'output_memory_bytes': output_memory,\n        'model_size_bytes': model_size,\n        'tensor_arena_size_bytes': tensor_arena_size,\n        'total_estimated_memory': input_memory + output_memory + tensor_arena_size\n    }\n\n    print(f\"Model Size: {(model_size / 1024)/1000:.2f} MB\")\n    print(f\"Input Tensors Memory: {input_memory / 1024:.2f} KB\")\n    print(f\"Output Tensors Memory: {output_memory / 1024:.2f} KB\")\n    print(f\"Tensor Arena Size: {(tensor_arena_size / 1024)/1000:.2f} MB\")\n    print(f\"Total Estimated Memory: {((input_memory + output_memory + tensor_arena_size) / 1024)/1000:.2f} MB\")\n\n    return memory_info\n\n\nif __name__ == \"__main__\":\n    memory_info = estimate_model_memory_usage('/kaggle/input/birdnet-tflite/BirdNET_GLOBAL_6K_V2.4_MData_Model_V2_FP16.tflite')","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:05:42.092406Z","iopub.execute_input":"2024-10-22T20:05:42.092975Z","iopub.status.idle":"2024-10-22T20:05:42.254940Z","shell.execute_reply.started":"2024-10-22T20:05:42.092926Z","shell.execute_reply":"2024-10-22T20:05:42.253394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model requirements VS ESP32 stats\n\n**Your ESP32 has:**\\\nSRAM: 400KB\\\nROM: 384KB\\\nFlash memory: 4MB (4096KB)\\\n\\\n\\\n\\\n**Your model requires:**\\\nModel Size (stored in Flash): 14,424.29 KB\\\n\\\nRuntime Memory (SRAM) needs:\\\nInput Memory: 0.01 KB\\\nOutput Memory: 25.48 KB\\\nTensor Arena: 43,297.58 KB\\\nTotal Runtime Memory: 43,323.06 KB\\\n\\\n\\\n\\\n**Memory Overflow Analysis:**\\\n\\\n**Flash Memory Overflow:**\\\nRequired: 14,424.29 KB\\\nAvailable: 4,096 KB\\\nOverflow: 10,328.29 KB (needs ~3.5x reduction)\\\n\\\n\\\n**SRAM Overflow:**\\\nRequired: 43,323.06 KB\\\nAvailable: 400 KB\\\nOverflow: 42,923.06 KB (needs ~108x reduction)\\\n\n***TLDR: THE ESP32 will literally fry itself if it tries to run this model***","metadata":{}},{"cell_type":"markdown","source":"# TBD: OPTIMIZE THE TFLITE MODEL\n**Code below doesn't work FML so much for AI**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport os\nimport soundfile as sf\nimport tensorflow_model_optimization as tfmot\nfrom typing import Dict, List, Union\nimport logging\n\n# Set up logging\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\nclass BirdNETOptimizer:\n    def __init__(self, original_model_path: str):\n        \"\"\"\n        Initialize the optimizer with the original BirdNET TFLite model\n        \n        Args:\n            original_model_path: Path to the original BirdNET TFLite model\n        \"\"\"\n        self.original_model_path = original_model_path\n        self.sample_rate = 48000  # BirdNET's expected sample rate\n        self.window_size = 48000  # 1 second window\n        \n        # Verify the model file exists\n        if not os.path.exists(original_model_path):\n            raise FileNotFoundError(f\"Model file not found: {original_model_path}\")\n        logger.info(f\"Found model file at: {original_model_path}\")\n        \n    def load_and_preprocess_audio(self, audio_path: str) -> np.ndarray:\n        \"\"\"Load and preprocess audio file for model validation\"\"\"\n        try:\n            audio, _ = sf.read(audio_path)\n            if len(audio.shape) > 1:\n                audio = np.mean(audio, axis=1)\n            return audio\n        except Exception as e:\n            logger.error(f\"Error loading audio file {audio_path}: {str(e)}\")\n            raise\n        \n    def generate_representative_dataset(self, calibration_audio_paths: List[str]):\n        \"\"\"Generate representative dataset for quantization\"\"\"\n        def representative_dataset():\n            for audio_path in calibration_audio_paths:\n                try:\n                    logger.info(f\"Processing calibration audio: {audio_path}\")\n                    audio = self.load_and_preprocess_audio(audio_path)\n                    # Process audio in 1-second windows\n                    for i in range(0, len(audio) - self.window_size, self.window_size):\n                        window = audio[i:i + self.window_size]\n                        # Apply BirdNET's preprocessing (mel-spectrogram conversion)\n                        spec = self.create_melspectrogram(window)\n                        yield [spec.reshape(1, 48, 48, 1).astype(np.float32)]\n                except Exception as e:\n                    logger.error(f\"Error processing calibration audio {audio_path}: {str(e)}\")\n                    continue\n        return representative_dataset\n\n    def optimize_model(self, \n                      output_path: str,\n                      calibration_audio_paths: List[str],\n                      validate_audio_path: str = None) -> Dict:\n        \"\"\"\n        Optimize the BirdNET model for ESP32\n        \"\"\"\n        try:\n            logger.info(\"Starting model optimization...\")\n            \n            # Create interpreter from the original model\n            interpreter = tf.lite.Interpreter(model_path=self.original_model_path)\n            interpreter.allocate_tensors()\n            logger.info(\"Successfully loaded original model\")\n            \n            # Create converter\n            converter = tf.lite.TFLiteConverter.from_saved_model(\"/kaggle/input/birdnet-tflite\")\n            logger.info(\"Created TFLite converter\")\n            \n            # Enable quantization\n            converter.optimizations = [tf.lite.Optimize.DEFAULT]\n            \n            # Configure full integer quantization with float fallback\n            converter.target_spec.supported_ops = [\n                tf.lite.OpsSet.TFLITE_BUILTINS_INT8,\n                tf.lite.OpsSet.TFLITE_BUILTINS\n            ]\n            \n            # Set representative dataset\n            logger.info(\"Setting up representative dataset...\")\n            converter.representative_dataset = self.generate_representative_dataset(calibration_audio_paths)\n            \n            # Convert model\n            logger.info(\"Starting model conversion...\")\n            try:\n                optimized_model = converter.convert()\n                logger.info(\"Model conversion successful\")\n            except Exception as e:\n                logger.error(f\"Error during model conversion: {str(e)}\")\n                raise\n            \n            # Create output directory if it doesn't exist\n            os.makedirs(os.path.dirname(output_path), exist_ok=True)\n            \n            # Save optimized model\n            logger.info(f\"Saving optimized model to {output_path}\")\n            try:\n                with open(output_path, 'wb') as f:\n                    f.write(optimized_model)\n                logger.info(\"Model saved successfully\")\n            except Exception as e:\n                logger.error(f\"Error saving model: {str(e)}\")\n                raise\n                \n            # Calculate memory requirements\n            logger.info(\"Calculating memory requirements...\")\n            memory_info = self.analyze_model_memory(output_path)\n            \n            # Validate if test audio provided\n            accuracy_info = {}\n            if validate_audio_path:\n                logger.info(\"Validating optimized model...\")\n                accuracy_info = self.validate_model(output_path, validate_audio_path)\n                \n            return {\n                'memory_info': memory_info,\n                'accuracy_info': accuracy_info\n            }\n            \n        except Exception as e:\n            logger.error(f\"Error in optimize_model: {str(e)}\")\n            raise\n\n    def analyze_model_memory(self, model_path: str) -> Dict:\n        \"\"\"Analyze memory requirements of the model\"\"\"\n        interpreter = tf.lite.Interpreter(model_path=model_path)\n        interpreter.allocate_tensors()\n\n        # Calculate memory requirements\n        input_details = interpreter.get_input_details()\n        output_details = interpreter.get_output_details()\n\n        input_memory = sum(detail['shape'].size * detail['dtype'].itemsize\n                           for detail in input_details)\n        output_memory = sum(detail['shape'].size * detail['dtype'].itemsize\n                            for detail in output_details)\n\n        model_size = os.path.getsize(model_path)\n\n        return {\n            'model_size_kb': model_size / 1024,\n            'runtime_memory_kb': (input_memory + output_memory) / 1024,\n            'total_memory_kb': (model_size + input_memory + output_memory) / 1024\n        }\n\n    def validate_model(self, model_path: str, audio_path: str) -> Dict:\n        \"\"\"Validate the optimized model against the original\"\"\"\n        # Load both models\n        original_interpreter = tf.lite.Interpreter(model_path=self.original_model_path)\n        optimized_interpreter = tf.lite.Interpreter(model_path=model_path)\n\n        original_interpreter.allocate_tensors()\n        optimized_interpreter.allocate_tensors()\n\n        # Load and preprocess test audio\n        audio = self.load_and_preprocess_audio(audio_path)\n        spec = self.create_melspectrogram(audio[:self.window_size])\n        input_data = spec.reshape(1, 48, 48, 1)\n\n        # Get predictions from both models\n        original_output = self.get_model_prediction(original_interpreter, input_data)\n        optimized_output = self.get_model_prediction(optimized_interpreter, input_data)\n\n        # Calculate correlation between predictions\n        correlation = np.corrcoef(original_output.flatten(),\n                                  optimized_output.flatten())[0, 1]\n\n        return {\n            'prediction_correlation': correlation,\n            'original_top5': np.argsort(original_output.flatten())[-5:],\n            'optimized_top5': np.argsort(optimized_output.flatten())[-5:]\n        }\n\n    def get_model_prediction(self, interpreter, input_data):\n        \"\"\"Get prediction from model interpreter\"\"\"\n        input_details = interpreter.get_input_details()\n        output_details = interpreter.get_output_details()\n\n        interpreter.set_tensor(input_details[0]['index'], input_data.astype(np.float32))\n        interpreter.invoke()\n        return interpreter.get_tensor(output_details[0]['index'])\n\n\n# Example usage\nif __name__ == \"__main__\":\n    try:\n        # Check if running in Kaggle environment\n        in_kaggle = os.path.exists('/kaggle/input')\n        \n        if in_kaggle:\n            # Kaggle paths\n            model_path = '/kaggle/input/birdnet-tflite/BirdNET_GLOBAL_6K_V2.4_MData_Model_V2_FP16.tflite'\n            output_dir = '/kaggle/working'\n            calibration_folder = '/kaggle/input/bird-sound'  # Update this to your actual dataset path\n            output_path = os.path.join(output_dir, 'BirdNET_ESP32_Optimized.tflite')\n        else:\n            # Local paths\n            model_path = './models/BirdNET_GLOBAL_6K_V2.4_MData_Model_V2_FP16.tflite'\n            calibration_folder = './calibration_audio'\n            output_path = './models/BirdNET_ESP32_Optimized.tflite'\n        \n        logger.info(f\"Using model path: {model_path}\")\n        logger.info(f\"Using calibration folder: {calibration_folder}\")\n        \n        optimizer = BirdNETOptimizer(model_path)\n        \n        # Get all audio files from the folder\n        calibration_audio_paths = []\n        for file in os.listdir(calibration_folder):\n            if file.lower().endswith(('.wav', '.mp3', '.ogg', '.flac')):\n                full_path = os.path.join(calibration_folder, file)\n                calibration_audio_paths.append(full_path)\n        \n        if not calibration_audio_paths:\n            raise ValueError(f\"No audio files found in {calibration_folder}\")\n        \n        logger.info(f\"Found {len(calibration_audio_paths)} audio files for calibration\")\n        \n        try:\n            results = optimizer.optimize_model(\n                output_path=output_path,\n                calibration_audio_paths=calibration_audio_paths,\n                validate_audio_path='./test_audio/test_recording.wav'\n            )\n            \n            print(\"\\nOptimization Results:\")\n            print(f\"Model Size: {results['memory_info']['model_size_kb']:.2f} KB\")\n            print(f\"Runtime Memory: {results['memory_info']['runtime_memory_kb']:.2f} KB\")\n            print(f\"Total Memory: {results['memory_info']['total_memory_kb']:.2f} KB\")\n            \n            if results['accuracy_info']:\n                print(f\"\\nValidation Results:\")\n                print(f\"Prediction Correlation: {results['accuracy_info']['prediction_correlation']:.4f}\")\n                print(\"Original Top 5 Classes:\", results['accuracy_info']['original_top5'])\n                print(\"Optimized Top 5 Classes:\", results['accuracy_info']['optimized_top5'])\n                \n        except Exception as e:\n            logger.error(f\"Error during model optimization: {str(e)}\")\n            raise\n        \n    except Exception as e:\n        logger.error(f\"An error occurred: {str(e)}\")\n        raise","metadata":{"execution":{"iopub.status.busy":"2024-10-22T20:14:49.527238Z","iopub.execute_input":"2024-10-22T20:14:49.527848Z","iopub.status.idle":"2024-10-22T20:14:49.897015Z","shell.execute_reply.started":"2024-10-22T20:14:49.527799Z","shell.execute_reply":"2024-10-22T20:14:49.895199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CHATGPT CODE FOR ESP32 ","metadata":{}},{"cell_type":"markdown","source":"**Folder Structure**","metadata":{}},{"cell_type":"code","source":"/project_directory\n├── models\n│   ├── BirdNET_6K_GLOBAL_MODEL.tflite\n│   └── BirdNET_GLOBAL_6K_V2.4_MData_Model_V2_FP16.tflite\n├── main.cpp (or main.ino if using Arduino IDE)\n└── other_project_files","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Convert the Model File to a Byte Array**","metadata":{}},{"cell_type":"code","source":"# Python script to convert the .tflite file to a C array\ndef convert_model_to_c_array(model_path, output_path):\n    with open(model_path, \"rb\") as model_file:\n        model_data = model_file.read()\n\n    with open(output_path, \"w\") as output_file:\n        output_file.write(f\"const unsigned char model_data[] = {{\\n\")\n        for i, byte in enumerate(model_data):\n            if i % 12 == 0:\n                output_file.write(\"\\n  \")\n            output_file.write(f\"0x{byte:02X}, \")\n        output_file.write(\"\\n};\\n\")\n        output_file.write(f\"const int model_data_len = {len(model_data)};\\n\")\n\n# Example usage\nconvert_model_to_c_array(\"models/BirdNET_GLOBAL_6K_V2.4_MData_Model_V2_FP16.tflite\", \n                         \"model_data.h\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**SETUP MAIN.CPP**","metadata":{}},{"cell_type":"code","source":"#include <TensorFlowLite.h>\n#include \"model_data.h\"  // Include the generated C array model data\n\n#include \"tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h\"\n#include \"tensorflow/lite/experimental/micro/micro_error_reporter.h\"\n#include \"tensorflow/lite/experimental/micro/micro_interpreter.h\"\n#include \"tensorflow/lite/experimental/micro/micro_mutable_op_resolver.h\"\n#include \"tensorflow/lite/schema/schema_generated.h\"\n\n\nnamespace {\n    tflite::MicroErrorReporter micro_error_reporter;\n    tflite::ErrorReporter* error_reporter = &micro_error_reporter;\n    const tflite::Model* model = nullptr;\n    tflite::MicroInterpreter* interpreter = nullptr;\n    TfLiteTensor* input = nullptr;\n    TfLiteTensor* output = nullptr;\n\n    // Memory allocation for input, output, and intermediate arrays\n    constexpr int kTensorArenaSize = 10 * 1024;\n    uint8_t tensor_arena[kTensorArenaSize];\n}\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"void setup() {\n    Serial.begin(115200);\n\n    // Load the model from the C array\n    model = tflite::GetModel(model_data);\n    if (model->version() != TFLITE_SCHEMA_VERSION) {\n        error_reporter->Report(\"Model version does not match Schema\");\n        return;\n    }\n\n    // Set up the operation resolver\n    static tflite::MicroMutableOpResolver<10> micro_op_resolver;\n    micro_op_resolver.AddBuiltin(tflite::BuiltinOperator_FULLY_CONNECTED,\n                                 tflite::ops::micro::Register_FULLY_CONNECTED());\n    micro_op_resolver.AddBuiltin(tflite::BuiltinOperator_SOFTMAX,\n                                 tflite::ops::micro::Register_SOFTMAX());\n\n    // Set up the interpreter\n    static tflite::MicroInterpreter static_interpreter(\n        model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter);\n    interpreter = &static_interpreter;\n\n    // Allocate memory for the model's tensors\n    if (interpreter->AllocateTensors() != kTfLiteOk) {\n        error_reporter->Report(\"AllocateTensors() failed\");\n        return;\n    }\n\n    // Get pointers to the input and output tensors\n    input = interpreter->input(0);\n    output = interpreter->output(0);\n    error_reporter->Report(\"Setup complete, ready to run inference.\");\n}\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Run inference in the loop() function**","metadata":{}},{"cell_type":"code","source":"void loop() {\n    // Example: populate the input tensor with test data (replace with actual audio data processing)\n    for (int i = 0; i < input->dims->data[0]; i++) {\n        input->data.f[i] = 0.0f; // Replace with actual preprocessed audio data\n    }\n\n    // Run inference\n    if (interpreter->Invoke() != kTfLiteOk) {\n        error_reporter->Report(\"Invoke failed\");\n        return;\n    }\n\n    // Read the output\n    float* output_data = output->data.f;\n    float confidence = output_data[0]; // Example usage, adjust based on actual model output\n\n    // Output results (for debugging)\n    Serial.printf(\"Inference result: %.2f\\n\", confidence);\n    delay(1000);\n}","metadata":{},"execution_count":null,"outputs":[]}]}