magnumical commited on
Commit
9c6b905
·
verified ·
1 Parent(s): a210548

Upload 103 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +4 -0
  2. .gitignore +7 -0
  3. 101_1b1_Al_sc_Meditron.wav +3 -0
  4. Exploration/__pycache__/inference.cpython-312.pyc +0 -0
  5. Exploration/inference.py +209 -0
  6. ExplorationApp.py +247 -0
  7. Model_Inference.py +109 -0
  8. README.md +1 -12
  9. Train.py +215 -0
  10. data/Respiratory_Sound_Database/filename_differences.txt +91 -0
  11. data/Respiratory_Sound_Database/filename_format.txt +7 -0
  12. data/Respiratory_Sound_Database/patient_diagnosis.csv +126 -0
  13. data/Respiratory_Sound_Database/testsample/101_1b1_Al_sc_Meditron.txt +12 -0
  14. data/Respiratory_Sound_Database/testsample/101_1b1_Al_sc_Meditron.wav +3 -0
  15. data/Respiratory_Sound_Database/testsample/101_1b1_Pr_sc_Meditron.txt +11 -0
  16. data/Respiratory_Sound_Database/testsample/101_1b1_Pr_sc_Meditron.wav +3 -0
  17. data/Respiratory_Sound_Database/testsample/102_1b1_Ar_sc_Meditron.txt +13 -0
  18. data/Respiratory_Sound_Database/testsample/102_1b1_Ar_sc_Meditron.wav +3 -0
  19. data/Respiratory_Sound_Database/testsample/103_2b2_Ar_mc_LittC2SE.txt +6 -0
  20. data/Respiratory_Sound_Database/testsample/103_2b2_Ar_mc_LittC2SE.wav +3 -0
  21. data/Respiratory_Sound_Database/testsample/104_1b1_Al_sc_Litt3200.txt +6 -0
  22. data/Respiratory_Sound_Database/testsample/104_1b1_Al_sc_Litt3200.wav +0 -0
  23. data/Respiratory_Sound_Database/testsample/104_1b1_Ar_sc_Litt3200.txt +14 -0
  24. data/__pycache__/data_loader.cpython-312.pyc +0 -0
  25. data/demographic_info.txt +127 -0
  26. deployTest.py +231 -0
  27. legacy/train,py +767 -0
  28. main_ui.py +35 -0
  29. models/archive/latest/final_model_binary_augmented.h5 +3 -0
  30. models/archive/latest/final_model_binary_log_mel.h5 +3 -0
  31. models/archive/latest/final_model_binary_mfcc.h5 +3 -0
  32. models/archive/latest/final_model_multi_augmented.h5 +3 -0
  33. models/archive/latest/final_model_multi_log_mel.h5 +3 -0
  34. models/archive/latest/final_model_multi_mfcc.h5 +3 -0
  35. models/archive/old/final_model_binary_augmented.h5 +3 -0
  36. models/archive/old/final_model_binary_log_mel.h5 +3 -0
  37. models/archive/old/final_model_binary_mfcc.h5 +3 -0
  38. models/archive/old/final_model_multi_augmented.h5 +3 -0
  39. models/archive/old/final_model_multi_log_mel.h5 +3 -0
  40. models/archive/old/final_model_multi_mfcc.h5 +3 -0
  41. models/archive/workingmodels/final_model_binary_augmented.h5 +3 -0
  42. models/archive/workingmodels/final_model_binary_log_mel.h5 +3 -0
  43. models/archive/workingmodels/final_model_binary_mfcc.h5 +3 -0
  44. models/archive/workingmodels/final_model_multi_augmented.h5 +3 -0
  45. models/archive/workingmodels/final_model_multi_log_mel.h5 +3 -0
  46. models/archive/workingmodels/final_model_multi_mfcc.h5 +3 -0
  47. models/final_model_binary_augmented.h5 +3 -0
  48. models/final_model_binary_log_mel.h5 +3 -0
  49. models/final_model_binary_mfcc.h5 +3 -0
  50. models/final_model_multi_augmented.h5 +3 -0
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ 101_1b1_Al_sc_Meditron.wav filter=lfs diff=lfs merge=lfs -text
37
+ data/Respiratory_Sound_Database/testsample/101_1b1_Pr_sc_Meditron.wav filter=lfs diff=lfs merge=lfs -text
38
+ data/Respiratory_Sound_Database/testsample/102_1b1_Ar_sc_Meditron.wav filter=lfs diff=lfs merge=lfs -text
39
+ data/Respiratory_Sound_Database/testsample/103_2b2_Ar_mc_LittC2SE.wav filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ /data/Respiratory_Sound_Database/audio_and_txt_files
2
+ /mlruns
3
+ /KaggleRuns
4
+ /data
5
+ /models/archive
6
+ /huggingface
7
+ /processed_datasets/old
101_1b1_Al_sc_Meditron.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8cecba490774f874dab3bd907ddd2de6a6c42df2a50f46e7436cea3adaa3d724
3
+ size 2646044
Exploration/__pycache__/inference.cpython-312.pyc ADDED
Binary file (12 kB). View file
 
