Patrick Baumgartner 2 yıl önce
ebeveyn
işleme
0146325fa9

+ 12 - 0
trainer/components/callbacks/hotwords_callbacks.py

@@ -51,3 +51,15 @@ def register_hotwords_callbacks(app):
             return HotwordsLayout()
 
         return html.Div()
+
+    @app.callback(
+        Output('data-table-body', 'children'),
+        [Input('data-table-pagination', 'active_page')],
+        [State('url', 'pathname')]
+    )
+    def update_table(page, pathname):
+        model_name = pathname.split('/')[-1]
+        filepath = f"{TRAINING_HOTWORD_DIR}/{model_name}/"
+        training_data = list_files_in_directory(filepath, ".wav")
+        rows = generate_training_data_table(model_name, training_data, page, page_size=10)
+        return rows

+ 137 - 76
trainer/components/hotwords.py

@@ -1,11 +1,12 @@
-from dash import html, dcc
+from dash import html, dcc, callback_context, dash_table
 import dash_bootstrap_components as dbc
-from utils.file_utils import list_directories_in_directory, list_files_in_directory, get_file_metadata, get_training_time, get_file_size, trainer_classes
-import json
+from dash.dependencies import Input, Output, State
+from utils.file_utils import list_directories_in_directory, list_files_in_directory, get_file_metadata, get_training_time, get_file_size, trainer_classes, get_Size_String
 import os
+import json
+import plotly.graph_objs as go
 
 TRAINING_HOTWORD_DIR = './training/hotword/'
-MODEL_DIR = './model/hotword/'
 
 def HotwordsLayout():
     hotword_models = list_directories_in_directory(TRAINING_HOTWORD_DIR)
@@ -36,27 +37,107 @@ def generate_model_table(models):
     return dbc.Table(header + [html.Tbody(rows)], bordered=True, hover=True)
 
 def ManageHotwordLayout(model_name):
+    page_size = 10
     training_data = list_files_in_directory(f"{TRAINING_HOTWORD_DIR}/{model_name}/", ".wav")
-    training_data_table = generate_training_data_table(model_name, training_data)
+    training_data_table, row_count = generate_training_data_table(model_name, training_data, 1, page_size)
+    trainer_options = [{'label': name, 'value': name} for name in trainer_classes.keys()]
 
