Spaces:
Runtime error
Runtime error
Kumar Shubham
commited on
Commit
·
2c2f868
1
Parent(s):
271a1c7
Adding all files
Browse files- app.py +75 -0
- models/lr_sound_classifier_model.joblib +3 -0
- models/nn_sound_classifier_model.joblib +3 -0
- models/rf_sound_classifier_model.joblib +3 -0
- models/svm_sound_classifier_model.joblib +3 -0
- requirements.txt +12 -0
- sound_classifier.py +142 -0
app.py
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import os
|
3 |
+
import joblib
|
4 |
+
from sound_classifier import SoundClassifier
|
5 |
+
import numpy as np
|
6 |
+
|
7 |
+
# Get list of available models and their friendly names
|
8 |
+
MODELS_DIR = 'models'
|
9 |
+
MODEL_NAMES = {
|
10 |
+
'lr_sound_classifier_model.joblib': 'Logistic Regression',
|
11 |
+
'nn_sound_classifier_model.joblib': 'Neural Network',
|
12 |
+
'rf_sound_classifier_model.joblib': 'Random Forest',
|
13 |
+
'svm_sound_classifier_model.joblib': 'Support Vector Machine'
|
14 |
+
}
|
15 |
+
|
16 |
+
model_files = [f for f in os.listdir(MODELS_DIR) if f.endswith('_model.joblib')]
|
17 |
+
model_choices = {MODEL_NAMES[file]: file for file in model_files}
|
18 |
+
|
19 |
+
def load_model(model_file):
|
20 |
+
"""Load a saved model and its associated scaler and label encoder"""
|
21 |
+
model_path = os.path.join(MODELS_DIR, model_file)
|
22 |
+
saved_data = joblib.load(model_path)
|
23 |
+
return saved_data['model'], saved_data['scaler'], saved_data['label_encoder']
|
24 |
+
|
25 |
+
def format_issue(issue_text):
|
26 |
+
"""Format the issue text to be more readable"""
|
27 |
+
# Replace underscores with spaces and title case the text
|
28 |
+
formatted = issue_text.replace('_', ' ').title()
|
29 |
+
return formatted
|
30 |
+
|
31 |
+
def predict_sound(audio_file, model_name):
|
32 |
+
"""
|
33 |
+
Function to make predictions on uploaded audio files using the selected model
|
34 |
+
"""
|
35 |
+
# Get the actual model filename from the friendly name
|
36 |
+
model_file = model_choices[model_name]
|
37 |
+
|
38 |
+
# Load the selected model
|
39 |
+
model, scaler, le = load_model(model_file)
|
40 |
+
|
41 |
+
# Initialize classifier for feature extraction only
|
42 |
+
classifier = SoundClassifier(data_dir='data')
|
43 |
+
|
44 |
+
# Extract features and predict
|
45 |
+
features = classifier.extract_features(audio_file)
|
46 |
+
features = features.reshape(1, -1)
|
47 |
+
features_scaled = scaler.transform(features)
|
48 |
+
prediction = model.predict(features_scaled)
|
49 |
+
|
50 |
+
# Get the predicted label and format it
|
51 |
+
predicted_label = le.inverse_transform(prediction)[0]
|
52 |
+
formatted_label = format_issue(predicted_label)
|
53 |
+
|
54 |
+
return f"Predicted Issue: {formatted_label}"
|
55 |
+
|
56 |
+
# Create Gradio interface
|
57 |
+
iface = gr.Interface(
|
58 |
+
fn=predict_sound,
|
59 |
+
inputs=[
|
60 |
+
gr.Audio(type="filepath", label="Upload Sound File"),
|
61 |
+
gr.Dropdown(choices=list(model_choices.keys()), label="Select Model Type", value=list(model_choices.keys())[0])
|
62 |
+
],
|
63 |
+
outputs=gr.Textbox(label="Prediction"),
|
64 |
+
title="Engine Sound Issue Classifier",
|
65 |
+
description="Upload an audio file of engine sound to identify potential issues. Choose from different machine learning models.",
|
66 |
+
examples=[
|
67 |
+
[os.path.join("test_data", "air_filter_sample_5.wav"), list(model_choices.keys())[0]],
|
68 |
+
[os.path.join("test_data", "cd_sample_16.wav"), list(model_choices.keys())[1]],
|
69 |
+
[os.path.join("test_data", "vl_sample_4.wav"), list(model_choices.keys())[2]]
|
70 |
+
]
|
71 |
+
)
|
72 |
+
|
73 |
+
if __name__ == "__main__":
|
74 |
+
iface.launch()
|
75 |
+
|
models/lr_sound_classifier_model.joblib
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:e6cbd07e39ac1508901942b63bb123f3e11a69bc0fb6080a4cb30df2f9ca75bb
|
3 |
+
size 3363
|
models/nn_sound_classifier_model.joblib
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:8357223fcdbc7ac1cddcc6179a7ac7a5dca08c27af719e6627b62e1d0ec52976
|
3 |
+
size 272851
|
models/rf_sound_classifier_model.joblib
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f36dac57d6ebcec562dd1e5dc6b10526e54c9a820f46781ed24951088670ab87
|
3 |
+
size 119043
|
models/svm_sound_classifier_model.joblib
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f8706f20c6742817c9b095fe7de9d6698516d344dc2fddb9e8bd072d80581429
|
3 |
+
size 8564
|
requirements.txt
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy>=1.20.0
|
2 |
+
librosa>=0.9.0
|
3 |
+
scikit-learn>=0.24.0
|
4 |
+
joblib>=1.0.0
|
5 |
+
pandas>=1.3.0
|
6 |
+
matplotlib>=3.4.0
|
7 |
+
seaborn>=0.11.0
|
8 |
+
scipy>=1.7.0
|
9 |
+
gradio>=4.0.0
|
10 |
+
onnx>=1.15.0
|
11 |
+
skl2onnx>=1.14.0
|
12 |
+
onnxruntime>=1.16.0
|
sound_classifier.py
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import numpy as np
|
3 |
+
import librosa
|
4 |
+
from sklearn.model_selection import train_test_split
|
5 |
+
from sklearn.preprocessing import LabelEncoder, StandardScaler
|
6 |
+
from sklearn.ensemble import RandomForestClassifier
|
7 |
+
from sklearn.linear_model import LogisticRegression
|
8 |
+
from sklearn.svm import SVC
|
9 |
+
from sklearn.neural_network import MLPClassifier
|
10 |
+
from sklearn.metrics import classification_report
|
11 |
+
import joblib
|
12 |
+
|
13 |
+
|
14 |
+
class SoundClassifier:
|
15 |
+
def __init__(self, data_dir, model_type='rf', sr=22050, duration=20):
|
16 |
+
self.data_dir = data_dir
|
17 |
+
self.sr = sr
|
18 |
+
self.duration = duration
|
19 |
+
self.model = None
|
20 |
+
self.le = LabelEncoder()
|
21 |
+
self.scaler = StandardScaler()
|
22 |
+
self.model_type = model_type
|
23 |
+
|
24 |
+
def extract_features(self, file_path):
|
25 |
+
# Load audio file
|
26 |
+
y, _ = librosa.load(file_path, sr=self.sr, duration=self.duration)
|
27 |
+
|
28 |
+
# Pad or truncate to fixed length
|
29 |
+
if len(y) < self.sr * self.duration:
|
30 |
+
y = np.pad(y, (0, self.sr * self.duration - len(y)))
|
31 |
+
else:
|
32 |
+
y = y[:self.sr * self.duration]
|
33 |
+
|
34 |
+
# Extract features
|
35 |
+
mfccs = librosa.feature.mfcc(y=y, sr=self.sr, n_mfcc=13)
|
36 |
+
spectral_centroid = librosa.feature.spectral_centroid(y=y, sr=self.sr)
|
37 |
+
spectral_rolloff = librosa.feature.spectral_rolloff(y=y, sr=self.sr)
|
38 |
+
|
39 |
+
# Compute statistics
|
40 |
+
features = np.concatenate([
|
41 |
+
mfccs.mean(axis=1),
|
42 |
+
mfccs.std(axis=1),
|
43 |
+
spectral_centroid.mean(axis=1),
|
44 |
+
spectral_rolloff.mean(axis=1)
|
45 |
+
])
|
46 |
+
|
47 |
+
return features
|
48 |
+
|
49 |
+
def prepare_data(self):
|
50 |
+
X = []
|
51 |
+
y = []
|
52 |
+
|
53 |
+
# Iterate through each issue folder
|
54 |
+
for issue in os.listdir(self.data_dir):
|
55 |
+
issue_path = os.path.join(self.data_dir, issue)
|
56 |
+
if os.path.isdir(issue_path):
|
57 |
+
# Process each audio file in the folder
|
58 |
+
for audio_file in os.listdir(issue_path):
|
59 |
+
if audio_file.endswith('.wav'):
|
60 |
+
file_path = os.path.join(issue_path, audio_file)
|
61 |
+
features = self.extract_features(file_path)
|
62 |
+
X.append(features)
|
63 |
+
y.append(issue)
|
64 |
+
print(len(X))
|
65 |
+
print(len(y))
|
66 |
+
X = np.array(X)
|
67 |
+
y = self.le.fit_transform(y)
|
68 |
+
|
69 |
+
return X, y
|
70 |
+
|
71 |
+
def train(self):
|
72 |
+
# Prepare data
|
73 |
+
X, y = self.prepare_data()
|
74 |
+
|
75 |
+
# Split data
|
76 |
+
X_train, X_test, y_train, y_test = train_test_split(
|
77 |
+
X, y, test_size=0.2, random_state=42
|
78 |
+
)
|
79 |
+
|
80 |
+
# Scale features
|
81 |
+
X_train_scaled = self.scaler.fit_transform(X_train)
|
82 |
+
X_test_scaled = self.scaler.transform(X_test)
|
83 |
+
|
84 |
+
# Train model based on model_type
|
85 |
+
if self.model_type == 'rf':
|
86 |
+
self.model = RandomForestClassifier(n_estimators=100, random_state=42)
|
87 |
+
elif self.model_type == 'lr':
|
88 |
+
self.model = LogisticRegression(random_state=42, max_iter=1000)
|
89 |
+
elif self.model_type == 'svm':
|
90 |
+
self.model = SVC(kernel='rbf', random_state=42)
|
91 |
+
elif self.model_type == 'nn':
|
92 |
+
self.model = MLPClassifier(hidden_layer_sizes=(100, 50), max_iter=1000, random_state=42)
|
93 |
+
else:
|
94 |
+
raise ValueError("Invalid model type. Choose 'rf', 'lr', 'svm', or 'nn'.")
|
95 |
+
|
96 |
+
self.model.fit(X_train_scaled, y_train)
|
97 |
+
|
98 |
+
# Evaluate
|
99 |
+
y_pred = self.model.predict(X_test_scaled)
|
100 |
+
print(f"\nModel Performance ({self.model_type}):")
|
101 |
+
print(classification_report(y_test, y_pred,
|
102 |
+
labels=np.unique(y),
|
103 |
+
target_names=self.le.classes_[np.unique(y)]))
|
104 |
+
|
105 |
+
return self.model
|
106 |
+
|
107 |
+
def predict(self, audio_file):
|
108 |
+
# Extract features from new audio
|
109 |
+
features = self.extract_features(audio_file)
|
110 |
+
|
111 |
+
# Scale features
|
112 |
+
features_scaled = self.scaler.transform([features])
|
113 |
+
|
114 |
+
# Make prediction
|
115 |
+
prediction = self.model.predict(features_scaled)[0]
|
116 |
+
|
117 |
+
# Return the issue name
|
118 |
+
return self.le.inverse_transform([prediction])[0]
|
119 |
+
|
120 |
+
def save_model(self, model_path='sound_classifier_model.joblib'):
|
121 |
+
"""Save the trained model, label encoder, and scaler"""
|
122 |
+
if self.model is None:
|
123 |
+
raise ValueError("Model hasn't been trained yet!")
|
124 |
+
|
125 |
+
model_data = {
|
126 |
+
'model': self.model,
|
127 |
+
'label_encoder': self.le,
|
128 |
+
'scaler': self.scaler,
|
129 |
+
'model_type': self.model_type
|
130 |
+
}
|
131 |
+
joblib.dump(model_data, model_path)
|
132 |
+
|
133 |
+
@classmethod
|
134 |
+
def load_model(cls, model_path='sound_classifier_model.joblib'):
|
135 |
+
"""Load a trained model"""
|
136 |
+
classifier = cls(data_dir=None) # Create instance without data dir
|
137 |
+
model_data = joblib.load(model_path)
|
138 |
+
classifier.model = model_data['model']
|
139 |
+
classifier.le = model_data['label_encoder']
|
140 |
+
classifier.scaler = model_data['scaler']
|
141 |
+
classifier.model_type = model_data['model_type']
|
142 |
+
return classifier
|