Exploration/inference.py ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import wave
3
+ import numpy as np
4
+ import pandas as pd
5
+ import seaborn as sns
6
+ import matplotlib.pyplot as plt
7
+ import librosa
8
+ import librosa.display
9
+ import scipy.signal as signal
10
+
11
+ class RespiratorySoundAnalysis:
12
+ def __init__(self, diagnosis_file, audio_path):
13
+ self.diagnosis_file = diagnosis_file
14
+ self.audio_path = audio_path
15
+ self.diagnosis_df = None
16
+ self.audio_files = None
17
+ self.audio_df = None
18
+ self.merged_df = None
19
+
20
+ def load_diagnosis_data(self):
21
+ """Load patient diagnosis data."""
22
+ self.diagnosis_df = pd.read_csv(self.diagnosis_file, names=['patient_id', 'disease'])
23
+ print("Diagnosis Data Preview:")
24
+ print(self.diagnosis_df.head())
25
+
26
+ print("\nDisease Distribution:")
27
+ print(self.diagnosis_df['disease'].value_counts())
28
+
29
+ print("\nDisease Proportion:")
30
+ print(self.diagnosis_df['disease'].value_counts(normalize=True) * 100)
31
+
32
+ def plot_disease_distribution(self):
33
+ """Plot disease distribution."""
34
+ plt.figure(figsize=(10, 6))
35
+ sns.countplot(
36
+ y=self.diagnosis_df['disease'],
37
+ order=self.diagnosis_df['disease'].value_counts().index,
38
+ hue=self.diagnosis_df['disease'],
39
+ palette='viridis',
40
+ dodge=False,
41
+ legend=False
42
+ )
43
+ plt.title("Disease Distribution")
44
+ plt.xlabel("Count")
45
+ plt.ylabel("Disease")
46
+ plt.show()
47
+
48
+
49
+ def load_audio_files(self):
50
+ """Load audio file paths."""
51
+ print(f"Searching for .wav files in: {self.audio_path}")
52
+ try:
53
+ # Recursively look for .wav files
54
+ self.audio_files = [
55
+ os.path.join(root, file)
56
+ for root, _, files in os.walk(self.audio_path) # Walk through subdirectories
57
+ for file in files
58
+ if file.lower().endswith('.wav') # Case-insensitive filtering
59
+ ]
60
+ print(f"Total audio files found: {len(self.audio_files)}")
61
+ if not self.audio_files:
62
+ print("No .wav files found. Check the directory or file extensions.")
63
+ except Exception as e:
64
+ print(f"Error while loading audio files: {e}")
65
+ self.audio_files = []
66
+
67
+ def extract_audio_properties(self, file_path):
68
+ """Extract properties of an audio file."""
69
+ with wave.open(file_path, 'r') as audio_file:
70
+ params = audio_file.getparams()
71
+ return {
72
+ "n_channels": params.nchannels,
73
+ "sample_width": params.sampwidth,
74
+ "frame_rate": params.framerate,
75
+ "n_frames": params.nframes,
76
+ "duration_sec": params.nframes / params.framerate
77
+ }
78
+
79
+ def analyze_audio_properties(self):
80
+ """Analyze properties of audio files."""
81
+ if not self.audio_files:
82
+ print("No audio files found to analyze.")
83
+ self.audio_df = None
84
+ return
85
+
86
+ audio_properties = []
87
+
88
+ for file_path in self.audio_files:
89
+ if not os.path.exists(file_path):
90
+ print(f"File not found: {file_path}")
91
+ continue
92
+ try:
93
+ props = self.extract_audio_properties(file_path)
94
+ props['file_name'] = file_path
95
+ audio_properties.append(props)
96
+ except Exception as e:
97
+ print(f"Error analyzing {file_path}: {e}")
98
+
99
+ if audio_properties:
100
+ self.audio_df = pd.DataFrame(audio_properties)
101
+ print("\nAudio File Properties:")
102
+ print(self.audio_df.describe())
103
+ else:
104
+ print("No audio properties could be extracted.")
105
+ self.audio_df = None
106
+
107
+
108
+
109
+ def plot_audio_duration_distribution(self):
110
+ """Plot distribution of audio durations."""
111
+ if self.audio_df is None or 'duration_sec' not in self.audio_df:
112
+ print("Audio data is not available for plotting. Please ensure audio files are analyzed first.")
113
+ return
114
+
115
+ plt.figure(figsize=(10, 6))
116
+ sns.histplot(self.audio_df['duration_sec'], kde=True, bins=20, color='skyblue')
117
+ plt.title("Audio Duration Distribution")
118
+ plt.xlabel("Duration (seconds)")
119
+ plt.ylabel("Frequency")
120
+ plt.show()
121
+
122
+
123
+ def visualize_sample_audio(self, file_name):
124
+ """Visualize a sample audio file."""
125
+ file_path = os.path.join(self.audio_path, file_name)
126
+ if not os.path.exists(file_path):
127
+ print(f"File not found: {file_path}")
128
+ return
129
+
130
+ try:
131
+ y, sr = librosa.load(file_path)
132
+
133
+ # Plot waveform
134
+ plt.figure(figsize=(12, 6))
135
+ librosa.display.waveshow(y, sr=sr)
136
+ plt.title(f"Waveform for {file_name}")
137
+ plt.xlabel("Time (s)")
138
+ plt.ylabel("Amplitude")
139
+ plt.show()
140
+
141
+ # Plot spectrogram
142
+ D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
143
+ plt.figure(figsize=(12, 6))
144
+ librosa.display.specshow(D, sr=sr, x_axis='time', y_axis='log', cmap='viridis')
145
+ plt.colorbar(format='%+2.0f dB')
146
+ plt.title("Spectrogram")
147
+ plt.show()
148
+ except Exception as e:
149
+ print(f"Error visualizing {file_name}: {e}")
150
+
151
+
152
+ def merge_audio_and_diagnosis_data(self):
153
+ """Combine audio stats with diagnosis data."""
154
+ if self.audio_df is None:
155
+ print("Audio data is not available. Please analyze audio properties before merging.")
156
+ return
157
+
158
+ # Extract file name without the full path
159
+ self.audio_df['file_name_only'] = self.audio_df['file_name'].apply(os.path.basename)
160
+
161
+ # Split the file name to extract patient ID (assuming it is the first part of the file name)
162
+ try:
163
+ self.audio_df['patient_id'] = self.audio_df['file_name_only'].str.split('_').str[0].astype(int)
164
+ except ValueError as e:
165
+ print(f"Error extracting patient_id: {e}")
166
+ print(self.audio_df['file_name_only'].head()) # Debugging information
167
+ return
168
+
169
+ # Merge with diagnosis data
170
+ self.merged_df = pd.merge(
171
+ self.audio_df,
172
+ self.diagnosis_df,
173
+ left_on='patient_id',
174
+ right_on='patient_id',
175
+ how='left'
176
+ )
177
+ print("\nMerged Audio and Diagnosis Data:")
178
+ print(self.merged_df.head())
179
+
180
+
181
+ def preprocess_audio(self, y, sr, target_sr=7000, low_cutoff=80, high_cutoff=3000, gamma=30):
182
+ """Preprocess audio by resampling, bandpass filtering, log compression, and normalization."""
183
+ y_resampled = librosa.resample(y, orig_sr=sr, target_sr=target_sr)
184
+ sos = signal.butter(10, [low_cutoff, high_cutoff], btype='bandpass', fs=target_sr, output='sos')
185
+ y_filtered = signal.sosfilt(sos, y_resampled)
186
+ y_compressed = np.sign(y_filtered) * np.log1p(gamma * np.abs(y_filtered)) / np.log1p(gamma)
187
+ y_normalized = y_compressed / np.max(np.abs(y_compressed))
188
+ return y_normalized, target_sr
189
+
190
+ # Entry point for standalone execution
191
+ if __name__ == "__main__":
192
+ diagnosis_file = '../data//Respiratory_Sound_Database//patient_diagnosis.csv'
193
+ audio_path = '../data/Respiratory_Sound_Database/testsample'
194
+
195
+ analysis = RespiratorySoundAnalysis(diagnosis_file, audio_path)
196
+
197
+ # Load and analyze data
198
+ analysis.load_diagnosis_data()
199
+ analysis.plot_disease_distribution()
200
+ analysis.load_audio_files()
201
+ analysis.analyze_audio_properties()
202
+ analysis.plot_audio_duration_distribution()
203
+
204
+ # Visualize sample audio
205
+ if analysis.audio_files:
206
+ analysis.visualize_sample_audio(analysis.audio_files[0])
207
+
208
+ # Merge data
209
+ analysis.merge_audio_and_diagnosis_data()
ExplorationApp.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ import librosa
6
+ import librosa.display
7
+ from Exploration.inference import RespiratorySoundAnalysis
8
+ import seaborn as sns
9
+ import os
10
+
11
+ # Define base paths
12
+ BASE_PATH = 'D://github//AmpleHealth//data//Respiratory_Sound_Database//Respiratory_Sound_Database'
13
+ DIAGNOSIS_FILE = os.path.join(BASE_PATH, 'patient_diagnosis.csv')
14
+ AUDIO_PATH = os.path.join(BASE_PATH, 'testsample')
15
+ DEMOGRAPHIC_FILE = os.path.join('D://github//AmpleHealth//data', 'demographic_info.txt')
16
+
17
+ # Initialize analysis object
18
+ analysis = RespiratorySoundAnalysis(DIAGNOSIS_FILE, AUDIO_PATH)
19
+
20
+ # Load data
21
+ @st.cache_data
22
+ def load_data():
23
+ analysis.load_diagnosis_data()
24
+ analysis.load_audio_files()
25
+ analysis.analyze_audio_properties()
26
+ return analysis.diagnosis_df, analysis.audio_df
27
+
28
+ diagnosis_df, audio_df = load_data()
29
+
30
+ # Load patient demographic data
31
+ @st.cache_data
32
+ def load_patient_demographics():
33
+ patient_df = pd.read_csv(
34
+ DEMOGRAPHIC_FILE,
35
+ names=['Patient number', 'Age', 'Sex', 'Adult BMI (kg/m2)', 'Child Weight (kg)', 'Child Height (cm)'],
36
+ delimiter=' '
37
+ )
38
+ return patient_df
39
+
40
+ patient_df = load_patient_demographics()
41
+
42
+ # Streamlit App
43
+ st.title("Respiratory Sound Data Explorer")
44
+
45
+ # Tabs for navigation
46
+ tabs = st.tabs(["Overview", "Explore Data", "Patient Demographics", "Preprocessing & Audio Effects"])
47
+
48
+ # Overview Tab
49
+
50
+
51
+ # Overview Tab
52
+ with tabs[0]:
53
+ st.header("Dataset Overview")
54
+
55
+ # Highlight key statistics
56
+ total_patients = len(diagnosis_df)
57
+ most_common_disease = diagnosis_df['disease'].value_counts().idxmax()
58
+ least_common_disease = diagnosis_df['disease'].value_counts().idxmin()
59
+
60
+ st.subheader("Key Statistics")
61
+ st.markdown(f"""
62
+ - **Total Patients:** {total_patients}
63
+ - **Most Common Disease:** {most_common_disease} ({diagnosis_df['disease'].value_counts().max()} patients)
64
+ - **Least Common Disease:** {least_common_disease} ({diagnosis_df['disease'].value_counts().min()} patients)
65
+ """)
66
+
67
+ # Diagnosis Distribution
68
+ st.subheader("Diagnosis Distribution")
69
+ disease_counts = diagnosis_df['disease'].value_counts()
70
+ fig, ax = plt.subplots(figsize=(10, 6))
71
+ sns.barplot(y=disease_counts.index, x=disease_counts.values, palette="viridis", ax=ax, legend=False, hue=disease_counts.index, dodge=False)
72
+ ax.set_title("Disease Distribution", fontsize=16, fontweight='bold')
73
+ ax.set_xlabel("Number of Patients", fontsize=12)
74
+ ax.set_ylabel("Disease", fontsize=12)
75
+ for i, v in enumerate(disease_counts.values):
76
+ ax.text(v + 1, i, str(v), color='black', fontsize=10, va='center')
77
+ st.pyplot(fig)
78
+
79
+ # Proportion of Diseases
80
+ st.subheader("Disease Proportion")
81
+ disease_proportions = diagnosis_df['disease'].value_counts(normalize=True) * 100
82
+ fig, ax = plt.subplots(figsize=(10, 6))
83
+ sns.barplot(y=disease_proportions.index, x=disease_proportions.values, hue=disease_proportions.index, dodge=False, palette="coolwarm", ax=ax, legend=False)
84
+ ax.set_title("Disease Proportion (%)", fontsize=16, fontweight='bold')
85
+ ax.set_xlabel("Proportion (%)", fontsize=12)
86
+ ax.set_ylabel("Disease", fontsize=12)
87
+ for i, v in enumerate(disease_proportions.values):
88
+ ax.text(v + 0.5, i, f"{v:.1f}%", color='black', fontsize=10, va='center')
89
+ st.pyplot(fig)
90
+
91
+ # Explore Data Tab
92
+ with tabs[1]:
93
+ st.header("Explore Data")
94
+
95
+ if audio_df is not None and not audio_df.empty:
96
+ # Key Audio Insights
97
+ st.subheader("Key Audio Insights")
98
+ st.markdown(f"""
99
+ - **Total Audio Files:** {len(audio_df)}
100
+ - **Average Duration:** {audio_df['duration_sec'].mean():.2f} seconds
101
+ - **Shortest Audio File:** {audio_df.loc[audio_df['duration_sec'].idxmin(), 'file_name']} ({audio_df['duration_sec'].min():.2f} seconds)
102
+ - **Longest Audio File:** {audio_df.loc[audio_df['duration_sec'].idxmax(), 'file_name']} ({audio_df['duration_sec'].max():.2f} seconds)
103
+ """)
104
+
105
+ # Duration Distribution
106
+ st.subheader("Audio Duration Distribution")
107
+ fig, ax = plt.subplots(figsize=(10, 6))
108
+ sns.histplot(audio_df['duration_sec'], bins=20, kde=True, color='skyblue', ax=ax)
109
+ ax.set_title("Audio Duration Distribution", fontsize=16, fontweight='bold')
110
+ ax.set_xlabel("Duration (seconds)", fontsize=12)
111
+ ax.set_ylabel("Frequency", fontsize=12)
112
+ st.pyplot(fig)
113
+
114
+ # Highlight Outliers
115
+ st.subheader("Audio Duration Outliers")
116
+ outlier_threshold = st.slider("Set Outlier Threshold (seconds):", 1.0, float(audio_df['duration_sec'].max()), 25.0, step=0.5)
117
+ outliers = audio_df[audio_df['duration_sec'] > outlier_threshold]
118
+ st.write(outliers if not outliers.empty else "No outliers found above the threshold.")
119
+
120
+ # Optional Filtering
121
+ st.subheader("Filter Audio Files by Duration")
122
+ min_range, max_range = st.slider("Select Duration Range (seconds):", 0.0, float(audio_df['duration_sec'].max()), (0.0, float(audio_df['duration_sec'].max())), step=0.5)
123
+ filtered_files = audio_df[(audio_df['duration_sec'] >= min_range) & (audio_df['duration_sec'] <= max_range)]
124
+ st.write(f"**Number of Files in Range:** {len(filtered_files)}")
125
+ st.dataframe(filtered_files[['file_name', 'duration_sec']])
126
+ else:
127
+ st.warning("No audio data available to display.")
128
+
129
+ # Patient Demographics Tab
130
+ with tabs[2]:
131
+ st.header("Patient Demographics")
132
+ st.subheader("Demographics Data")
133
+ st.dataframe(patient_df)
134
+
135
+ st.subheader("Missing Values Information")
136
+ st.write(patient_df.isna().sum())
137
+
138
+ st.subheader("Key Statistics")
139
+ avg_age, min_age, max_age = patient_df['Age'].mean(), patient_df['Age'].min(), patient_df['Age'].max()
140
+ st.markdown(f"- **Average Age:** {avg_age:.1f} years\n- **Youngest Patient:** {min_age} years\n- **Oldest Patient:** {max_age} years")
141
+
142
+ # Visualizations
143
+ st.markdown("### Age Distribution")
144
+ fig, ax = plt.subplots(figsize=(10, 6))
145
+ sns.histplot(patient_df['Age'].dropna(), bins=20, kde=True, color='skyblue', ax=ax)
146
+ ax.set_title("Age Distribution", fontsize=16, fontweight='bold')
147
+ st.pyplot(fig)
148
+
149
+ st.markdown("### Gender Distribution")
150
+ fig, ax = plt.subplots(figsize=(10, 6))
151
+ sns.barplot(x=patient_df['Sex'].value_counts().index, y=patient_df['Sex'].value_counts().values, palette="coolwarm", ax=ax, hue=patient_df['Sex'].value_counts().index, dodge=False)
152
+ ax.set_title("Gender Distribution", fontsize=16, fontweight='bold')
153
+ st.pyplot(fig)
154
+
155
+
156
+ with tabs[3]:
157
+ st.header("Preprocessing & Audio Effects")
158
+
159
+ # List all .wav files in the AUDIO_PATH directory
160
+ wav_files = [f for f in os.listdir(AUDIO_PATH) if f.endswith('.wav')]
161
+
162
+ if wav_files:
163
+ selected_file_name = st.selectbox("Select an Audio File", wav_files)
164
+
165
+ # Construct the full path of the selected file
166
+ file_path = os.path.join(AUDIO_PATH, selected_file_name)
167
+
168
+ try:
169
+ # Load raw audio
170
+ y_raw, sr = librosa.load(file_path)
171
+ except Exception as e:
172
+ st.error(f"Error loading audio file: {e}")
173
+ st.stop()
174
+
175
+ # Preprocessing and Visualization
176
+ try:
177
+ y_processed, processed_sr = analysis.preprocess_audio(y_raw, sr)
178
+
179
+ # Mel spectrogram
180
+ mel = librosa.feature.melspectrogram(
181
+ y=y_processed, sr=processed_sr, n_fft=2048, hop_length=512, power=2.0
182
+ )
183
+ mel_db = librosa.power_to_db(mel, ref=np.max)
184
+
185
+ # STFT
186
+ stft = librosa.stft(y_processed, n_fft=2048, hop_length=512)
187
+ stft_db = librosa.amplitude_to_db(np.abs(stft), ref=np.max)
188
+
189
+ # Frequency Spectrum
190
+ fft = np.abs(np.fft.rfft(y_processed))
191
+ freqs = np.fft.rfftfreq(len(y_processed), 1 / processed_sr)
192
+
193
+ # Zero-Crossing Rate
194
+ zcr = librosa.feature.zero_crossing_rate(y_processed)[0]
195
+
196
+ # RMS Energy
197
+ rms = librosa.feature.rms(y=y_processed)[0]
198
+
199
+ # Create subplots for visualizations
200
+ fig, axs = plt.subplots(3, 2, figsize=(15, 12))
201
+
202
+ # Raw waveform
203
+ librosa.display.waveshow(y_raw, sr=sr, ax=axs[0, 0])
204
+ axs[0, 0].set_title("Raw Waveform", fontsize=12)
205
+
206
+ # Preprocessed waveform
207
+ librosa.display.waveshow(y_processed, sr=processed_sr, ax=axs[0, 1])
208
+ axs[0, 1].set_title("Preprocessed Waveform", fontsize=12)
209
+
210
+ # Frequency spectrum
211
+ axs[1, 0].plot(freqs, fft, color='blue')
212
+ axs[1, 0].set_title("Frequency Spectrum", fontsize=12)
213
+ axs[1, 0].set_xlabel("Frequency (Hz)")
214
+ axs[1, 0].set_ylabel("Amplitude")
215
+
216
+ # ZCR
217
+ axs[1, 1].plot(zcr, color='green')
218
+ axs[1, 1].set_title("Zero-Crossing Rate", fontsize=12)
219
+ axs[1, 1].set_xlabel("Frames")
220
+ axs[1, 1].set_ylabel("Rate")
221
+
222
+ # RMS Energy
223
+ axs[2, 0].plot(rms, color='red')
224
+ axs[2, 0].set_title("RMS Energy", fontsize=12)
225
+ axs[2, 0].set_xlabel("Frames")
226
+ axs[2, 0].set_ylabel("RMS")
227
+
228
+ # Mel spectrogram
229
+ img_mel = librosa.display.specshow(
230
+ mel_db, sr=processed_sr, x_axis='time', y_axis='mel', ax=axs[2, 1], cmap='viridis'
231
+ )
232
+ axs[2, 1].set_title("Mel Spectrogram", fontsize=12)
233
+ fig.colorbar(img_mel, ax=axs[2, 1], format="%+2.0f dB")
234
+
235
+ # Adjust layout
236
+ plt.tight_layout()
237
+ st.pyplot(fig)
238
+
239
+ except Exception as e:
240
+ st.error(f"Error during audio preprocessing or visualization: {e}")
241
+ st.stop()
242
+
243
+ # Play audio
244
+ st.subheader("Listen to Audio")
245
+ st.audio(file_path, format="audio/wav")
246
+ else:
247
+ st.warning("No audio files found in the directory.")
Model_Inference.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ import os
4
+ import numpy as np
5
+ import pandas as pd
6
+ from sklearn.metrics import (
7
+ accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, confusion_matrix, classification_report, roc_curve
8
+ )
9
+ from tensorflow.keras.models import load_model
10
+ import matplotlib.pyplot as plt
11
+
12
+ # Paths
13
+ MODEL_PATH = "./models"
14
+ DATASET_PATH = "./processed_datasets"
15
+
16
+ # Model and dataset filenames
17
+ MODELS = [
18
+ "final_model_binary_augmented.h5",
19
+ "final_model_binary_log_mel.h5",
20
+ "final_model_binary_mfcc.h5",
21
+ "final_model_multi_augmented.h5",
22
+ "final_model_multi_log_mel.h5",
23
+ "final_model_multi_mfcc.h5"
24
+ ]
25
+
26
+ DATASETS = {
27
+ "binary_augmented": ("X_test_binary_augmented.npy", "y_test_binary_augmented.npy"),
28
+ "binary_log_mel": ("X_test_binary_log_mel.npy", "y_test_binary_log_mel.npy"),
29
+ "binary_mfcc": ("X_test_binary_mfcc.npy", "y_test_binary_mfcc.npy"),
30
+ "multi_augmented": ("X_test_multi_augmented.npy", "y_test_multi_augmented.npy"),
31
+ "multi_log_mel": ("X_test_multi_log_mel.npy", "y_test_multi_log_mel.npy"),
32
+ "multi_mfcc": ("X_test_multi_mfcc.npy", "y_test_multi_mfcc.npy")
33
+ }
34
+
35
+ # Metrics dictionary
36
+ metrics_dict = []
37
+
38
+ # Function to evaluate a model
39
+ def evaluate_model(model, X_test, y_test, mode):
40
+ y_pred_prob = model.predict(X_test)
41
+ y_pred = np.argmax(y_pred_prob, axis=1)
42
+ y_true = np.argmax(y_test, axis=1)
43
+
44
+ accuracy = accuracy_score(y_true, y_pred)
45
+ precision = precision_score(y_true, y_pred, average='weighted')
46
+ recall = recall_score(y_true, y_pred, average='weighted')
47
+ f1 = f1_score(y_true, y_pred, average='weighted')
48
+ auc = roc_auc_score(y_test, y_pred_prob, multi_class='ovr')
49
+ conf_matrix = confusion_matrix(y_true, y_pred)
50
+
51
+ print(f"--- Evaluation for {mode} ---")
52
+ print(f"Accuracy: {accuracy:.4f}")
53
+ print(f"Precision: {precision:.4f}")
54
+ print(f"Recall: {recall:.4f}")
55
+ print(f"F1 Score: {f1:.4f}")
56
+ print(f"ROC-AUC: {auc:.4f}")
57
+ print("Confusion Matrix:")
58
+ print(conf_matrix)
59
+ print("\n")
60
+
61
+ # Log metrics
62
+ metrics_dict.append({
63
+ "Model": mode,
64
+ "Accuracy": accuracy,
65
+ "Precision": precision,
66
+ "Recall": recall,
67
+ "F1 Score": f1,
68
+ "ROC-AUC": auc
69
+ })
70
+
71
+ # Plot ROC curve
72
+ fpr = {}
73
+ tpr = {}
74
+ for i in range(y_test.shape[1]):
75
+ fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_pred_prob[:, i])
76
+ plt.figure(figsize=(10, 6))
77
+ for i, label in enumerate(np.unique(y_true)):
78
+ plt.plot(fpr[i], tpr[i], label=f"Class {label} ROC")
79
+ plt.plot([0, 1], [0, 1], 'k--', label='Chance')
80
+ plt.xlabel('False Positive Rate')
81
+ plt.ylabel('True Positive Rate')
82
+ plt.title(f"ROC Curve - {mode}")
83
+ plt.legend()
84
+ plt.savefig(f"roc_curve_{mode}.png")
85
+ plt.close()
86
+
87
+ # Evaluate all models
88
+ for model_name in MODELS:
89
+ mode_key = model_name.replace("final_model_", "").replace(".h5", "").replace(" ", "_").lower()
90
+ dataset = DATASETS.get(mode_key)
91
+
92
+ if dataset:
93
+ # Load the model and dataset
94
+ model_path = os.path.join(MODEL_PATH, model_name)
95
+ model = load_model(model_path)
96
+
97
+ X_test_path, y_test_path = dataset
98
+ X_test = np.load(os.path.join(DATASET_PATH, X_test_path))
99
+ y_test = np.load(os.path.join(DATASET_PATH, y_test_path))
100
+
101
+ # Evaluate the model
102
+ evaluate_model(model, X_test, y_test, mode_key)
103
+ else:
104
+ print(f"No dataset found for model: {model_name}")
105
+
106
+ # Save metrics as a CSV
107
+ metrics_df = pd.DataFrame(metrics_dict)
108
+ metrics_df.to_csv("model_evaluation_summary.csv", index=False)
109
+ print("Evaluation complete. Summary saved as 'model_evaluation_summary.csv'.")
README.md CHANGED
@@ -1,12 +1 @@
1
- ---
2
- title: Amp
3
- emoji: 🔥
4
- colorFrom: purple
5
- colorTo: green
6
- sdk: streamlit
7
- sdk_version: 1.41.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ "# amp1"
 
 
 
 
 
 
 
 
 
 
 