-    model_info = generate_model_info(model_name)
+    training_time = get_training_time(model_name)
+    
+    tab_trainer = []
+    for trainer_info in trainer_options:
+        infoFile = f"./model/hotword/{model_name}/info_{trainer_info['value']}.json"
+        if os.path.exists(infoFile):
+            with open(infoFile, 'r') as file:
+                info = json.load(file)
+                epochs = '-'
+                batch_size = '-'
+                dropout_rate = '-'
+                training_method = '-'
+                duration = '-'
+                testAccuracy = '-'
+                accu = []
+                loss = []
+                size = '-'
+                if 'epochs' in info:
+                    epochs = info['epochs']
+                if 'batch_size' in info:
+                    batch_size = info['batch_size']
+                if 'dropout_rate' in info:
+                    dropout_rate = info['dropout_rate']
+                if 'trainer_script' in info:
+                    training_method = info['trainer_script']
+                if 'accuracy' in info:
+                    accu = info['accuracy']
+                if 'loss' in info:
+                    loss = info['loss']
+                if 'training_time' in info:
+                    duration = info['training_time']
+                if 'test_accuracy' in info:
+                    testAccuracy = info['test_accuracy']
+                if 'model_size' in info:
+                    size = info['model_size']
+                chart_fig1 = go.Figure(data=[go.Scatter(y=accu)])
+                chart_fig2 = go.Figure(data=[go.Scatter(y=loss)])
+                entries = [
+                    dcc.Graph(figure=chart_fig1),
+                    dcc.Graph(figure=chart_fig2),
+                    html.P("Epochen: "+str(epochs), className="card-text"),
+                    html.P("Batch Size: "+str(batch_size), className="card-text"),
+                    html.P("Dropout Rate: "+str(dropout_rate), className="card-text"),
+                    html.P("Methode: "+str(training_method), className="card-text"),
+                    html.P("Duration: "+str(duration), className="card-text"),
+                    html.P("Test Accuracy: "+str(testAccuracy), className="card-text"),
+                    html.P("Size: "+get_Size_String(size*1024), className="card-text"),
+                ]
+                tab_trainer.append(
+                    dbc.Tab(entries
+                    , label=trainer_info['label'], tab_id=trainer_info['value'])
+                )
+        else:
+            tab_trainer.append(
+                dbc.Tab("",label=trainer_info['label'], tab_id=trainer_info['value'], disabled=True)
+            )
+    
+    # Pagination logic
+    num_pages = (row_count // page_size) + (1 if row_count % page_size > 0 else 0)
+    pagination = dbc.Pagination(id='data-table-pagination', max_value=num_pages, active_page=1)
 
     return html.Div([
         html.H2(f"Manage Hotword Model: {model_name}"),
-        model_info,
+        dbc.Card([dbc.CardHeader("Model Infos"),dbc.CardBody(dbc.Tabs(tab_trainer))]),
         dbc.Card([
             dbc.CardHeader("Training Controls"),
             dbc.CardBody([
-                dbc.ButtonGroup([
-                    dbc.Button("Start Training", id="start-training-hotword", color="success", className="mb-3"),
-                    dbc.DropdownMenu(
-                        [dbc.DropdownMenuItem(name, id={'type': 'select-trainer', 'index': name}) for name in trainer_classes.keys()],
-                        label="Select Trainer", bs_size="lg", direction="down"
-                    ),
-                    dbc.Button("Optimize Training", id="optimize-training-hotword", color="primary", className="mb-3"),
-                    dbc.Button("Stop Training", id="stop-training-hotword", color="danger", className="mb-3")
-                ]),
+                #dbc.Row([
+                    #dbc.Col(dbc.Button("Start Training", id="start-training-hotword", color="success", className="mb-3")),
+                    #dbc.Col(dbc.Button("Optimize Training", id="optimize-training-hotword", color="primary", className="mb-3 ml-3")),
+                    #dbc.Col(dbc.Button("Stop Training", id="stop-training-hotword", color="danger", className="mb-3 ml-3")),
+                    dbc.ButtonGroup([
+                        dbc.DropdownMenu(
+                            label="Start training",
+                            children=[
+                                dbc.DropdownMenuItem("Item 1"),
+                                dbc.DropdownMenuItem("Item 2"),
+                                dbc.DropdownMenuItem("Item 3"),
+                            ],
+                        ),
+                        dbc.Button("Start Training", id="start-training-hotword", color="success", className="mb-3"),
+                        dbc.Button("Optimize Training", id="optimize-training-hotword", color="primary", className="mb-3 ml-3"),
+                        dbc.Button("Stop Training", id="stop-training-hotword", color="danger", className="mb-3 ml-3"),
+                    ]),
+                #]),
                 dbc.Row([
+                    dbc.Col(
+                        dcc.Dropdown(
+                            id="training-method-dropdown",
+                            options=trainer_options,
+                            value=trainer_options[0]["value"],  # default value
+                            clearable=False,
+                            className="mb-3",
+                            placeholder="Select Training Method",
+                        )
+                    ),
                     dbc.Col(
                         dcc.Input(
                             id="dropout-rate",
@@ -70,26 +151,35 @@ def ManageHotwordLayout(model_name):
                         )
                     ),
                     dbc.Col(
-                        dcc.Input(
-                            id="num-epochs",
-                            type="number",
-                            value=10,
-                            step=1,
-                            min=1,
-                            className="mb-3",
-                            placeholder="Epochs"
-                        )
+                        dcc.Slider(0, 10000, value=3000, id="num-epochs",tooltip={"placement": "bottom", "always_visible": False})
+                        #dcc.Input(
+                        #    id="num-epochs",
+                        #    type="number",
+                        #    value=10,
+                        #    step=1,
+                        #    min=1,
+                        #    className="mb-3",
+                        #    placeholder="Epochs"
+                        #)
                     ),
                     dbc.Col(
-                        dcc.Input(
-                            id="batch-size",
-                            type="number",
-                            value=32,
-                            step=1,
-                            min=1,
-                            className="mb-3",
-                            placeholder="Batch Size"
-                        )
+                        dcc.Slider(0, 256, marks={
+                            8: '8',
+                            16: '16',
+                            32: '32',
+                            64: '64',
+                            128: '128',
+                            256: '256',
+                        }, value=32, id="batch-size", step=None)
+                        #dcc.Input(
+                        #    id="batch-size",
+                        #    type="number",
+                        #    value=32,
+                        #    step=1,
+                        #    min=1,
+                        #    className="mb-3",
+                        #    placeholder="Batch Size"
+                        #)
                     )
                 ]),
                 html.Div(id="training-status", className='mt-3'),
@@ -97,7 +187,7 @@ def ManageHotwordLayout(model_name):
                 dbc.Card([
                     dbc.CardHeader("Training Progress"),
                     dbc.CardBody([
-                        dcc.Graph(id="training-chart"),
+                        dcc.Graph(id="training-chart", figure=[]),
                         dbc.Progress(id="training-progress", striped=True, animated=True, style={"height": "20px"}),
                     ])
                 ]),
@@ -132,49 +222,12 @@ def ManageHotwordLayout(model_name):
         dbc.Card([
             dbc.CardHeader("Training Data"),
             dbc.CardBody([
-                training_data_table
+                training_data_table, pagination
             ])
         ])
     ])
 
-def generate_model_info(model_name):
-    model_dir = f"./model/hotword/{model_name}/"
-    model_info = []
-    for extension in ["h5", "keras", "pth"]:
-        model_path = model_dir + f"hotword_model.{extension}"
-        if os.path.exists(model_path):
-            json_path = model_dir + f"info_{extension}.json"
-            try:
-                with open(json_path, "r") as f:
-                    info = json.load(f)
-                    model_info.append(html.Div([
-                        html.H4(f"Model ({extension.upper()})"),
-                        html.P(f"Training Time: {info['training_time']} seconds"),
-                        html.P(f"Model Size: {info['model_size']} KB"),
-                        html.P(f"Trainer Script: {info['trainer_script']}"),
-                        html.P(f"Epochs: {info['epochs']}"),
-                        html.P(f"Dropout Rate: {info['dropout_rate']}"),
-                        html.P(f"Batch Size: {info['batch_size']}"),
-                        html.P(f"Total Training Data: {info['total_training_data']}"),
-                        html.P(f"Training Directories: {', '.join(info['training_directories'])}"),
-                        html.P(f"Accuracy: {info['accuracy'][-1] if info['accuracy'] else 'N/A'}"),
-                        html.P(f"Loss: {info['loss'][-1] if info['loss'] else 'N/A'}"),
-                        html.P(f"Test Accuracy: {info['test_accuracy']}")
-                    ], className='mb-3'))
-            except FileNotFoundError:
-                model_info.append(html.Div([
-                    html.H4(f"Model ({extension.upper()})"),
-                    html.P("No detailed information available")
-                ], className='mb-3'))
-
-    if not model_info:
-        model_info = html.Div([
-            html.P("No trained model available"),
-        ], className='mb-3')
-
-    return html.Div(model_info)
-
-def generate_training_data_table(model_name, files, page_size=10):
+def generate_training_data_table(model_name, files, page=1, page_size=10):
     import os
     header = [
         html.Thead(html.Tr([html.Th("Audio"), html.Th("File Name"), html.Th("Display"), html.Th("Length (s)"), html.Th("Size (KB)"), html.Th("Actions")]))
@@ -219,5 +272,13 @@ def generate_training_data_table(model_name, files, page_size=10):
                     html.Td("-"),
                     html.Td("File not found")
                 ]))
-    pagination = dcc.Pagination(id='data-table-pagination', max_value=len(rows)//page_size + 1, page_size=page_size)
-    return html.Div([dbc.Table(header + [html.Tbody(rows)], bordered=True, hover=True), pagination])
+
+    start = (page - 1) * 10
+    end = start + 10
+    row_count = len(rows)
+    table_body = html.Tbody(id='data-table-body', children=rows[start:end])
+
+    return html.Div([
+        dbc.Table(header + [table_body], bordered=True, hover=True)
+    ]), row_count
+

BIN
trainer/model/hotword/trixy/hotword_model.pth


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
trainer/model/hotword/trixy/info_pytorch_trainer.json


+ 2 - 0
trainer/trainer.pyproj

@@ -41,9 +41,11 @@
     <Compile Include="components\tts.py" />
     <Compile Include="components\voice_detection.py" />
     <Compile Include="components\__init__.py" />
+    <Compile Include="trainer_scripts\pytorch_adv_trainer.py" />
     <Compile Include="utils\file_utils.py" />
     <Compile Include="trainer_scripts\pytorch_trainer.py" />
     <Compile Include="trainer_scripts\tensorflow_trainer.py" />
+    <Compile Include="utils\pytorch_utils.py" />
     <Compile Include="utils\training_interface.py" />
     <Compile Include="utils\training_utils.py" />
   </ItemGroup>

+ 167 - 0
trainer/trainer_scripts/pytorch_adv_trainer.py

@@ -0,0 +1,167 @@
+import os
+import time
+import json
+import torch
+import torch.optim as optim
+from torch.utils.data import DataLoader
+from utils.training_interface import TrainerInterface
+from utils.file_utils import list_files_in_directory
+from utils.pytorch_utils import WakeWordDataset, CNNNetwork, preprocess_training_data, train_model, optimize_graph
+
+# Global variables for tracking progress
+current_progress = 0
+current_loss = 0.0
+current_accuracy = 0.0
+total_epochs = 0
+total_batches = 0
+
+class pytorch_adv_trainer(TrainerInterface):
+    def __init__(self, learning_rate=0.001):
+        self.model_path = None
+        self.training_directories = []
+        self.sample_directory = None
+        self.background_directory = None
+        self.dropout_rate = 0.5
+        self.epochs = 10
+        self.batch_size = 32
+        self.learning_rate = learning_rate
+        self.model = None
+        self.optimizer = None
+        self.criterion = torch.nn.BCEWithLogitsLoss()
+        self.current_epoch = 0
+        self.stop_training = False
+        self.training_status = "Not started"
+        self.train_loader = None
+        self.val_loader = None
+
+    def set_model_path(self, model_path):
+        self.model_path = model_path
+        self.model = self.load_model()
+        self.optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate)
+
+    def set_training_directories(self, directories):
+        self.training_directories = directories
+
+    def set_sample_directory(self, directory):
+        self.sample_directory = directory
+
+    def set_background_directory(self, directory):
+        self.background_directory = directory
+
+    def set_dropout_rate(self, rate):
+        self.dropout_rate = rate
+
+    def set_epochs(self, epochs):
+        self.epochs = epochs
+
+    def set_batch_size(self, batch_size):
+        self.batch_size = batch_size
+
+    def get_training_data(self):
+        return self.training_directories
+
+    def get_model_path(self):
+        return self.model_path
+
+    def get_epochs(self):
+        return self.epochs
+
+    def get_batch_size(self):
+        return self.batch_size
+
+    def get_dropout_rate(self):
+        return self.dropout_rate
+
+    def get_training_directories(self):
+        return self.training_directories
+
+    def get_sample_directory(self):
+        return self.sample_directory
+
+    def get_background_directory(self):
+        return self.background_directory
+
+    def set_training_data(self, features, labels):
+        X_train, X_val, y_train, y_val = train_test_split(features, labels, test_size=0.2, random_state=42)
+        self.train_loader = DataLoader(WakeWordDataset(X_train, y_train), batch_size=self.batch_size, shuffle=True)
+        self.val_loader = DataLoader(WakeWordDataset(X_val, y_val), batch_size=self.batch_size, shuffle=False)
+
+    def load_model(self):
+        model = CNNNetwork()
+        if os.path.exists(self.model_path + "hotword_model.pth"):
+            model.load_state_dict(torch.load(self.model_path + "hotword_model.pth"))
+        return model
+
+    def start(self):
+        self.training_status = "Training"
+        self.stop_training = False
+        self.run_training()
+
+    def start_new(self):
+        self.training_status = "Training"
+        self.stop_training = False
+        self.model = self.load_model()
+        self.current_epoch = 0
+        self.run_training()
+
+    def pause(self):
+        self.training_status = "Paused"
+        self.stop_training = True
+
+    def resume(self):
+        self.training_status = "Training"
+        self.stop_training = False
+        self.run_training()
+
+    def stop(self):
+        self.training_status = "Stopped"
+        self.stop_training = True
+
+    def preprocess_training_data(self, update_progress_callback):
+        preprocess_training_data(self.training_directories, self.background_directory, self.model_path, update_progress_callback)
+
+    def run_training(self):
+        global current_progress, current_loss, current_accuracy, total_epochs, total_batches
+        self.preprocess_training_data(lambda progress: setattr(self, 'current_progress', progress))
+
+        df = pd.read_pickle(self.model_path + "audio_data.csv")
+        X = df["feature"].values
+        X = np.concatenate(X, axis=0).reshape(len(X), 40)
+        y = np.array(df["class_label"].tolist())
+        self.set_training_data(X, y)
+        
+        total_batches = int(np.ceil(len(self.train_loader.dataset) / self.batch_size))
+        total_epochs = self.epochs
+
+        for epoch in range(self.current_epoch, self.epochs):
+            if self.stop_training:
+                break
+            self.current_epoch = epoch
+            train_model(self.model, self.train_loader, self.optimizer, self.criterion, epoch, self.epochs)
+
+            current_progress = (epoch + 1) / self.epochs * 100
+            print(f"Epoch {epoch + 1}/{self.epochs}")
+
+        if not self.stop_training:
+            torch.save(self.model.state_dict(), self.model_path + "hotword_model.pth")
+            self.evaluate_model(X, y)
+            self.training_status = "Finished"
+
+    def evaluate_model(self, X_test, y_test):
+        self.model.eval()
+        with torch.no_grad():
+            X_test_tensor = torch.FloatTensor(X_test)
+            y_test_tensor = torch.LongTensor(y_test)
+            outputs = self.model(X_test_tensor)
+            _, predicted = torch.max(outputs, 1)
+            accuracy = (predicted == y_test_tensor).sum().item() / len(y_test_tensor)
+            print(f"Test Accuracy: {accuracy * 100:.2f}%")
+
+    def get_training_info(self):
+        return {
+            "status": self.training_status,
+            "current_epoch": self.current_epoch,
+            "total_epochs": self.epochs,
+            "loss": current_loss,
+            "accuracy": current_accuracy
+        }

+ 28 - 1
trainer/trainer_scripts/pytorch_trainer.py

@@ -7,6 +7,8 @@ import numpy as np
 from sklearn.model_selection import train_test_split
 from utils.training_interface import TrainerInterface
 from utils.file_utils import list_files_in_directory
+import time
+import json
 
 # Global variables for progress tracking
 current_progress = 0
@@ -179,6 +181,7 @@ class PyTorchTrainer(TrainerInterface):
     def run_training(self):
         global current_progress, current_loss, current_accuracy, total_epochs, total_batches
         self.preprocess_training_data()
+        start_time = time.time()
         df = pd.read_pickle(self.model_path + "audio_data.csv")
         X = df["feature"].values
         X = np.concatenate(X, axis=0).reshape(len(X), 40)
@@ -187,6 +190,20 @@ class PyTorchTrainer(TrainerInterface):
 
         total_batches = len(self.train_loader)
         total_epochs = self.epochs
+        
+        training_info = {
+            "trainer_script": "tensorflow_trainer",
+            "training_time": 0,
+            "model_size": 0,
+            "epochs": self.epochs,
+            "dropout_rate": self.dropout_rate,
+            "batch_size": self.batch_size,
+            "total_training_data": len(X),
+            "training_directories": self.training_directories,
+            "accuracy": [],
+            "loss": [],
+            "test_accuracy": 0
+        }
 
         for epoch in range(self.current_epoch, self.epochs):
             if self.stop_training:
@@ -194,22 +211,28 @@ class PyTorchTrainer(TrainerInterface):
             self.current_epoch = epoch
             self.model.train()
             for batch_idx, (batch_X, batch_y) in enumerate(self.train_loader):
+                global current_loss, current_accuracy
                 self.optimizer.zero_grad()
                 outputs = self.model(batch_X)
                 loss = self.criterion(outputs, batch_y.long())  # Convert labels to Long type
                 loss.backward()
                 self.optimizer.step()
                 # Update global progress variables
-                global current_loss, current_accuracy
                 current_loss = loss.item()
                 current_accuracy = (outputs.argmax(dim=1) == batch_y).float().mean().item()
                 current_progress = (epoch * len(self.train_loader) + batch_idx + 1) / (self.epochs * len(self.train_loader)) * 100
+            training_info["accuracy"].append(current_accuracy)
+            training_info["loss"].append(current_loss)
             
             print(f"Epoch {epoch + 1}/{self.epochs}, Loss: {current_loss}, Accuracy: {current_accuracy}")
 
+        epoch_time = time.time() - start_time
+        training_info["training_time"] = epoch_time
+        
         if not self.stop_training:
             torch.save(self.model.state_dict(), self.model_path + "hotword_model.pth")
             self.evaluate_model(X, y)
+            self.save_training_info(training_info)
             self.training_status = "Finished"
         else:
             self.training_status = "Paused"
@@ -223,6 +246,10 @@ class PyTorchTrainer(TrainerInterface):
             _, predicted = torch.max(outputs, 1)
             accuracy = (predicted == y_test_tensor).sum().item() / len(y_test_tensor)
             print(f"Test Accuracy: {accuracy * 100:.2f}%")
+    
+    def save_training_info(self, info):
+        with open(self.model_path + "info_pytorch_trainer.json", "w") as f:
+            json.dump(info, f)
 
     def get_training_info(self):
         return {

+ 4 - 4
trainer/trainer_scripts/tensorflow_trainer.py

@@ -162,6 +162,7 @@ class TensorFlowTrainer(TrainerInterface):
         global current_progress, current_loss, current_accuracy, total_epochs, total_batches
         self.preprocess_training_data()
 
+        start_time = time.time()
         df = pd.read_pickle(self.model_path + "audio_data.csv")
         X = df["feature"].values
         X = np.concatenate(X, axis=0).reshape(len(X), 40)
@@ -192,17 +193,16 @@ class TensorFlowTrainer(TrainerInterface):
             if self.stop_training:
                 break
             self.current_epoch = epoch
-            start_time = time.time()
             history = self.model.fit(X_train, y_train, epochs=1, batch_size=self.batch_size)
-            epoch_time = time.time() - start_time
             current_loss = history.history['loss'][-1]
             current_accuracy = history.history['accuracy'][-1]
             current_progress = (epoch + 1) / self.epochs * 100
-            training_info["training_time"] += epoch_time
             training_info["accuracy"].append(current_accuracy)
             training_info["loss"].append(current_loss)
             print(f"Epoch {epoch + 1}/{self.epochs}, Loss: {current_loss}, Accuracy: {current_accuracy}")
-
+        
+        epoch_time = time.time() - start_time
+        training_info["training_time"] = epoch_time
         if not self.stop_training:
             self.model.save(self.model_path + "hotword_model.h5")
             self.evaluate_model(X, y)

+ 10 - 2
trainer/utils/file_utils.py

@@ -71,8 +71,16 @@ def is_valid_wav(file_path):
 def get_file_size(file_path):
     if not os.path.exists(file_path):
         raise FileNotFoundError(f"File {file_path} does not exist.")
-    size = os.path.getsize(file_path) / 1024  # size in KB
-    return round(size, 2)
+    size = os.path.getsize(file_path)
+    return get_Size_String(size)
+
+def get_Size_String(value):
+    ext = ["Byte","KB","MB","GB","TB"]
+    i = 0
+    while value > 1024:
+        value /= 1024
+        i += 1
+    return f"{value:.2f} {ext[i]}"
 
 def update_training_time(model_name, additional_time):
     training_time_path = f"./model/hotword/{model_name}/training_time.txt"

+ 103 - 0
trainer/utils/pytorch_utils.py

@@ -0,0 +1,103 @@
+import torch
+import torch.nn as nn
+import numpy as np
+import pandas as pd
+from torch.utils.data import Dataset
+
+class WakeWordDataset(Dataset):
+    def __init__(self, features, labels):
+        self.features = features
+        self.labels = labels
+
+    def __len__(self):
+        return len(self.features)
+
+    def __getitem__(self, idx):
+        feature = torch.tensor(self.features[idx], dtype=torch.float32)
+        label = torch.tensor(self.labels[idx], dtype=torch.long)
+        return feature, label
+
+class CNNNetwork(nn.Module):
+    def __init__(self):
+        super(CNNNetwork, self).__init__()
+        self.network = nn.Sequential(
+            nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
+            nn.ReLU(),
+            nn.MaxPool2d(kernel_size=2, stride=2),
+            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
+            nn.ReLU(),
+            nn.MaxPool2d(kernel_size=2, stride=2),
+            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
+            nn.ReLU(),
+            nn.MaxPool2d(kernel_size=2, stride=2),
+            nn.Flatten(),
+            nn.Linear(128 * 4 * 4, 128),
+            nn.ReLU(),
+            nn.Dropout(0.5),
+            nn.Linear(128, 1),
+            nn.Sigmoid()
+        )
+
+    def forward(self, x):
+        return self.network(x)
+
+def preprocess_training_data(training_directories, background_directory, model_path, update_progress_callback):
+    import librosa
+    data_path_dict = {}
+    data_path_dict[0] = list_files_in_directory(background_directory, extension='.wav')
+    for idx, directory in enumerate(training_directories):
+        data_path_dict[idx+1] = list_files_in_directory(directory, extension='.wav')
+
+    all_data = []
+    total_files = sum(len(files) for files in data_path_dict.values())
+    processed_files = 0
+
+    for class_label, list_of_files in data_path_dict.items():
+        for single_file in list_of_files:
+            try:
+                audio, sample_rate = librosa.load(single_file)
+                mfcc = librosa.feature.mfcc(y=audio, sr=sample_rate, n_mfcc=40)
+                mfcc_processed = np.mean(mfcc.T, axis=0)
+                all_data.append([mfcc_processed, class_label])
+                processed_files += 1
+                update_progress_callback(processed_files / total_files * 100)
+            except Exception as e:
+                print(f"Exception: {str(e)}")
+
+    df = pd.DataFrame(all_data, columns=["feature", "class_label"])
+    df.to_pickle(model_path + "audio_data.csv")
+
+def train_model(model, train_loader, optimizer, criterion, epoch, total_epochs):
+    model.train()
+    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
+    model.to(device)
+    
+    for batch_idx, (data, target) in enumerate(train_loader):
+        data, target = data.to(device), target.to(device)
+        optimizer.zero_grad()
+        output = model(data)
+        loss = criterion(output, target.float().unsqueeze(1))
+        loss.backward()
+        optimizer.step()
+
+        if batch_idx % 10 == 0:
+            print(f'Train Epoch: {epoch}/{total_epochs} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')
+
+def optimize_graph(model, device, optimizer, criterion, dataloader):
+    model.train()
+    total_loss = 0
+    correct = 0
+
+    for data, target in dataloader:
+        data, target = data.to(device), target.to(device)
+        optimizer.zero_grad()
+        output = model(data)
+        loss = criterion(output, target.float().unsqueeze(1))
+        loss.backward()
+        optimizer.step()
+        total_loss += loss.item()
+        pred = torch.round(output)
+        correct += pred.eq(target.float().unsqueeze(1)).sum().item()
+
+    accuracy = correct / len(dataloader.dataset)
+    return total_loss / len(dataloader), accuracy