yufii commited on
Commit
6dee894
·
verified ·
1 Parent(s): dba1e8a

Upload 10 files

Browse files
Files changed (5) hide show
  1. .gitattributes +2 -0
  2. app.py +19 -11
  3. best_model.keras +3 -0
  4. best_model_2.keras +3 -0
  5. utils_api.py +129 -27
.gitattributes CHANGED
@@ -34,3 +34,5 @@ saved_model/**/* 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
  cnn_1_v6_final_model.h5 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
  cnn_1_v6_final_model.h5 filter=lfs diff=lfs merge=lfs -text
37
+ best_model_2.keras filter=lfs diff=lfs merge=lfs -text
38
+ best_model.keras filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -9,10 +9,11 @@ import librosa
9
  import numpy as np
10
  import re
11
  import Levenshtein
 
12
 
13
  from fastapi.responses import JSONResponse
14
  from fastapi.middleware.cors import CORSMiddleware
15
- from utils import get_features
16
 
17
 
18
  #вывод в консоль для просмотри на hugging face
@@ -43,10 +44,12 @@ os.makedirs(cache_dir, exist_ok=True)
43
  whisper_model = whisper.load_model("tiny", download_root=cache_dir)
44
 
45
  # загрузка параметров модели
46
- filepath = os.path.abspath("best_model.h5")
47
  if not os.path.exists(filepath):
48
- raise FileNotFoundError(f"Model file not found at {filepath}")
49
-
 
 
50
  # Контекстный менеджер для временных аудио файлов
51
  @contextmanager
52
  def temporary_audio_file(audio_bytes):
@@ -68,8 +71,6 @@ def temporary_audio_file(audio_bytes):
68
  async def read_root():
69
  return {"message": "Welcome to the Defects_model API"}
70
 
71
- model = keras.models.load_model(filepath, compile=False)
72
-
73
  # Endpoint для сохранения аудио файлов
74
  @app.post("/save-audio")
75
  async def save_audio(file: UploadFile = File(...)):