Train.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import numpy as np
3
+ from utils.data_loader import load_data, process_audio_metadata
4
+ from utils.audioprocessing import *
5
+ from utils.model_utils import *
6
+ import joblib
7
+ from utils.evaluation import log_metrics, plot_roc_curve, plot_confusion_matrix
8
+ import os
9
+ import gc
10
+ from joblib import Parallel, delayed
11
+ import mlflow
12
+ import mlflow.keras
13
+ import pandas as pd
14
+ import librosa
15
+ import librosa.display
16
+ import optuna
17
+ from tqdm import tqdm
18
+ import matplotlib.pyplot as plt
19
+ from sklearn.metrics import roc_auc_score, roc_curve, confusion_matrix, classification_report
20
+ from sklearn.model_selection import train_test_split
21
+ from sklearn.preprocessing import LabelEncoder
22
+ from keras.utils import to_categorical, normalize
23
+ from keras.layers import Conv2D, Dense, MaxPooling2D, Flatten, Dropout, BatchNormalization, GlobalAveragePooling2D
24
+ from imblearn.over_sampling import SMOTE
25
+ from tensorflow.keras.models import Sequential, Model
26
+ from tensorflow.keras.layers import Conv1D, GRU, Input, add, Dense, Dropout, BatchNormalization, LeakyReLU
27
+ from tensorflow.keras.optimizers import Adamax
28
+ from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
29
+ from tensorflow.keras.preprocessing.image import ImageDataGenerator
30
+
31
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # Suppress INFO and WARNING logs from TensorFlow
32
+ os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' # Disable oneDNN optimizations
33
+
34
+ # Configure logging
35
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
36
+ data_logger = logging.getLogger("data_pipeline")
37
+ train_logger = logging.getLogger("train")
38
+ processing_logger = logging.getLogger("data_processing")
39
+ model_logger = logging.getLogger("model_training")
40
+
41
+ # Dataset and Paths
42
+ AUDIO_FILES_PATH = 'D://github//AmpleHealth//data//Respiratory_Sound_Database//audio_and_txt_files'
43
+ METADATA_PATH = 'D://github//AmpleHealth//data//Respiratory_Sound_Database//audio_and_txt_files'
44
+
45
+ def save_dataset(X, y, mode, output_dir="c"):
46
+ """
47
+ Save the processed X and y to .npy files.
48
+
49
+ Args:
50
+ X: Processed features.
51
+ y: Processed labels.
52
+ mode: Mode for which the dataset is processed.
53
+ output_dir: Directory to save the .npy files.
54
+ """
55
+ import os
56
+
57
+ # Ensure the output directory exists
58
+ os.makedirs(output_dir, exist_ok=True)
59
+
60
+ # Save files with mode-specific names
61
+ X_path = os.path.join(output_dir, f"X_{mode}.npy")
62
+ y_path = os.path.join(output_dir, f"y_{mode}.npy")
63
+
64
+ np.save(X_path, X)
65
+ np.save(y_path, y)
66
+ processing_logger.info(f"Saved dataset for mode '{mode}' to {output_dir}")
67
+
68
+
69
+ def load_or_process_dataset(df_filtered, audio_files_path, mode, output_dir="processed_datasets"):
70
+
71
+ #output_dir = os.path.abspath(output_dir)
72
+ # File paths for preprocessed data
73
+ X_path = os.path.join(output_dir, f"X_{mode}.npy")
74
+ y_path = os.path.join(output_dir, f"y_{mode}.npy")
75
+
76
+ # Check if the files exist
77
+ if os.path.exists(X_path) and os.path.exists(y_path):
78
+ processing_logger.info(f"Preprocessed files found for mode '{mode}'. Loading from disk...")
79
+ X = np.load(X_path)
80
+ y = np.load(y_path)
81
+ else:
82
+ processing_logger.info(f"Preprocessed files not found for mode '{mode}'. Processing data...")
83
+ os.makedirs(output_dir, exist_ok=True)
84
+
85
+ if mode == 'augmented':
86
+ X, y, le = prepare_dataset_augmented(df_filtered, audio_files_path)
87
+ else:
88
+ X, y, le = prepare_dataset_parallel(df_filtered, audio_files_path, mode=mode)
89
+
90
+
91
+
92
+ # Save the processed data and LabelEncoder
93
+ np.save(X_path, X)
94
+ np.save(y_path, y)
95
+ processing_logger.info(f"Saved processed dataset and LabelEncoder for mode '{mode}' to {output_dir}")
96
+
97
+ le = LabelEncoder()
98
+ return X, y, le
99
+
100
+
101
+ def main():
102
+ data_logger.info("Starting data pipeline.")
103
+
104
+ # Step 1: Load and preprocess data
105
+ data_logger.info("Loading and preprocessing data...")
106
+ df = load_data()
107
+ audio_metadata = process_audio_metadata(METADATA_PATH)
108
+ df_all = merge_datasets(audio_metadata, df)
109
+
110
+ # Define classification modes and feature types
111
+ classification_modes = [ 'multi', 'binary']#
112
+ feature_types = [ 'augmented','mfcc', 'log_mel'] #,
113
+
114
+ for classification_mode in classification_modes:
115
+ # Preprocess dataset for binary or multi-class classification
116
+ df_filtered = filter_and_sample_data(df_all, mode=classification_mode)
117
+
118
+ for feature_type in feature_types:
119
+ processing_logger.info(f"Preparing dataset for {classification_mode} classification with {feature_type} features.")
120
+
121
+ # Load or process dataset
122
+ X, y, le = load_or_process_dataset(df_filtered, AUDIO_FILES_PATH, feature_type, output_dir=f"processed_datasets/{classification_mode}")
123
+
124
+ # Log input dimensions
125
+ processing_logger.info(f"Input data dimensions for {feature_type}: {X.shape}")
126
+ processing_logger.info(f"Output data dimensions for {feature_type}: {y.shape}")
127
+
128
+ # Split dataset
129
+ processing_logger.info("Splitting dataset...")
130
+ X_train, X_val, X_test, y_train, y_val, y_test = split_dataset(X, y)
131
+
132
+ # Check for class balance
133
+ unique_classes, class_counts = np.unique(np.argmax(y_train, axis=1), return_counts=True)
134
+ processing_logger.info(f"Class distribution before oversampling: {dict(zip(unique_classes, class_counts))}")
135
+
136
+ try:
137
+ X_train, y_train = oversample_data(X_train, y_train)
138
+ unique_classes, class_counts = np.unique(np.argmax(y_train, axis=1), return_counts=True)
139
+ processing_logger.info(f"Class distribution after oversampling: {dict(zip(unique_classes, class_counts))}")
140
+ except ValueError as e:
141
+ processing_logger.warning(f"SMOTE skipped: {e}")
142
+
143
+
144
+ # Log dimensions after preprocessing
145
+ processing_logger.info(f"Training data dimensions for {feature_type}: X_train={X_train.shape}, y_train={y_train.shape}")
146
+ processing_logger.info(f"Validation data dimensions for {feature_type}: X_val={X_val.shape}, y_val={y_val.shape}")
147
+ processing_logger.info(f"Test data dimensions for {feature_type}: X_test={X_test.shape}, y_test={y_test.shape}")
148
+
149
+ # Train and optimize model
150
+ model_logger.info(f"Running optimization for {feature_type} mode...")
151
+
152
+ if feature_type == 'augmented': # Train 1D CNN for GRU features
153
+ X_train = np.expand_dims(X_train, axis=-1)
154
+ X_val = np.expand_dims(X_val, axis=-1)
155
+ X_test = np.expand_dims(X_test, axis=-1)
156
+
157
+ model_logger.info(f"Updated 1D CNN Input dimensions: X_train={X_train.shape}, X_val={X_val.shape}, X_test={X_test.shape}")
158
+
159
+ best_params = run_optuna_optimization(
160
+ model_type="1D",
161
+ input_shape=X_train.shape[1:],
162
+ num_classes=y_train.shape[1],
163
+ X_train=X_train,
164
+ y_train=y_train,
165
+ X_val=X_val,
166
+ y_val=y_val,
167
+ n_trials=20
168
+ )
169
+ best_model = build_cnn_model(
170
+ input_shape=X_train.shape[1:],
171
+ n_filters=best_params["n_filters"],
172
+ dense_units=best_params["dense_units"],
173
+ dropout_rate=best_params["dropout_rate"],
174
+ num_classes=y_train.shape[1],
175
+ model_type="1D"
176
+ )
177
+ else: # Train 2D CNN for MFCC and Log-Mel
178
+ best_params = run_optuna_optimization(
179
+ model_type="2D",
180
+ input_shape=X_train.shape[1:],
181
+ num_classes=y_train.shape[1],
182
+ X_train=X_train,
183
+ y_train=y_train,
184
+ X_val=X_val,
185
+ y_val=y_val,
186
+ n_trials=20
187
+ )
188
+ best_model = build_cnn_model(
189
+ input_shape=X_train.shape[1:],
190
+ n_filters=best_params["n_filters"],
191
+ dense_units=best_params["dense_units"],
192
+ dropout_rate=best_params["dropout_rate"],
193
+ num_classes=y_train.shape[1],
194
+ model_type="2D"
195
+ )
196
+
197
+ model_logger.info(f"Model input shape: {X_train.shape[1:]}")
198
+ model_logger.info(f"Number of output classes: {y_train.shape[1]}")
199
+
200
+ # Train and save the model
201
+ best_model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=10, batch_size=32)
202
+ model_path = f".models/best_model_{classification_mode}_{feature_type}.h5"
203
+ best_model.save(model_path)
204
+ mlflow.log_artifact(model_path)
205
+
206
+ # Evaluate model
207
+ y_pred = best_model.predict(X_test)
208
+ log_metrics(y_test, y_pred, f"{classification_mode}_{feature_type}")
209
+
210
+ data_logger.info("Pipeline completed successfully.")
211
+
212
+
213
+ if __name__ == "__main__":
214
+ main()
215
+
data/Respiratory_Sound_Database/filename_differences.txt ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '101_1b1_Al_sc_AKGC417L'
2
+ '101_1b1_Pr_sc_AKGC417L'
3
+ '102_1b1_Ar_sc_AKGC417L'
4
+ '105_1b1_Tc_sc_LittC2SE'
5
+ '108_1b1_Al_sc_LittC2SE'
6
+ '111_1b2_Tc_sc_LittC2SE'
7
+ '111_1b3_Tc_sc_LittC2SE'
8
+ '115_1b1_Ar_sc_LittC2SE'
9
+ '116_1b2_Pl_sc_LittC2SE'
10
+ '116_1b2_Tc_sc_LittC2SE'
11
+ '119_1b1_Ar_sc_AKGC417L'
12
+ '121_1b1_Tc_sc_LittC2SE'
13
+ '121_1p1_Tc_sc_LittC2SE'
14
+ '123_1b1_Al_sc_AKGC417L'
15
+ '125_1b1_Tc_sc_LittC2SE'
16
+ '126_1b1_Al_sc_AKGC417L'
17
+ '127_1b1_Ar_sc_LittC2SE'
18
+ '129_1b1_Ar_sc_LittC2SE'
19
+ '131_1b1_Al_sc_LittC2SE'
20
+ '136_1b1_Ar_sc_AKGC417L'
21
+ '137_1b1_Ar_sc_LittC2SE'
22
+ '137_1b1_Ll_sc_LittC2SE'
23
+ '143_1b1_Al_sc_AKGC417L'
24
+ '144_1b1_Al_sc_AKGC417L'
25
+ '144_1b1_Tc_sc_AKGC417L'
26
+ '148_1b1_Al_sc_LittC2SE'
27
+ '149_1b1_Al_sc_LittC2SE'
28
+ '149_1b1_Lr_sc_LittC2SE'
29
+ '149_1b1_Pl_sc_LittC2SE'
30
+ '150_1b2_Al_sc_AKGC417L'
31
+ '152_1b1_Al_sc_LittC2SE'
32
+ '153_1b1_Al_sc_LittC2SE'
33
+ '159_1b1_Al_sc_AKGC417L'
34
+ '159_1b1_Ar_sc_AKGC417L'
35
+ '159_1b1_Ll_sc_AKGC417L'
36
+ '159_1b1_Pr_sc_AKGC417L'
37
+ '161_1b1_Al_sc_LittC2SE'
38
+ '161_1b1_Pl_sc_LittC2SE'
39
+ '164_1b1_Ll_sc_LittC2SE'
40
+ '165_1b1_Ar_sc_AKGC417L'
41
+ '165_1b1_Pl_sc_AKGC417L'
42
+ '165_1b1_Pr_sc_AKGC417L'
43
+ '167_1b1_Al_sc_LittC2SE'
44
+ '167_1b1_Pr_sc_LittC2SE'
45
+ '168_1b1_Al_sc_LittC2SE'
46
+ '169_1b1_Lr_sc_AKGC417L'
47
+ '169_1b2_Ll_sc_AKGC417L'
48
+ '171_1b1_Al_sc_AKGC417L'
49
+ '173_1b1_Al_sc_AKGC417L'
50
+ '179_1b1_Al_sc_LittC2SE'
51
+ '179_1b1_Tc_sc_LittC2SE'
52
+ '182_1b1_Tc_sc_LittC2SE'
53
+ '183_1b1_Pl_sc_AKGC417L'
54
+ '183_1b1_Tc_sc_AKGC417L'
55
+ '184_1b1_Ar_sc_LittC2SE'
56
+ '187_1b1_Ll_sc_AKGC417L'
57
+ '188_1b1_Al_sc_LittC2SE'
58
+ '188_1b1_Ar_sc_LittC2SE'
59
+ '188_1b1_Pl_sc_LittC2SE'
60
+ '188_1b1_Tc_sc_LittC2SE'
61
+ '190_1b1_Tc_sc_AKGC417L'
62
+ '194_1b1_Lr_sc_AKGC417L'
63
+ '194_1b1_Pr_sc_AKGC417L'
64
+ '196_1b1_Pr_sc_LittC2SE'
65
+ '197_1b1_Al_sc_AKGC417L'
66
+ '197_1b1_Tc_sc_AKGC417L'
67
+ '201_1b1_Al_sc_LittC2SE'
68
+ '201_1b1_Ar_sc_LittC2SE'
69
+ '201_1b2_Al_sc_LittC2SE'
70
+ '201_1b2_Ar_sc_LittC2SE'
71
+ '201_1b3_Al_sc_LittC2SE'
72
+ '201_1b3_Ar_sc_LittC2SE'
73
+ '202_1b1_Ar_sc_AKGC417L'
74
+ '206_1b1_Ar_sc_LittC2SE'
75
+ '206_1b1_Lr_sc_LittC2SE'
76
+ '206_1b1_Pl_sc_LittC2SE'
77
+ '208_1b1_Ll_sc_LittC2SE'
78
+ '209_1b1_Tc_sc_LittC2SE'
79
+ '210_1b1_Al_sc_LittC2SE'
80
+ '210_1b1_Ar_sc_LittC2SE'
81
+ '214_1b1_Ar_sc_AKGC417L'
82
+ '215_1b2_Ar_sc_LittC2SE'
83
+ '215_1b3_Tc_sc_LittC2SE'
84
+ '216_1b1_Al_sc_AKGC417L'
85
+ '216_1b1_Pl_sc_AKGC417L'
86
+ '217_1b1_Tc_sc_LittC2SE'
87
+ '224_1b1_Tc_sc_AKGC417L'
88
+ '224_1b2_Al_sc_AKGC417L'
89
+ '225_1b1_Pl_sc_AKGC417L'
90
+ '226_1b1_Al_sc_LittC2SE'
91
+ '226_1b1_Ll_sc_LittC2SE'
data/Respiratory_Sound_Database/filename_format.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Elements contained in the filenames:
2
+
3
+ Patient number (101,102,...,226)
4
+ Recording index
5
+ Chest location (Trachea (Tc), {Anterior (A), Posterior (P), Lateral (L)}{left (l), right (r)})
6
+ Acquisition mode (sequential/single channel (sc), simultaneous/multichannel (mc))
7
+ Recording equipment (AKG C417L Microphone, 3M Littmann Classic II SE Stethoscope, 3M Litmmann 3200 Electronic Stethoscope, WelchAllyn Meditron Master Elite Electronic Stethoscope)
data/Respiratory_Sound_Database/patient_diagnosis.csv ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 101,URTI
2
+ 102,Healthy
3
+ 103,Asthma
4
+ 104,COPD
5
+ 105,URTI
6
+ 106,COPD
7
+ 107,COPD
8
+ 108,LRTI
9
+ 109,COPD
10
+ 110,COPD
11
+ 111,Bronchiectasis
12
+ 112,COPD
13
+ 113,COPD
14
+ 114,COPD
15
+ 115,LRTI
16
+ 116,Bronchiectasis
17
+ 117,COPD
18
+ 118,COPD
19
+ 119,URTI
20
+ 120,COPD
21
+ 121,Healthy
22
+ 122,Pneumonia
23
+ 123,Healthy
24
+ 124,COPD
25
+ 125,Healthy
26
+ 126,Healthy
27
+ 127,Healthy
28
+ 128,COPD
29
+ 129,URTI
30
+ 130,COPD
31
+ 131,URTI
32
+ 132,COPD
33
+ 133,COPD
34
+ 134,COPD
35
+ 135,Pneumonia
36
+ 136,Healthy
37
+ 137,URTI
38
+ 138,COPD
39
+ 139,COPD
40
+ 140,Pneumonia
41
+ 141,COPD
42
+ 142,COPD
43
+ 143,Healthy
44
+ 144,Healthy
45
+ 145,COPD
46
+ 146,COPD
47
+ 147,COPD
48
+ 148,URTI
49
+ 149,Bronchiolitis
50
+ 150,URTI
51
+ 151,COPD
52
+ 152,Healthy
53
+ 153,Healthy
54
+ 154,COPD
55
+ 155,COPD
56
+ 156,COPD
57
+ 157,COPD
58
+ 158,COPD
59
+ 159,Healthy
60
+ 160,COPD
61
+ 161,Bronchiolitis
62
+ 162,COPD
63
+ 163,COPD
64
+ 164,URTI
65
+ 165,URTI
66
+ 166,COPD
67
+ 167,Bronchiolitis
68
+ 168,Bronchiectasis
69
+ 169,Bronchiectasis
70
+ 170,COPD
71
+ 171,Healthy
72
+ 172,COPD
73
+ 173,Bronchiolitis
74
+ 174,COPD
75
+ 175,COPD
76
+ 176,COPD
77
+ 177,COPD
78
+ 178,COPD
79
+ 179,Healthy
80
+ 180,COPD
81
+ 181,COPD
82
+ 182,Healthy
83
+ 183,Healthy
84
+ 184,Healthy
85
+ 185,COPD
86
+ 186,COPD
87
+ 187,Healthy
88
+ 188,URTI
89
+ 189,COPD
90
+ 190,URTI
91
+ 191,Pneumonia
92
+ 192,COPD
93
+ 193,COPD
94
+ 194,Healthy
95
+ 195,COPD
96
+ 196,Bronchiectasis
97
+ 197,URTI
98
+ 198,COPD
99
+ 199,COPD
100
+ 200,COPD
101
+ 201,Bronchiectasis
102
+ 202,Healthy
103
+ 203,COPD
104
+ 204,COPD
105
+ 205,COPD
106
+ 206,Bronchiolitis
107
+ 207,COPD
108
+ 208,Healthy
109
+ 209,Healthy
110
+ 210,URTI
111
+ 211,COPD
112
+ 212,COPD
113
+ 213,COPD
114
+ 214,Healthy
115
+ 215,Bronchiectasis
116
+ 216,Bronchiolitis
117
+ 217,Healthy
118
+ 218,COPD
119
+ 219,Pneumonia
120
+ 220,COPD
121
+ 221,COPD
122
+ 222,COPD
123
+ 223,COPD
124
+ 224,Healthy
125
+ 225,Healthy
126
+ 226,Pneumonia
data/Respiratory_Sound_Database/testsample/101_1b1_Al_sc_Meditron.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0.036 0.579 0 0
2
+ 0.579 2.45 0 0
3
+ 2.45 3.893 0 0
4
+ 3.893 5.793 0 0
5
+ 5.793 7.521 0 0
6
+ 7.521 9.279 0 0
7
+ 9.279 11.15 0 0
8
+ 11.15 13.036 0 0
9
+ 13.036 14.721 0 0
10
+ 14.721 16.707 0 0
11
+ 16.707 18.507 0 0
12
+ 18.507 19.964 0 0
data/Respiratory_Sound_Database/testsample/101_1b1_Al_sc_Meditron.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8cecba490774f874dab3bd907ddd2de6a6c42df2a50f46e7436cea3adaa3d724
3
+ size 2646044
data/Respiratory_Sound_Database/testsample/101_1b1_Pr_sc_Meditron.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0.036 1.264 0 0
2
+ 1.264 3.422 0 0
3
+ 3.422 5.55 0 0
4
+ 5.55 7.436 0 0
5
+ 7.436 9.221 0 0
6
+ 9.221 11.264 0 0
7
+ 11.264 13.264 0 0
8
+ 13.264 15.179 0 0
9
+ 15.179 17.207 0 0
10
+ 17.207 19.179 0 0
11
+ 19.179 19.936 0 0
data/Respiratory_Sound_Database/testsample/101_1b1_Pr_sc_Meditron.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6d6a959f758d90e4a1cdc3da55b9d2cfcc23860691cb23cd6eab8c2d5cf4c7b8
3
+ size 2646044
data/Respiratory_Sound_Database/testsample/102_1b1_Ar_sc_Meditron.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0.264 1.736 0 0
2
+ 1.736 3.293 0 0
3
+ 3.293 5.307 0 0
4
+ 5.307 6.636 0 0
5
+ 6.636 8.036 0 0
6
+ 8.036 9.607 0 0
7
+ 9.607 11.036 0 0
8
+ 11.036 13.036 0 0
9
+ 13.036 14.664 0 0
10
+ 14.664 16.393 0 0
11
+ 16.393 17.893 0 0
12
+ 17.893 19.593 0 0
13
+ 19.593 19.964 0 0
data/Respiratory_Sound_Database/testsample/102_1b1_Ar_sc_Meditron.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:46f1864cee63d51cdf8d2278284614d7a9da7a4860bbd0c04d5cdc4283a24753
3
+ size 1764044
data/Respiratory_Sound_Database/testsample/103_2b2_Ar_mc_LittC2SE.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ 0.364 3.25 0 1
2
+ 3.25 6.636 0 0
3
+ 6.636 11.179 0 1
4
+ 11.179 14.25 0 1
5
+ 14.25 16.993 0 1
6
+ 16.993 19.979 0 0
data/Respiratory_Sound_Database/testsample/103_2b2_Ar_mc_LittC2SE.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6a27e314b07ea8f3830cb45480b2209325ec9e432dd9281e4ce6ebe3c75a629a
3
+ size 2646044
data/Respiratory_Sound_Database/testsample/104_1b1_Al_sc_Litt3200.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ 0 1.8771 0 0
2
+ 1.8771 3.7543 0 0
3
+ 3.7543 6.1071 0 0
4
+ 6.1071 8.2502 0 0
5
+ 8.2502 12.618 0 0
6
+ 12.618 15.856 0 0
data/Respiratory_Sound_Database/testsample/104_1b1_Al_sc_Litt3200.wav ADDED
Binary file (127 kB). View file
 