@@ -142,21 +143,28 @@ async def process_audio(
142
  raise ValueError("Empty or invalid audio data.")
143
 
144
  # Извлечение признаков из аудио
145
- features = get_features(tmp_filename) # here data already in form
146
  # features = np.expand_dims(features, axis=0) # Add batch dimension
147
  logging.info(f"Features extracted: shape = {features.shape}")
148
 
149
  # Получение предсказания от модели
150
- class_weights = {0: 0.5460790960451978, 1: 1.0068333333333332, 2: 4}
151
 
152
  prediction = model.predict(features)
153
  logging.info(f"Prediction shape: {prediction.shape}")
154
 
155
- # Iterate over columns (classes)
156
  for j in range(prediction.shape[1]):
157
- prediction[0, j] *= class_weights.get(j, 1.0) # Access elements using [0, j]
 
158
 
159
  logging.info(f"Prediction: {prediction}")
 
 
 
 
 
 
160
 
161
  # Транскрибация аудио с помощью Whisper
162
  transcription_result = whisper_model.transcribe(tmp_filename, language="russian")
@@ -178,7 +186,7 @@ async def process_audio(
178
 
179
  # Возврат результатов
180
  return {
181
- "prediction": prediction.tolist(),
182
  "match_phrase": match_phrase
183
  }
184
 
 
9
  import numpy as np
10
  import re
11
  import Levenshtein
12
+ import tensorflow as tf
13
 
14
  from fastapi.responses import JSONResponse
15
  from fastapi.middleware.cors import CORSMiddleware
16
+ from utils_api import get_features
17
 
18
 
19
  #вывод в консоль для просмотри на hugging face
 
44
  whisper_model = whisper.load_model("tiny", download_root=cache_dir)
45
 
46
  # загрузка параметров модели
47
+ filepath = "best_model.keras"
48
  if not os.path.exists(filepath):
49
+ raise FileNotFoundError(f"Model file not found at {filepath}")\
50
+
51
+ model = tf.keras.models.load_model(filepath, compile=False)
52
+ logging.info(model.summary())
53
  # Контекстный менеджер для временных аудио файлов
54
  @contextmanager
55
  def temporary_audio_file(audio_bytes):
 
71
  async def read_root():
72
  return {"message": "Welcome to the Defects_model API"}
73
 
 
 
74
  # Endpoint для сохранения аудио файлов
75
  @app.post("/save-audio")
76
  async def save_audio(file: UploadFile = File(...)):
 
143
  raise ValueError("Empty or invalid audio data.")
144
 
145
  # Извлечение признаков из аудио
146
+ features = get_features(tmp_filename)
147
  # features = np.expand_dims(features, axis=0) # Add batch dimension
148
  logging.info(f"Features extracted: shape = {features.shape}")
149
 
150
  # Получение предсказания от модели
151
+ class_weights = {0: 0.5460790960451978, 1: 1.0068333333333332, 2: 1000.696369636963697}
152
 
153
  prediction = model.predict(features)
154
  logging.info(f"Prediction shape: {prediction.shape}")
155
 
156
+ #умножаем предикт на веса классов
157
  for j in range(prediction.shape[1]):
158
+ prediction[0, j] *= class_weights.get(j, 1.0)
159
+ prediction[0, j] *= 10
160
 
161
  logging.info(f"Prediction: {prediction}")
162
+ response_answer = np.argmax(prediction)
163
+ if (response_answer == 0):
164
+ response_answer = 1
165
+ else:
166
+ response_answer = 0
167
+ logging.info(f"Right or with defects: 1 or 0: {response_answer}")
168
 
169
  # Транскрибация аудио с помощью Whisper
170
  transcription_result = whisper_model.transcribe(tmp_filename, language="russian")
 
186
 
187
  # Возврат результатов
188
  return {
189
+ "prediction": response_answer,
190
  "match_phrase": match_phrase
191
  }
192
 
best_model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6044b8558b0f84731adc10353ae525c7a76b710127bf4de33aeecd620d8bc4be
3
+ size 34790773
best_model_2.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:40e263882edea1f1f1517a3ed580af0d994d0b2529bec20b04afa3801233a3ab
3
+ size 34790755
utils_api.py CHANGED
@@ -7,59 +7,161 @@ from tensorflow.keras.models import Sequential
7
  import tensorflow_hub as hub
8
  import soundfile as sf
9
  import tensorflow as tf
 
 
10
 
11
- # Load the embedding model globally to avoid reloading it every time
 
 
 
 
 
 
 
12
  embedding_model = hub.load("https://www.kaggle.com/models/google/speech-embedding/TensorFlow1/speech-embedding/1")
13
 
 
 
 
 
 
14
  def load_audio(audio_file_path):
 
 
 
 
 
 
 
15
  try:
16
  audio_samples, sample_rate = librosa.load(audio_file_path, sr=None)
17
  audio_samples = audio_samples.astype(np.float32)
18
- audio_samples /= np.max(np.abs(audio_samples))
19
  return audio_samples, sample_rate
20
  except Exception as e:
21
- print(f"Error loading {audio_file_path}: {e}")
22
  return None, None
23
 
24
  def pad_or_trim(audio, sr, target_length=5):
 
 
 
 
 
 
 
 
 
25
  target_samples = int(target_length * sr)
26
  return librosa.util.fix_length(audio, size=target_samples) if len(audio) < target_samples else audio[:target_samples]
27
 
28
  def get_features(path, duration=5):
 
 
 
 
 
 
 
 
29
  try:
30
  data, sample_rate = load_audio(path)
31
-
32
- # Model need 16000 sample rate
33
- if sample_rate != 16000:
34
- data = librosa.resample(data, orig_sr=sample_rate, target_sr=16000)
35
- sample_rate = 16000
36
-
37
  data = pad_or_trim(data, sample_rate)
38
  except Exception as e:
39
- print(f"Error loading {path}: {e}")
40
  return None
41
 
42
- embeddings = extract_embeddings(np.expand_dims(data, axis=0)) # Add batch dimension
 
43
 
44
- if embeddings is not None:
45
- return embeddings
46
- else:
47
- return None # Fail
48
 
49
  def extract_embeddings(audio_samples):
50
- """Extract embeddings from audio samples."""
 
 
 
 
 
 
51
  try:
52
- # Convert audio samples to tensor and extract embeddings
53
  embeddings = embedding_model.signatures['default'](tf.convert_to_tensor(audio_samples))
54
- return embeddings['default'].numpy().flatten()
 
 
 
 
 
 
 
55
  except Exception as e:
56
- print(f"Error extracting embeddings: {e}")
57
- return None # Return None if there's an error
58
 
59
- def pad_or_trim(feature, target_shape):
60
- """Pad or trim feature array to ensure a consistent shape."""
61
- if len(feature) > target_shape:
62
- feature = feature[:target_shape]
63
- elif len(feature) < target_shape:
64
- feature = np.pad(feature, (0, target_shape - len(feature)), mode='constant')
65
- return feature
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  import tensorflow_hub as hub
8
  import soundfile as sf
9
  import tensorflow as tf
10
+ from scipy.signal import resample, butter, lfilter
11
+ import logging
12
 
13
+ # Настройка логирования для отслеживания ошибок и процесса выполнения
14
+ logging.basicConfig(
15
+ level=logging.INFO,
16
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
17
+ handlers=[logging.StreamHandler()]
18
+ )
19
+
20
+ # Загрузка модели для извлечения эмбеддингов из речи
21
  embedding_model = hub.load("https://www.kaggle.com/models/google/speech-embedding/TensorFlow1/speech-embedding/1")
22
 
23
+ # Константы для фильтрации звука
24
+ LOWCUT = 400 # Нижняя частота среза в Гц
25
+ HIGHCUT = 5000 # Верхняя частота среза в Гц
26
+ ORDER = 5 # Порядок фильтра
27
+
28
  def load_audio(audio_file_path):
29
+ """
30
+ Загрузка аудиофайла и нормализация его амплитуды
31
+ Args:
32
+ audio_file_path: путь к аудиофайлу
33
+ Returns:
34
+ кортеж (аудио данные, частота дискретизации)
35
+ """
36
  try:
37
  audio_samples, sample_rate = librosa.load(audio_file_path, sr=None)
38
  audio_samples = audio_samples.astype(np.float32)
39
+ audio_samples /= np.max(np.abs(audio_samples)) # Нормализация амплитуды
40
  return audio_samples, sample_rate
41
  except Exception as e:
42
+ logging.exception(f"Error loading {audio_file_path}: {e}")
43
  return None, None
44
 
45
  def pad_or_trim(audio, sr, target_length=5):
46
+ """
47
+ Обрезка или дополнение аудио до заданной длительности
48
+ Args:
49
+ audio: аудио данные
50
+ sr: частота дискретизации
51
+ target_length: целевая длительность в секундах
52
+ Returns:
53
+ обработанные аудио данные
54
+ """
55
  target_samples = int(target_length * sr)
56
  return librosa.util.fix_length(audio, size=target_samples) if len(audio) < target_samples else audio[:target_samples]
57
 
58
  def get_features(path, duration=5):
59
+ """
60
+ Извлечение признаков из аудиофайла
61
+ Args:
62
+ path: путь к аудиофайлу
63
+ duration: длительность в секундах
64
+ Returns:
65
+ эмбеддинги аудио или None в случае ошибки
66
+ """
67
  try:
68
  data, sample_rate = load_audio(path)
69
+ data, sample_rate = upgrade_sound(data, sample_rate) # Улучшение качества звука
 
 
 
 
 
70
  data = pad_or_trim(data, sample_rate)
71
  except Exception as e:
72
+ logging.exception(f"Error loading {path}: {e}")
73
  return None
74
 
75
+ data = np.array(data, dtype=np.float32) # Преобразование в float32
76
+ embeddings = extract_embeddings(np.expand_dims(data, axis=0)) # Добавление размерности батча
77
 
78
+ return embeddings if embeddings is not None else None
 
 
 
79
 
80
  def extract_embeddings(audio_samples):
81
+ """
82
+ Извлечение эмбеддингов из аудио с помощью предобученной модели
83
+ Args:
84
+ audio_samples: аудио данные
85
+ Returns:
86
+ эмбеддинги в форме (1, n_features)
87
+ """
88
  try:
89
+ # Преобразование в тензор и получение эмбеддингов
90
  embeddings = embedding_model.signatures['default'](tf.convert_to_tensor(audio_samples))
91
+
92
+ # Получение тензора эмбеддингов
93
+ embeddings_tensor = embeddings['default'].numpy()
94
+
95
+ # Преобразование формы для соответствия входу модели
96
+ embeddings_flat = embeddings_tensor.reshape((1, -1))
97
+
98
+ return embeddings_flat
99
  except Exception as e:
100
+ logging.exception(f"Error extracting embeddings: {e}")
101
+ return None
102
 
103
+ def butter_bandpass(lowcut, highcut, sr, order=5):
104
+ """
105
+ Создание полосового фильтра Баттерворта
106
+ Args:
107
+ lowcut: нижняя частота среза
108
+ highcut: верхняя частота среза
109
+ sr: частота дискретизации
110
+ order: порядок фильтра
111
+ Returns:
112
+ коэффициенты фильтра (b, a)
113
+ """
114
+ nyquist = 0.5 * sr
115
+ low = lowcut / nyquist
116
+ high = highcut / nyquist
117
+ return butter(order, [low, high], btype='band')
118
+
119
+ def apply_bandpass_filter(y, sr, lowcut=LOWCUT, highcut=HIGHCUT, order=ORDER):
120
+ """
121
+ Применение полосового фильтра к аудио
122
+ Args:
123
+ y: аудио данные
124
+ sr: частота дискретизации
125
+ lowcut: нижняя частота среза
126
+ highcut: верхняя частота среза
127
+ order: порядок фильтра
128
+ Returns:
129
+ отфильтрованные аудио данные
130
+ """
131
+ b, a = butter_bandpass(lowcut, highcut, sr, order)
132
+ return lfilter(b, a, y)
133
+
134
+ def resample_audio(y, sr, target_sr=16000):
135
+ """
136
+ Передискретизация аудио до целевой частоты
137
+ Args:
138
+ y: аудио данные
139
+ sr: исходная частота дискретизации
140
+ target_sr: целевая частота дискретизации
141
+ Returns:
142
+ кортеж (передискретизированные данные, новая частота)
143
+ """
144
+ if sr != target_sr:
145
+ num_samples = round(len(y) * float(target_sr) / sr)
146
+ return resample(y, num_samples), target_sr
147
+ return y, sr
148
+
149
+ def upgrade_sound(y, sr):
150
+ """
151
+ Комплексное улучшение качества звука
152
+ Args:
153
+ y: аудио данные
154
+ sr: частота дискретизации
155
+ Returns:
156
+ кортеж (улучшенные аудио данные, частота дискретизации)
157
+
158
+ Выполняет:
159
+ 1. Передискретизацию до 16кГц
160
+ 2. Нормализацию амплитуды
161
+ 3. Полосовую фильтрацию
162
+ 4. Предварительное усиление высоких частот
163
+ """
164
+ y_resampled, sr = resample_audio(y, sr)
165
+ y_normalized = librosa.util.normalize(y_resampled)
166
+ y_filtered = apply_bandpass_filter(y_normalized, sr)
167
+ return librosa.effects.preemphasis(y_filtered), sr