data/Respiratory_Sound_Database/testsample/104_1b1_Ar_sc_Litt3200.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0 0.54469 0 1
2
+ 0.54469 2.9628 0 1
3
+ 2.9628 5.1085 0 1
4
+ 5.1085 7.2172 0 1
5
+ 7.2172 9.1442 0 1
6
+ 9.1442 10.675 0 1
7
+ 10.675 12.371 0 1
8
+ 12.371 14.381 0 1
9
+ 14.381 16.535 0 1
10
+ 16.535 19.048 0 1
11
+ 19.048 22.176 0 0
12
+ 22.176 22.951 0 0
13
+ 22.951 24.664 0 0
14
+ 24.664 25.584 0 0
data/__pycache__/data_loader.cpython-312.pyc ADDED
Binary file (4.6 kB). View file
 
data/demographic_info.txt ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ 101 3 F NA 19 99
3
+ 102 0.75 F NA 9.8 73
4
+ 103 70 F 33 NA NA
5
+ 104 70 F 28.47 NA NA
6
+ 105 7 F NA 32 135
7
+ 106 73 F 21 NA NA
8
+ 107 75 F 33.7 NA NA
9
+ 108 3 M NA NA NA
10
+ 109 84 F 33.53 NA NA
11
+ 110 75 M 25.21 NA NA
12
+ 111 63 M 28.4 NA NA
13
+ 112 60 M 22.86 NA NA
14
+ 113 58 M 28.41 NA NA
15
+ 114 77 M 23.12 NA NA
16
+ 115 0.58 M NA 7.14 64
17
+ 116 56 M 28.58 NA NA
18
+ 117 68 M 24.4 NA NA
19
+ 118 81 M 36.76 NA NA
20
+ 119 2 F NA 15.2 94
21
+ 120 78 M 35.14 NA NA
22
+ 121 13 F NA 65 170
23
+ 122 66 M 33 NA NA
24
+ 123 5 M NA 25 125
25
+ 124 65 M 29.07 NA NA
26
+ 125 14 M NA 62 170
27
+ 126 1 F NA 10.18 80
28
+ 127 2 M NA 12.6 98
29
+ 128 65 F 24.3 NA NA
30
+ 129 6 M NA 23 119
31
+ 130 85 F 17.1 NA NA
32
+ 131 3 M NA 14 97
33
+ 132 71 M 34 NA NA
34
+ 133 68 M 27.4 NA NA
35
+ 134 61 M 32 NA NA
36
+ 135 70 M 21 NA NA
37
+ 136 5 M NA 16.2 110
38
+ 137 4 M NA 18 104
39
+ 138 56 F 21.6 NA NA
40
+ 139 61 M 28.68 NA NA
41
+ 140 79 F 23 NA NA
42
+ 141 66 M 22.4 NA NA
43
+ 142 78 M 26.1 NA NA
44
+ 143 0.25 F NA 8.24 68
45
+ 144 3 M NA 16.7 100
46
+ 145 69 M 23.4 NA NA
47
+ 146 67 M 28 NA NA
48
+ 147 77 M 25.7 NA NA
49
+ 148 4 M NA 33 110
50
+ 149 0.67 M NA 9.5 70
51
+ 150 0.67 F NA 8.12 74
52
+ 151 75 M 28.4 NA NA
53
+ 152 16 M NA 70 183
54
+ 153 3 M NA 16.7 103
55
+ 154 65 M 28.1 NA NA
56
+ 155 69 M 26 NA NA
57
+ 156 80 M 22.9 NA NA
58
+ 157 62 M 53.5 NA NA
59
+ 158 63 M 16.5 NA NA
60
+ 159 0.83 F NA 11 80
61
+ 160 74 M 27.4 NA NA
62
+ 161 2 F NA 12 85
63
+ 162 67 F 24.9 NA NA
64
+ 163 62 M 28.3 NA NA
65
+ 164 1 M NA 13 NA
66
+ 165 2 F NA 12.7 97
67
+ 166 71 M 25.06 NA NA
68
+ 167 1 F NA 11.5 86.4
69
+ 168 19 F 17.35 NA NA
70
+ 169 50 F 28.81 NA NA
71
+ 170 79 M 22.6 NA NA
72
+ 171 9 M NA 32 133
73
+ 172 73 M 29.3 NA NA
74
+ 173 3 M NA 17.3 NA
75
+ 174 68 M 26.4 NA NA
76
+ 175 63 M 28.34 NA NA
77
+ 176 65 M 30.1 NA NA
78
+ 177 56 M 22.1 NA NA
79
+ 178 58 M 30.1 NA NA
80
+ 179 10 F NA 15 104
81
+ 180 93 M 29.03 NA NA
82
+ 181 65 M 26.4 NA NA
83
+ 182 11 M NA 33 136
84
+ 183 14 F NA NA NA
85
+ 184 2 F NA 15 100
86
+ 185 75 M 27.7 NA NA
87
+ 186 71 M 30 NA NA
88
+ 187 0.5 F NA 8.26 71
89
+ 188 3 M NA 16 100
90
+ 189 75 F 26.2 NA NA
91
+ 190 3 F NA NA NA
92
+ 191 74 F 36 NA NA
93
+ 192 69 M 28 NA NA
94
+ 193 77 M 26.3 NA NA
95
+ 194 2 M NA 12.8 86
96
+ 195 67 M 29.41 NA NA
97
+ 196 21 F 25.5 NA NA
98
+ 197 16 F NA NA NA
99
+ 198 71 M 18.6 NA NA
100
+ 199 71 M 20 NA NA
101
+ 200 72 F 27.8 NA NA
102
+ 201 73 F 28.52 NA NA
103
+ 202 2 M NA 11.84 87
104
+ 203 57 F 24 NA NA
105
+ 204 66 M 29.76 NA NA
106
+ 205 45 M 20.1 NA NA
107
+ 206 3 M NA 13 92
108
+ 207 63 F 29.6 NA NA
109
+ 208 5 F NA 24.1 117
110
+ 209 14 F NA 80 183
111
+ 210 1 F NA 12.96 76
112
+ 211 70 F 31.1 NA NA
113
+ 212 83 M 23 NA NA
114
+ 213 58 F 24.7 NA NA
115
+ 214 5 M NA 30 118
116
+ 215 56 F 25.35 NA NA
117
+ 216 1 M NA 10.25 78
118
+ 217 12 F NA NA NA
119
+ 218 75 M 26.29 NA NA
120
+ 219 81 M 26 NA NA
121
+ 220 66 M 35.4 NA NA
122
+ 221 74 F 29 NA NA
123
+ 222 60 M NA NA NA
124
+ 223 NA NA NA NA NA
125
+ 224 10 F NA 32.3 143
126
+ 225 0.83 M NA 7.8 74
127
+ 226 4 M NA 16.7 103
deployTest.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import numpy as np
4
+ import librosa
5
+ from sklearn.preprocessing import normalize
6
+ from tensorflow.keras.models import load_model
7
+ from scipy.signal import butter, sosfilt
8
+
9
+ # Set up logging
10
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
+ logger = logging.getLogger("audio_classifier_test")
12
+
13
+ # Paths and Constants
14
+ MODEL_PATH = "./models"
15
+ FILE_PATH = "101_1b1_Al_sc_Meditron.wav"
16
+ MODELS = {
17
+ "binary": {
18
+ "augmented": "final_model_binary_augmented.h5",
19
+ "log_mel": "final_model_binary_log_mel.h5",
20
+ "mfcc": "final_model_binary_mfcc.h5",
21
+ },
22
+ "multi": {
23
+ "augmented": "final_model_multi_augmented.h5",
24
+ "log_mel": "final_model_multi_log_mel.h5",
25
+ "mfcc": "final_model_multi_mfcc.h5",
26
+ }
27
+ }
28
+ CLASS_NAMES = {
29
+ "binary": ["Abnormal", "Normal"],
30
+ "multi": ["Chronic Respiratory Diseases", "Normal", "Respiratory Infections"]
31
+ }
32
+
33
+
34
+ # Augmentation Functions
35
+ def add_noise(data, noise_factor=0.001):
36
+ noise = np.random.randn(len(data))
37
+ return data + noise_factor * noise
38
+
39
+ def shift(data, shift_factor=1600):
40
+ return np.roll(data, shift_factor)
41
+
42
+ def stretch(data, rate=1.2):
43
+ return librosa.effects.time_stretch(data, rate=rate)
44
+
45
+ def pitch_shift(data, sr, n_steps=3):
46
+ return librosa.effects.pitch_shift(data, sr=sr, n_steps=n_steps)
47
+
48
+
49
+
50
+ def filtering(audio, sr):
51
+ """
52
+ Apply a bandpass filter to audio data.
53
+
54
+ Args:
55
+ audio: The input audio signal.
56
+ sr: The sampling rate of the audio.
57
+
58
+ Returns:
59
+ Filtered audio signal.
60
+ """
61
+ # Define cutoff frequencies
62
+ low_cutoff = 50 # 50 Hz
63
+ high_cutoff = min(5000, sr / 2 - 1) # Ensure it is below Nyquist frequency
64
+
65
+ if low_cutoff >= high_cutoff:
66
+ raise ValueError(
67
+ f"Invalid filter range: low_cutoff={low_cutoff}, high_cutoff={high_cutoff} for sampling rate {sr}"
68
+ )
69
+
70
+ # Design a bandpass filter
71
+ sos = butter(N=10, Wn=[low_cutoff, high_cutoff], btype='band', fs=sr, output='sos')
72
+
73
+ # Apply the filter
74
+ filtered_audio = sosfilt(sos, audio)
75
+ return filtered_audio
76
+
77
+
78
+ def preprocess_audio(audio_file, mode="augmented", input_shape=None):
79
+ """
80
+ Preprocess an audio file for classification by resampling, padding/truncating,
81
+ and extracting features (e.g., MFCC, Log-Mel spectrogram, or Augmented features).
82
+
83
+ Args:
84
+ audio_file: Path to the audio file.
85
+ mode: Feature extraction mode ('mfcc', 'log_mel', or 'augmented').
86
+ input_shape: Expected input shape of the model for feature alignment.
87
+
88
+ Returns:
89
+ Extracted features as per the mode.
90
+ """
91
+ try:
92
+ sr_new = 16000 # Resample audio to 16 kHz
93
+ x, sr = librosa.load(audio_file, sr=sr_new)
94
+ x = filtering(x, sr)
95
+ logger.info(f"Loaded audio file '{audio_file}' with shape {x.shape} and sampling rate {sr}.")
96
+
97
+ max_len = 5 * sr_new
98
+ if x.shape[0] < max_len:
99
+ x = np.pad(x, (0, max_len - x.shape[0]))
100
+ logger.info(f"Audio padded to {max_len} samples.")
101
+ else:
102
+ x = x[:max_len]
103
+ logger.info(f"Audio truncated to {max_len} samples.")
104
+
105
+ # Handle each mode separately
106
+ if mode == 'mfcc':
107
+ feature = librosa.feature.mfcc(y=x, sr=sr_new, n_mfcc=20) # Extract MFCC
108
+ feature = normalize(feature, axis=1)
109
+
110
+ elif mode == 'log_mel':
111
+ mel_spec = librosa.feature.melspectrogram(y=x, sr=sr_new, n_mels=20, fmax=8000)
112
+ feature = librosa.power_to_db(mel_spec, ref=np.max) # Extract Log-Mel spectrogram
113
+ feature = normalize(feature, axis=1)
114
+
115
+ elif mode == 'augmented':
116
+ features = []
117
+
118
+ # Base MFCC
119
+ base_mfcc = np.mean(librosa.feature.mfcc(y=x, sr=sr_new, n_mfcc=52).T, axis=0)
120
+ features.append(base_mfcc)
121
+
122
+ # Augmented features
123
+ for augmentation in [
124
+ lambda d: add_noise(d, 0.001),
125
+ lambda d: shift(d, 1600),
126
+ lambda d: stretch(d, 1.2),
127
+ lambda d: pitch_shift(d, sr_new, 3)
128
+ ]:
129
+ augmented_data = augmentation(x)
130
+ aug_mfcc = np.mean(librosa.feature.mfcc(y=augmented_data, sr=sr_new, n_mfcc=52).T, axis=0)
131
+ features.append(aug_mfcc)
132
+
133
+ # Average augmented features
134
+ feature = np.mean(features, axis=0)
135
+ feature = normalize(feature.reshape(1, -1), axis=1).flatten() # Normalize
136
+
137
+ else:
138
+ raise ValueError(f"Unknown mode: {mode}")
139
+
140
+ # Reshape for model input if required
141
+ if input_shape:
142
+ feature = _reshape_feature(feature, input_shape)
143
+
144
+ logger.info(f"Feature extracted with shape {feature.shape}.")
145
+ return np.expand_dims(feature, axis=-1) # Add channel dimension
146
+
147
+ except Exception as e:
148
+ logger.error(f"Error in preprocessing audio: {e}")
149
+ raise
150
+
151
+
152
+ def _reshape_feature(feature, input_shape):
153
+ """
154
+ Reshape the feature to match the expected input shape of the model.
155
+
156
+ Args:
157
+ feature: The extracted feature.
158
+ input_shape: The expected input shape of the model.
159
+
160
+ Returns:
161
+ Reshaped feature.
162
+ """
163
+ expected_time_frames = input_shape[1]
164
+ if len(feature) > expected_time_frames:
165
+ feature = feature[:expected_time_frames]
166
+ elif len(feature) < expected_time_frames:
167
+ feature = np.pad(feature, (0, expected_time_frames - len(feature)))
168
+
169
+ return feature
170
+
171
+
172
+ def classify_audio(model_type, feature_type, file_path):
173
+ """
174
+ Classify an audio file using the specified model and feature type.
175
+
176
+ Args:
177
+ model_type: Type of model ('binary' or 'multi').
178
+ feature_type: Feature extraction type ('mfcc', 'log_mel', or 'augmented').
179
+ file_path: Path to the audio file.
180
+
181
+ Returns:
182
+ Predicted class and prediction probabilities.
183
+ """
184
+ try:
185
+ model_file = os.path.join(MODEL_PATH, MODELS[model_type][feature_type])
186
+ if not os.path.exists(model_file):
187
+ raise FileNotFoundError(f"Model file '{model_file}' not found.")
188
+ model = load_model(model_file)
189
+
190
+ # Get input shape from the model
191
+ input_shape = model.input_shape
192
+
193
+ # Preprocess audio
194
+ processed_audio = preprocess_audio(file_path, mode=feature_type, input_shape=input_shape)
195
+
196
+ # Add batch dimension
197
+ processed_audio = np.expand_dims(processed_audio, axis=0)
198
+
199
+ # Predict
200
+ predictions = model.predict(processed_audio)
201
+ predicted_class = np.argmax(predictions, axis=1)[0]
202
+ probabilities = predictions[0].tolist()
203
+
204
+ logger.info(f"Prediction complete. Predicted class: {predicted_class}, Probabilities: {probabilities}")
205
+ return predicted_class, probabilities
206
+
207
+ except Exception as e:
208
+ logger.error(f"Error in classification: {e}")
209
+ raise
210
+
211
+
212
+ def main():
213
+ logger.info("Starting audio classification test script.")
214
+
215
+ if not os.path.exists(FILE_PATH):
216
+ logger.error(f"Audio file not found: {FILE_PATH}")
217
+ return
218
+
219
+ for model_type in MODELS.keys():
220
+ for feature_type in MODELS[model_type].keys():
221
+ try:
222
+ logger.info(f"Testing {model_type} model with {feature_type} features.")
223
+ predicted_class, probabilities = classify_audio(model_type, feature_type, FILE_PATH)
224
+ class_name = CLASS_NAMES[model_type][predicted_class]
225
+ logger.info(f"Predicted Class: {class_name} ({predicted_class}), Probabilities: {probabilities}")
226
+ except Exception as e:
227
+ logger.error(f"Failed for {model_type} - {feature_type}: {e}")
228
+
229
+
230
+ if __name__ == "__main__":
231
+ main()
legacy/train,py ADDED
@@ -0,0 +1,767 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import gc
4
+ from joblib import Parallel, delayed
5
+ import mlflow
6
+ import mlflow.keras
7
+ import numpy as np
8
+ import pandas as pd
9
+ import librosa
10
+ import librosa.display
11
+ import optuna
12
+ from tqdm import tqdm
13
+ import matplotlib.pyplot as plt
14
+ from sklearn.metrics import roc_auc_score, roc_curve, confusion_matrix, classification_report
15
+ from sklearn.model_selection import train_test_split
16
+ from sklearn.preprocessing import LabelEncoder
17
+ from keras.models import Sequential
18
+ from keras.utils import to_categorical, normalize
19
+ from keras.layers import Conv2D, Dense, MaxPooling2D, Flatten, Dropout, BatchNormalization, GlobalAveragePooling2D
20
+
21
+ from imblearn.over_sampling import RandomOverSampler
22
+ from keras.preprocessing.image import ImageDataGenerator
23
+ from imblearn.over_sampling import SMOTE
24
+ from scipy.signal import butter, sosfilt
25
+
26
+
27
+ from keras.models import Sequential
28
+ from keras.layers import (
29
+ Conv1D, Conv2D, MaxPooling1D, MaxPooling2D,
30
+ GlobalAveragePooling1D, GlobalAveragePooling2D,
31
+ Dense, Dropout, BatchNormalization
32
+ )
33
+
34
+
35
+ from tensorflow.keras.models import Sequential, Model, load_model
36
+
37
+ from tensorflow.keras.layers import Conv1D, Conv2D, SeparableConv1D, MaxPooling1D, MaxPooling2D
38
+ from tensorflow.keras.layers import Input, add, Flatten, Dense, BatchNormalization, Dropout, LSTM, GRU
39
+ from tensorflow.keras.layers import GlobalMaxPooling1D, GlobalMaxPooling2D, Activation, LeakyReLU, ReLU
40
+
41
+ from tensorflow.keras import regularizers
42
+ from tensorflow.keras import backend as K
43
+ from tensorflow.keras.optimizers import Adamax
44
+ from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
45
+
46
+ from sklearn.model_selection import train_test_split
47
+ from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,matthews_corrcoef
48
+ from sklearn.metrics import cohen_kappa_score,roc_auc_score,confusion_matrix,classification_report
49
+
50
+
51
+ # Set up logging
52
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
53
+ data_logger = logging.getLogger("data_loading")
54
+ processing_logger = logging.getLogger("data_processing")
55
+ model_logger = logging.getLogger("model_training")
56
+
57
+ # Utility Functions
58
+ def load_data():
59
+ """Load patient diagnosis and demographic data."""
60
+ data_logger.info("Loading patient diagnosis and demographic data.")
61
+ diagnosis_df = pd.read_csv('/kaggle/input/respiratory-sound-database/Respiratory_Sound_Database/Respiratory_Sound_Database/patient_diagnosis.csv',
62
+ names=['Patient number', 'Diagnosis'])
63
+
64
+ patient_df = pd.read_csv('/kaggle/input/respiratory-sound-database/demographic_info.txt',
65
+ names=['Patient number', 'Age', 'Sex', 'Adult BMI (kg/m2)', 'Child Weight (kg)', 'Child Height (cm)'],
66
+ delimiter=' ')
67
+
68
+ data_logger.info("Data successfully loaded.")
69
+ return pd.merge(left=patient_df, right=diagnosis_df, how='left')
70
+
71
+
72
+ def process_audio_file(soundDir, audio_files_path, df_filtered):
73
+ """
74
+ Process a single audio file: extract MFCC features and augment with noise, stretching, and shifting.
75
+
76
+ Args:
77
+ soundDir: Filename of the audio file.
78
+ audio_files_path: Path to the directory containing audio files.
79
+ df_filtered: Filtered DataFrame containing patient diagnosis and metadata.
80
+
81
+ Returns:
82
+ Tuple containing features (X_local) and labels (y_local).
83
+ """
84
+ X_local = []
85
+ y_local = []
86
+ features = 52
87
+
88
+ # Extract patient ID and disease from filename and DataFrame
89
+ patient_id = int(soundDir.split('_')[0])
90
+ disease = df_filtered.loc[df_filtered['Patient number'] == patient_id, 'Diagnosis'].values[0]
91
+
92
+ # Load audio file
93
+ data_x, sampling_rate = librosa.load(os.path.join(audio_files_path, soundDir), sr=None)
94
+ data_x = preprocess_audio(data_x, sampling_rate) # Apply filtering
95
+
96
+
97
+ mfccs = np.mean(librosa.feature.mfcc(y=data_x, sr=sampling_rate, n_mfcc=features).T, axis=0)
98
+ X_local.append(mfccs)
99
+ y_local.append(disease)
100
+
101
+ # Data augmentation
102
+ for augmentation in [add_noise, shift, stretch, pitch_shift]:
103
+ if augmentation == add_noise:
104
+ augmented_data = augmentation(data_x, 0.001)
105
+ elif augmentation == shift:
106
+ augmented_data = augmentation(data_x, 1600)
107
+ elif augmentation == stretch:
108
+ augmented_data = augmentation(data_x, 1.2)
109
+ elif augmentation == pitch_shift:
110
+ augmented_data = augmentation(data_x, 3)
111
+
112
+ mfccs_augmented = np.mean(librosa.feature.mfcc(y=augmented_data, sr=sampling_rate, n_mfcc=features).T, axis=0)
113
+ X_local.append(mfccs_augmented)
114
+ y_local.append(disease)
115
+
116
+ return X_local, y_local
117
+
118
+
119
+
120
+ def mfccs_feature_exteraction(audio_files_path, df_filtered, n_jobs=-1):
121
+ """
122
+ Extract MFCC features from audio data and augment with noise, stretching, and shifting in parallel.
123
+
124
+ Args:
125
+ audio_files_path: Path to the directory containing audio files.
126
+ df_filtered: Filtered DataFrame containing patient diagnosis and metadata.
127
+ n_jobs: Number of parallel jobs (-1 to use all available cores).
128
+
129
+ Returns:
130
+ X_data: Array of features extracted from the audio files.
131
+ y_data: Array of target labels.
132
+ """
133
+ processing_logger.info(f"Processing audio files in: {audio_files_path}")
134
+ files = [file for file in os.listdir(audio_files_path) if file.endswith('.wav') and file[:3] not in ['103', '108', '115']]
135
+
136
+ files = files[:30] ## DEBUG
137
+
138
+ # Use Parallel and delayed to process files in parallel
139
+ results = Parallel(n_jobs=n_jobs, backend="loky")(delayed(process_audio_file)(file, audio_files_path, df_filtered) for file in tqdm(files, desc="Processing audio files"))
140
+
141
+ # Flatten results
142
+ X_ = []
143
+ y_ = []
144
+ for X_local, y_local in results:
145
+ X_.extend(X_local)
146
+ y_.extend(y_local)
147
+
148
+ X_data = np.array(X_)
149
+ y_data = np.array(y_)
150
+ processing_logger.info("MFCC feature extraction and augmentation complete.")
151
+ return X_data, y_data
152
+
153
+
154
+
155
+ def add_noise(data,x):
156
+ noise = np.random.randn(len(data))
157
+ data_noise = data + x * noise
158
+ return data_noise
159
+
160
+ def shift(data, x):
161
+ return np.roll(data, int(x))
162
+
163
+ def stretch(data, rate):
164
+ """Apply time-stretching to the audio signal."""
165
+ return librosa.effects.time_stretch(data, rate=rate)
166
+
167
+
168
+
169
+ def pitch_shift (data , rate):
170
+ data = librosa.effects.pitch_shift(data, sr=220250, n_steps=rate)
171
+ return data
172
+
173
+
174
+
175
+
176
+ def prepare_dataset_augmented(df_filtered, audio_files_path, classification_mode):
177
+ """Prepare the dataset using the GRU pipeline."""
178
+ processing_logger.info("Preparing dataset with GRU pipeline.")
179
+
180
+ # Extract features and labels
181
+ X, y = mfccs_feature_exteraction(audio_files_path, df_filtered)
182
+
183
+ # Apply label encoding
184
+ le = LabelEncoder()
185
+ y_encoded = le.fit_transform(np.array(y)) # Encode labels to integers
186
+
187
+ if classification_mode == "binary":
188
+ # Use single column with 0 and 1 for binary classification
189
+ processing_logger.info("Binary classification mode: Using single column labels (0/1).")
190
+ y_processed = y_encoded # No one-hot encoding
191
+ else:
192
+ # One-hot encode labels for multi-class classification
193
+ processing_logger.info("Multi-class classification mode: Applying one-hot encoding.")
194
+ y_processed = to_categorical(y_encoded)
195
+
196
+ # Log the mapping of one-hot encoding to class labels
197
+ print("One-hot encoding mapping:")
198
+ for idx, label in enumerate(le.classes_):
199
+ print(f"{idx} -> {label}")
200
+
201
+ processing_logger.info("Dataset preparation with GRU pipeline complete.")
202
+ return X, y_processed, le
203
+
204
+
205
+
206
+ def process_audio_metadata(folder_path):
207
+ """Extract audio metadata from filenames."""
208
+ processing_logger.info("Extracting audio metadata from filenames.")
209
+ data = []
210
+ for filename in os.listdir(folder_path):
211
+ if filename.endswith('.txt'):
212
+ parts = filename.split('_')
213
+ data.append({
214
+ 'Patient number': int(parts[0]),
215
+ 'Recording index': parts[1],
216
+ 'Chest location': parts[2],
217
+ 'Acquisition mode': parts[3],
218
+ 'Recording equipment': parts[4].split('.')[0]
219
+ })
220
+ processing_logger.info("Audio metadata extraction complete.")
221
+ return pd.DataFrame(data)
222
+
223
+ def merge_datasets(df1, df2):
224
+ """Merge metadata and diagnosis data."""
225
+ processing_logger.info("Merging metadata and diagnosis data.")
226
+ merged_df = pd.merge(left=df1, right=df2, how='left').sort_values('Patient number').reset_index(drop=True)
227
+ merged_df['audio_file_name'] = merged_df.apply(lambda row: f"{row['Patient number']}_{row['Recording index']}_{row['Chest location']}_{row['Acquisition mode']}_{row['Recording equipment']}.wav", axis=1)
228
+ processing_logger.info("Merging complete.")
229
+ return merged_df
230
+
231
+ def filter_and_sample_data(df, mode='binary'):
232
+ """
233
+ Filter and sample the dataset for binary or multi-class classification.
234
+
235
+ Args:
236
+ df: Input DataFrame containing diagnosis data.
237
+ mode: Specify 'binary' for Normal/Abnormal or 'multi-class' for grouped classes.
238
+
239
+ Returns:
240
+ Filtered and processed DataFrame.
241
+ """
242
+ processing_logger.info(f"Filtering and sampling the dataset for {mode} classification.")
243
+
244
+ if mode == 'binary':
245
+ # Binary classification: Normal vs. Abnormal
246
+ df['Diagnosis'] = df['Diagnosis'].apply(lambda x: 'Normal' if x == 'Healthy' else 'Abnormal')
247
+ elif mode == 'multi':
248
+ # Multi-class classification: Group classes
249
+ processing_logger.info("Grouping classes for multi-class classification.")
250
+ df['Diagnosis'] = df['Diagnosis'].replace({
251
+ 'Healthy': 'Normal',
252
+ 'COPD': 'Chronic Respiratory Diseases',
253
+ 'Asthma': 'Chronic Respiratory Diseases',
254
+ 'URTI': 'Respiratory Infections',
255
+ 'Bronchiolitis': 'Respiratory Infections',
256
+ 'LRTI': 'Respiratory Infections',
257
+ 'Pneumonia': 'Respiratory Infections',
258
+ 'Bronchiectasis': 'Respiratory Infections'
259
+ })
260
+
261
+ # Filter out rare classes with fewer than 5 samples
262
+ class_counts = df['Diagnosis'].value_counts()
263
+ valid_classes = class_counts[class_counts >= 5].index
264
+ df = df[df['Diagnosis'].isin(valid_classes)].reset_index(drop=True)
265
+
266
+ processing_logger.info(f"Filtered classes: {df['Diagnosis'].unique()}")
267
+ processing_logger.info(f"Filtering and sampling complete with mode={mode}.")
268
+ return df
269
+
270
+
271
+ def oversample_data(X, y):
272
+ """Apply SMOTE to balance classes."""
273
+ processing_logger.info("Applying SMOTE to balance classes.")
274
+
275
+ # Save the original shape of features
276
+ original_shape = X.shape[1:]
277
+
278
+ # Flatten for SMOTE processing
279
+ X = X.reshape((X.shape[0], -1))
280
+
281
+ # Convert one-hot encoded labels to integers
282
+ y = np.argmax(y, axis=1)
283
+
284
+ # Apply SMOTE
285
+ smote = SMOTE(random_state=42)
286
+ X_resampled, y_resampled = smote.fit_resample(X, y)
287
+
288
+ # Reshape back to the original dimensions
289
+ X_resampled = X_resampled.reshape((-1, *original_shape))
290
+
291
+ # Convert labels back to one-hot encoding
292
+ y_resampled = to_categorical(y_resampled)
293
+
294
+ processing_logger.info("SMOTE oversampling complete.")
295
+ return X_resampled, y_resampled
296
+
297
+
298
+
299
+ def augment_data(X, y):
300
+ """Apply data augmentation to increase dataset size."""
301
+ processing_logger.info("Applying data augmentation.")
302
+ datagen = ImageDataGenerator(
303
+ rotation_range=10,
304
+ width_shift_range=0.1,
305
+ height_shift_range=0.1,
306
+ horizontal_flip=True
307
+ )
308
+ datagen.fit(X)
309
+ processing_logger.info("Data augmentation setup complete.")
310
+ return datagen
311
+
312
+
313
+
314
+ def prepare_dataset_parallel(df, audio_files_path, mode, classification_mode):
315
+ """Prepare the dataset by extracting features from audio files in parallel."""
316
+ processing_logger.info(f"Preparing dataset using {mode} features in parallel.")
317
+ results = Parallel(n_jobs=-1)(delayed(preprocess_file)(row, audio_files_path, mode) for _, row in tqdm(df.iterrows(), total=len(df)))
318
+
319
+ X, y = zip(*results)
320
+ X = np.array(X)
321
+ X = np.expand_dims(X, axis=-1) # Add channel dimension
322
+ X = normalize(X, axis=1)
323
+
324
+ le = LabelEncoder()
325
+ y_encoded = le.fit_transform(np.array(y)) # Encode labels
326
+
327
+ if classification_mode == "binary":
328
+ # Use single column with 0 and 1 for binary classification
329
+ processing_logger.info("Binary classification mode: Using single column labels (0/1).")
330
+ y = y_encoded # No one-hot encoding
331
+ else:
332
+ # One-hot encode labels for multi-class classification
333
+ processing_logger.info("Multi-class classification mode: Applying one-hot encoding.")
334
+ y = to_categorical(y_encoded)
335
+
336
+ processing_logger.info(f"Dataset preparation using {mode} complete.")
337
+ return X, y, le
338
+
339
+ def preprocess_file(row, audio_files_path, mode):
340
+ """Preprocess a single audio file."""
341
+ file_path = os.path.join(audio_files_path, row['audio_file_name'])
342
+ feature = preprocessing(file_path, mode)
343
+ label = row['Diagnosis']
344
+ return feature, label
345
+
346
+ def preprocessing(audio_file, mode):
347
+ """Preprocess audio file by resampling, padding/truncating, and extracting features."""
348
+ sr_new = 16000 # Resample audio to 16 kHz
349
+ x, sr = librosa.load(audio_file, sr=sr_new)
350
+ x = preprocess_audio(x, sr)
351
+ # Padding or truncating to 5 seconds (5 * sr_new samples)
352
+ max_len = 5 * sr_new
353
+ if x.shape[0] < max_len:
354
+ x = np.pad(x, (0, max_len - x.shape[0]))
355
+ else:
356
+ x = x[:max_len]
357
+
358
+ # Extract features
359
+ if mode == 'mfcc':
360
+ feature = librosa.feature.mfcc(y=x, sr=sr_new, n_mfcc=20) # Ensure consistent shape
361
+ elif mode == 'log_mel':
362
+ feature = librosa.feature.melspectrogram(y=x, sr=sr_new, n_mels=20, fmax=8000) # Match n_mels to 20
363
+ feature = librosa.power_to_db(feature, ref=np.max)
364
+
365
+ return feature
366
+
367
+ def prepare_dataset(df, audio_files_path, mode):
368
+ """Prepare the dataset by extracting features from audio files."""
369
+ processing_logger.info(f"Preparing dataset using {mode} features.")
370
+ X, y = [], []
371
+ for _, row in tqdm(df.iterrows(), total=len(df)):
372
+ file_path = os.path.join(audio_files_path, row['audio_file_name'])
373
+ feature = preprocessing(file_path, mode)
374
+ X.append(feature)
375
+ y.append(row['Diagnosis'])
376
+ del feature # Free memory after processing each file
377
+ gc.collect()
378
+
379
+ X = np.array(X)
380
+ X = np.expand_dims(X, axis=-1) # Add channel dimension
381
+ X = normalize(X, axis=1)
382
+ le = LabelEncoder()
383
+ y = to_categorical(le.fit_transform(np.array(y)))
384
+ processing_logger.info(f"Dataset preparation using {mode} complete.")
385
+ return X, y, le
386
+
387
+
388
+ def build_model(input_shape, n_filters, dense_units, dropout_rate, num_classes, model_type='1D', classification_mode='binary'):
389
+ """
390
+ Build and compile a CNN model for 1D or 2D data.
391
+
392
+ Args:
393
+ input_shape: Tuple specifying the input shape.
394
+ n_filters: Number of filters in the first convolutional layer.
395
+ dense_units: Number of units in the dense layer.
396
+ dropout_rate: Dropout rate for regularization.
397
+ num_classes: Number of output classes.
398
+ model_type: '1D' for 1D CNN or '2D' for 2D CNN.
399
+ classification_mode: 'binary' for binary classification, 'multi' for multi-class classification.
400
+
401
+ Returns:
402
+ Compiled CNN model.
403
+ """
404
+ print(f"Building the updated {model_type} CNN model with {classification_mode} classification.")
405
+ model = Sequential()
406
+
407
+ # Add convolutional layers based on the model type
408
+ if model_type == '1D':
409
+ # 1D CNN layers
410
+ model.add(Conv1D(n_filters, kernel_size=3, activation='relu', input_shape=input_shape))
411
+ model.add(BatchNormalization())
412
+ model.add(MaxPooling1D(pool_size=2))
413
+ model.add(Dropout(dropout_rate))
414
+
415
+ model.add(Conv1D(n_filters * 2, kernel_size=3, activation='relu'))
416
+ model.add(BatchNormalization())
417
+ model.add(MaxPooling1D(pool_size=2))
418
+ model.add(Dropout(dropout_rate))
419
+
420
+ model.add(Conv1D(n_filters * 4, kernel_size=3, activation='relu'))
421
+ model.add(BatchNormalization())
422
+ model.add(GlobalAveragePooling1D())
423
+ model.add(Dropout(dropout_rate))
424
+
425
+ elif model_type == '2D':
426
+ # 2D CNN layers
427
+ model.add(Conv2D(n_filters, (3, 3), activation='relu', input_shape=input_shape))
428
+ model.add(BatchNormalization())
429
+ if input_shape[0] >= 2:
430
+ model.add(MaxPooling2D((2, 2)))
431
+ model.add(Dropout(dropout_rate))
432
+
433
+ model.add(Conv2D(n_filters * 2, (3, 3), activation='relu'))
434
+ model.add(BatchNormalization())
435
+ if input_shape[0] >= 4:
436
+ model.add(MaxPooling2D((2, 2)))
437
+ model.add(Dropout(dropout_rate))
438
+
439
+ model.add(Conv2D(n_filters * 4, (3, 3), activation='relu'))
440
+ model.add(BatchNormalization())
441
+ model.add(GlobalAveragePooling2D())
442
+ model.add(Dropout(dropout_rate))
443
+
444
+ else:
445
+ raise ValueError("Invalid model_type. Must be '1D' or '2D'.")
446
+
447
+ # Add fully connected layers
448
+ model.add(Dense(dense_units, activation='relu'))
449
+ model.add(BatchNormalization())
450
+ model.add(Dropout(dropout_rate))
451
+
452
+ # Add output layer dynamically based on classification mode
453
+ if classification_mode == 'binary':
454
+ # Binary classification: Single unit with sigmoid activation
455
+ model.add(Dense(1, activation='sigmoid'))
456
+ loss_function = 'binary_crossentropy'
457
+ else:
458
+ # Multi-class classification: num_classes units with softmax activation
459
+ model.add(Dense(num_classes, activation='softmax'))
460
+ loss_function = 'categorical_crossentropy'
461
+
462
+ # Compile the model
463
+ model.compile(optimizer='adam', loss=loss_function, metrics=['accuracy'])
464
+ print(f"{model_type} CNN model built and compiled successfully for {classification_mode} classification.")
465
+ return model
466
+
467
+
468
+
469
+ def log_metrics(y_true, y_pred, mode):
470
+ """Log evaluation metrics."""
471
+ precision = classification_report(y_true, y_pred, output_dict=True)['weighted avg']['precision']
472
+ recall = classification_report(y_true, y_pred, output_dict=True)['weighted avg']['recall']
473
+ f1_score = classification_report(y_true, y_pred, output_dict=True)['weighted avg']['f1-score']
474
+
475
+ mlflow.log_metric(f"{mode}_precision", precision)
476
+ mlflow.log_metric(f"{mode}_recall", recall)
477
+ mlflow.log_metric(f"{mode}_f1_score", f1_score)
478
+
479
+ def evaluate_model(model, X_test, y_test, le, mode):
480
+ """Evaluate the model and display results."""
481
+ model_logger.info(f"Evaluating the model using {mode} features.")
482
+ predictions = model.predict(X_test)
483
+ predicted_classes = np.argmax(predictions, axis=1)
484
+ y_true = np.argmax(y_test, axis=1)
485
+
486
+ # Confusion Matrix
487
+ conf_matrix = confusion_matrix(y_true, predicted_classes)
488
+ plt.figure(figsize=(8, 6))
489
+ plt.imshow(conf_matrix, interpolation='nearest', cmap=plt.cm.Blues)
490
+ plt.title(f"Confusion Matrix ({mode})")
491
+ plt.colorbar()
492
+ plt.tight_layout()
493
+ plt.ylabel('True label')
494
+ plt.xlabel('Predicted label')
495
+ cm_path = f"confusion_matrix_{mode}.png"
496
+ plt.savefig(cm_path)
497
+ mlflow.log_artifact(cm_path)
498
+
499
+ # ROC Curve
500
+ fpr, tpr, _ = roc_curve(y_true, predictions[:, 1])
501
+ auc_score = roc_auc_score(y_true, predictions[:, 1])
502
+ plt.figure(figsize=(8, 6))
503
+ plt.plot(fpr, tpr, color='darkorange', lw=2, label=f"ROC curve (area = {auc_score:.2f})")
504
+ plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
505
+ plt.xlabel('False Positive Rate')
506
+ plt.ylabel('True Positive Rate')
507
+ plt.title(f"Receiver Operating Characteristic ({mode})")
508
+ plt.legend(loc="lower right")
509
+ roc_path = f"roc_curve_{mode}.png"
510
+ plt.savefig(roc_path)
511
+ mlflow.log_artifact(roc_path)
512
+
513
+ # Log metrics
514
+ mlflow.log_metric(f"{mode}_auc", auc_score)
515
+ log_metrics(y_true, predicted_classes, mode)
516
+
517
+ model_logger.info(f"Model evaluation using {mode} features complete.")
518
+
519
+
520
+ def track_experiment_with_mlflow_and_optuna(mode, num_classes, model_type='1D', classification_mode='binary'):
521
+ """
522
+ Optimize hyperparameters using Optuna and track experiments with MLflow.
523
+
524
+ Args:
525
+ mode: Feature extraction mode (e.g., 'gru', 'mfcc', 'log_mel').
526
+ num_classes: Number of classes for classification.
527
+ model_type: Type of model ('1D' for Conv1D, '2D' for Conv2D).
528
+ classification_mode: 'binary' for binary classification, 'multi' for multi-class classification.
529
+ """
530
+ def objective(trial):
531
+ with mlflow.start_run(nested=True): # Start a new MLflow run for each trial
532
+ # Hyperparameters to tune
533
+ n_filters = trial.suggest_categorical('n_filters', [16, 32, 64])
534
+ dense_units = trial.suggest_int('dense_units', 64, 256, step=32)
535
+ dropout_rate = trial.suggest_float('dropout_rate', 0.1, 0.5, step=0.1)
536
+ learning_rate = trial.suggest_loguniform('learning_rate', 1e-4, 1e-2)
537
+
538
+ # Build and compile the model
539
+ model = build_model(
540
+ input_shape=X_train.shape[1:],
541
+ n_filters=n_filters,
542
+ dense_units=dense_units,
543
+ dropout_rate=dropout_rate,
544
+ num_classes=num_classes,
545
+ model_type=model_type,
546
+ classification_mode=classification_mode
547
+ )
548
+
549
+ # Define EarlyStopping callback
550
+ early_stopping = EarlyStopping(
551
+ monitor='val_loss', # Monitor validation loss
552
+ patience=5, # Stop training after 5 epochs with no improvement
553
+ restore_best_weights=True
554
+ )
555
+
556
+ # Train the model
557
+ history = model.fit(
558
+ X_train, y_train,
559
+ validation_data=(X_val, y_val),
560
+ epochs=50, # Allow a larger max epoch since EarlyStopping will handle early termination
561
+ batch_size=32,
562
+ callbacks=[early_stopping],
563
+ verbose=0
564
+ )
565
+
566
+ # Log hyperparameters and metrics to MLflow
567
+ mlflow.log_params({
568
+ 'n_filters': n_filters,
569
+ 'dense_units': dense_units,
570
+ 'dropout_rate': dropout_rate,
571
+ 'learning_rate': learning_rate,
572
+ 'model_type': model_type,
573
+ 'classification_mode': classification_mode
574
+ })
575
+ mlflow.log_metric("best_val_accuracy", max(history.history['val_accuracy']))
576
+
577
+ # Save training and validation loss curves
578
+ plt.figure()
579
+ plt.plot(history.history['loss'], label='Train Loss')
580
+ plt.plot(history.history['val_loss'], label='Validation Loss')
581
+ plt.legend()
582
+ plt.title("Training and Validation Loss")
583
+ loss_curve_path = f"loss_curve_{trial.number}_{model_type}.png"
584
+ plt.savefig(loss_curve_path)
585
+ mlflow.log_artifact(loss_curve_path)
586
+
587
+ return max(history.history['val_accuracy'])
588
+
589
+ # Start Optuna study
590
+ study = optuna.create_study(direction='maximize')
591
+ study.optimize(objective, n_trials=20)
592
+
593
+ # Retrieve best trial and log results
594
+ best_trial = study.best_trial
595
+ model_logger.info(f"Best Trial for {mode} ({model_type}): {best_trial.params}")
596
+
597
+ # Build the best model (already compiled in build_model)
598
+ best_model = build_model(
599
+ input_shape=X_train.shape[1:],
600
+ n_filters=best_trial.params['n_filters'],
601
+ dense_units=best_trial.params['dense_units'],
602
+ dropout_rate=best_trial.params['dropout_rate'],
603
+ num_classes=num_classes,
604
+ model_type=model_type,
605
+ classification_mode=classification_mode
606
+ )
607
+
608
+ # Train the best model with EarlyStopping
609
+ early_stopping = EarlyStopping(
610
+ monitor='val_loss',
611
+ patience=5,
612
+ restore_best_weights=True
613
+ )
614
+
615
+ best_model.fit(
616
+ X_train, y_train,
617
+ validation_data=(X_val, y_val),
618
+ epochs=50, batch_size=32,
619
+ callbacks=[early_stopping],
620
+ verbose=1
621
+ )
622
+
623
+ # Save the best model
624
+ best_model_path = f"best_model_{mode}_{model_type}.h5"
625
+ best_model.save(best_model_path)
626
+ mlflow.log_artifact(best_model_path)
627
+ model_logger.info(f"Best model for {mode} ({model_type}) saved successfully.")
628
+
629
+ return best_model
630
+
631
+ def log_class_distribution(y, message):
632
+ """Log the class distribution."""
633
+ if y.ndim == 1: # Binary classification (1D array of 0s and 1s)
634
+ unique, counts = np.unique(y, return_counts=True)
635
+ else: # Multi-class classification (2D one-hot encoded array)
636
+ unique, counts = np.unique(np.argmax(y, axis=1), return_counts=True)
637
+
638
+ class_distribution = dict(zip(unique, counts))
639
+ processing_logger.info(f"{message} Class Distribution: {class_distribution}")
640
+
641
+
642
+ def preprocess_audio(audio, sr):
643
+ """
644
+ Apply a bandpass filter to audio data.
645
+
646
+ Args:
647
+ audio: The input audio signal.
648
+ sr: The sampling rate of the audio.
649
+
650
+ Returns:
651
+ Filtered audio signal.
652
+ """
653
+ # Define cutoff frequencies
654
+ low_cutoff = 50 # 50 Hz
655
+ high_cutoff = min(5000, sr / 2 - 1) # Ensure it is below Nyquist frequency
656
+
657
+ if low_cutoff >= high_cutoff:
658
+ raise ValueError(
659
+ f"Invalid filter range: low_cutoff={low_cutoff}, high_cutoff={high_cutoff} for sampling rate {sr}"
660
+ )
661
+
662
+ # Design a bandpass filter
663
+ sos = butter(N=10, Wn=[low_cutoff, high_cutoff], btype='band', fs=sr, output='sos')
664
+
665
+ # Apply the filter
666
+ filtered_audio = sosfilt(sos, audio)
667
+ return filtered_audio
668
+
669
+
670
+ def main():
671
+ mlflow.end_run()
672
+
673
+ data_logger.info("Starting data pipeline.")
674
+ df = load_data()
675
+ audio_metadata = process_audio_metadata('/kaggle/input/respiratory-sound-database/Respiratory_Sound_Database/Respiratory_Sound_Database/audio_and_txt_files')
676
+ df_all = merge_datasets(audio_metadata, df)
677
+
678
+ # Define classification modes and feature types
679
+ classification_modes = [ 'multi', 'binary'] # Options: 'binary', 'multi'
680
+ feature_types = ['mfcc', 'log_mel', 'augmented'] # Options
681
+ models = []
682
+
683
+ for classification_mode in classification_modes:
684
+ # Preprocess dataset for binary or multi-class classification
685
+ df_filtered = filter_and_sample_data(df_all, mode=classification_mode)
686
+ processing_logger.info(f"Dataset shape for {classification_mode} mode: {df_filtered.shape}")
687
+
688
+ for feature_type in feature_types:
689
+ processing_logger.info(f"Running experiment for {classification_mode} classification with {feature_type} features.")
690
+ global X_train, X_val, X_test, y_train, y_val, y_test
691
+
692
+ # Prepare the dataset
693
+ if feature_type == 'augmented':
694
+ X, y, le = prepare_dataset_augmented(
695
+ df_filtered,
696
+ '/kaggle/input/respiratory-sound-database/Respiratory_Sound_Database/Respiratory_Sound_Database/audio_and_txt_files',
697
+ classification_mode=classification_mode
698
+ )
699
+ else:
700
+ X, y, le = prepare_dataset_parallel(
701
+ df_filtered,
702
+ '/kaggle/input/respiratory-sound-database/Respiratory_Sound_Database/Respiratory_Sound_Database/audio_and_txt_files',
703
+ mode=feature_type,
704
+ classification_mode=classification_mode
705
+ )
706
+
707
+ # Split data into train/val/test
708
+ X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)
709
+ X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, stratify=y_temp, random_state=42)
710
+
711
+ # Save test data for future evaluation
712
+ np.save(f"X_test_{classification_mode}_{feature_type}.npy", X_test)
713
+ np.save(f"y_test_{classification_mode}_{feature_type}.npy", y_test)
714
+ mlflow.log_artifact(f"X_test_{classification_mode}_{feature_type}.npy")
715
+ mlflow.log_artifact(f"y_test_{classification_mode}_{feature_type}.npy")
716
+
717
+ # Log dataset characteristics
718
+ log_class_distribution(y_train, "Before Oversampling")
719
+ processing_logger.info(f"Train size: {X_train.shape}, Validation size: {X_val.shape}, Test size: {X_test.shape}")
720
+
721
+ try:
722
+ X_train, y_train = oversample_data(X_train, y_train)
723
+ except ValueError as e:
724
+ processing_logger.warning(f"SMOTE skipped: {e}")
725
+ log_class_distribution(y_train, "After Oversampling")
726
+
727
+ # Determine number of classes
728
+ if classification_mode == "binary":
729
+ num_classes = 1 # Single output for binary classification
730
+ else:
731
+ num_classes = y_train.shape[1] # Number of classes for multi-class
732
+
733
+ # Train and save model
734
+ with mlflow.start_run(run_name=f"Experiment_{classification_mode}_{feature_type}", nested=True):
735
+ if feature_type == 'augmented':
736
+ # Expand dimensions for 1D CNN input
737
+ X_train = np.expand_dims(X_train, axis=-1)
738
+ X_val = np.expand_dims(X_val, axis=-1)
739
+ X_test = np.expand_dims(X_test, axis=-1)
740
+
741
+ # Optimize and train 1D CNN
742
+ model = track_experiment_with_mlflow_and_optuna(
743
+ mode=feature_type,
744
+ num_classes=num_classes,
745
+ model_type='1D', # Specify 1D CNN for GRU features
746
+ classification_mode=classification_mode
747
+ )
748
+ else:
749
+ # Optimize and train CNN models for MFCC and MEL
750
+ model = track_experiment_with_mlflow_and_optuna(
751
+ mode=feature_type,
752
+ num_classes=num_classes,
753
+ model_type='2D', # Specify 2D CNN for MFCC and Log-Mel
754
+ classification_mode=classification_mode
755
+ )
756
+
757
+ # Save final model
758
+ final_model_path = f"final_model_{classification_mode}_{feature_type}.h5"
759
+ model.save(final_model_path)
760
+ mlflow.log_artifact(final_model_path)
761
+ models.append(model)
762
+
763
+ processing_logger.info("All experiments completed successfully!")
764
+
765
+
766
+ if __name__ == "__main__":
767
+ main()
main_ui.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from streamlit_ui import readme, data_exploration, model_performance, model_deployment
3
+
4
+ # Load custom CSS
5
+ with open("streamlit_ui/style.css") as css_file:
6
+ st.markdown(f'<style>{css_file.read()}</style>', unsafe_allow_html=True)
7
+
8
+ # Initialize session state for the selected page
9
+ if "active_page" not in st.session_state:
10
+ st.session_state["active_page"] = "Introduction"
11
+
12
+ # Streamlit app setup
13
+ st.title("ICBHI 2017 Challenge - Amplifier Health")
14
+
15
+ # Sidebar Navigation
16
+ st.sidebar.markdown('<div class="sidebar-header">Navigate</div>', unsafe_allow_html=True)
17
+
18
+ if st.sidebar.button("Introduction"):
19
+ st.session_state["active_page"] = "Introduction"
20
+ if st.sidebar.button("Data Exploration"):
21
+ st.session_state["active_page"] = "Data Exploration"
22
+ if st.sidebar.button("Model Performance"):
23
+ st.session_state["active_page"] = "Model Performance"
24
+ if st.sidebar.button("Model Deployment"):
25
+ st.session_state["active_page"] = "Model Deployment"
26
+
27
+ # Page Content
28
+ if st.session_state["active_page"] == "Introduction":
29
+ readme.run()
30
+ elif st.session_state["active_page"] == "Data Exploration":
31
+ data_exploration.run()
32
+ elif st.session_state["active_page"] == "Model Performance":
33
+ model_performance.run()
34
+ elif st.session_state["active_page"] == "Model Deployment":
35
+ model_deployment.run()
models/archive/latest/final_model_binary_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9a789076aef5fa11dcb3566e4188d879eb388540427fb31f39242e835cc4fa4
3
+ size 240432
models/archive/latest/final_model_binary_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c807add33ef3fc00b536824c457433d45aa994069fe7ee4fb77d50517c3eaf46
3
+ size 426808
models/archive/latest/final_model_binary_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddd9db13624aa182372b709efa978778889aeabd5c7cb83ea3f9f8ec1f3315f0
3
+ size 4740776
models/archive/latest/final_model_multi_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:315d19b1369708f049f9b8e4fedc0d43280724cbfa95409407a3f70a5e6d0026
3
+ size 2294024
models/archive/latest/final_model_multi_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:15f7aed826b37328bf3a836e919c80ad9939a7a06275d74e8421ba0a380b9fd5
3
+ size 5147616
models/archive/latest/final_model_multi_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f40f08d3d45765b078d3fb09f5e54a58dae204f8eb3c5c60531fb58e313e1921
3
+ size 5045056
models/archive/old/final_model_binary_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9a789076aef5fa11dcb3566e4188d879eb388540427fb31f39242e835cc4fa4
3
+ size 240432
models/archive/old/final_model_binary_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c807add33ef3fc00b536824c457433d45aa994069fe7ee4fb77d50517c3eaf46
3
+ size 426808
models/archive/old/final_model_binary_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddd9db13624aa182372b709efa978778889aeabd5c7cb83ea3f9f8ec1f3315f0
3
+ size 4740776
models/archive/old/final_model_multi_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:287460263fc4ec540cd6bc3c36a9728a819edde0d9c0bde263646a9fa12509a1
3
+ size 2091032
models/archive/old/final_model_multi_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ea0758d4756fb293e88b357d36524313a1d1164f7f665f727b2108936c0cebe3
3
+ size 1414128
models/archive/old/final_model_multi_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:910c98b3809ad71a8c9255a68e23510c7d80ed8548ef506b91d791df0f24e93f
3
+ size 535952
models/archive/workingmodels/final_model_binary_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9a789076aef5fa11dcb3566e4188d879eb388540427fb31f39242e835cc4fa4
3
+ size 240432
models/archive/workingmodels/final_model_binary_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c807add33ef3fc00b536824c457433d45aa994069fe7ee4fb77d50517c3eaf46
3
+ size 426808
models/archive/workingmodels/final_model_binary_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddd9db13624aa182372b709efa978778889aeabd5c7cb83ea3f9f8ec1f3315f0
3
+ size 4740776
models/archive/workingmodels/final_model_multi_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:08e7b19fbae53e54b63c15a986890e026a6066a34be3d33c1505a55009659469
3
+ size 2393856
models/archive/workingmodels/final_model_multi_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0cda770c39faa5990ce0a70ca8991cb2ab8773c8fb419237d59cd425d2683696
3
+ size 4844280
models/archive/workingmodels/final_model_multi_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d0e0b37a3d4a508504e8a8faa3aa250bba1aeb1fad476d01d0d065d99192c404
3
+ size 5147616
models/final_model_binary_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9a789076aef5fa11dcb3566e4188d879eb388540427fb31f39242e835cc4fa4
3
+ size 240432
models/final_model_binary_log_mel.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c807add33ef3fc00b536824c457433d45aa994069fe7ee4fb77d50517c3eaf46
3
+ size 426808
models/final_model_binary_mfcc.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddd9db13624aa182372b709efa978778889aeabd5c7cb83ea3f9f8ec1f3315f0
3
+ size 4740776
models/final_model_multi_augmented.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:55c4ccce9e3964a11558f1cd4c96865f0c0c1d7a01c574401273a20c43532efe
3
+ size 2194456