Александр Иванов – Python в аудио-спецэффектах. Как работают нейросети изнутри. (страница 7)
# Генерируем данные
X, y = generate_synthetic_data(500)
# Разделяем на обучающую и тестовую выборки
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# Преобразуем в тензоры PyTorch
X_train_tensor = torch.tensor(X_train)
y_train_tensor = torch.tensor(y_train, dtype=torch.long)
X_test_tensor = torch.tensor(X_test)
y_test_tensor = torch.tensor(y_test, dtype=torch.long)
print(f"Обучающих примеров: {len(X_train)}")
print(f"Тестовых примеров: {len(X_test)}")
# Обучаем модель
model = SoundClassifier()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
num_epochs = 200
for epoch in range(num_epochs):
# Прямой проход
outputs = model(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
# Обратный проход и оптимизация
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 40 == 0 or epoch == num_epochs - 1:
# Оцениваем точность на тестовой выборке
with torch.no_grad():
test_outputs = model(X_test_tensor)
_, predicted = torch.max(test_outputs, 1)
accuracy = (predicted == y_test_tensor).float().mean()
print(f"Эпоха {epoch:3d}: Потери = {loss.item():.4f}, Точность = {accuracy:.2%}")
print("\nОбучение завершено!")
Запустите этот код. Вы увидите, как потери уменьшаются от эпохи к эпохе, а точность на тестовой выборке растёт. К концу обучения модель должна достигнуть точности выше девяноста процентов — это означает, что она хорошо научилась отличать три класса звуков друг от друга.
Разберём, что происходит при обучении. criterion = nn.CrossEntropyLoss() — функция потерь, которая измеряет, насколько предсказания модели отличаются от правильных ответов. optimizer = optim.Adam(model.parameters(), lr=0.01) — оптимизатор Adam, который сам подбирает величину шага для каждого параметра. loss.backward() — магия PyTorch: автоматически вычисляет градиенты для всех параметров модели. optimizer.step() — обновляет параметры в направлении уменьшения ошибки.
Применяем модель к реальному звуку
Теперь давайте проверим нашу модель на реальном аудиофайле. Мы загрузим запись, извлечём признаки и посмотрим, какие классы модель предсказывает для разных фреймов.
python
def classify_audio_file(filepath, model, label_names):
"""Классифицирует аудиофайл по фреймам."""
y, sr = librosa.load(filepath, sr=22050, mono=True)
features = extract_features(y, sr)
# Преобразуем в тензор
features_tensor = torch.tensor(features)
# Предсказываем
with torch.no_grad():
outputs = model(features_tensor)
_, predicted = torch.max(outputs, 1)
# Считаем статистику
unique, counts = np.unique(predicted.numpy(), return_counts=True)
total = len(predicted)
print(f"\nАнализ файла: {filepath}")
print(f" Всего фреймов: {total}")
for cls, count in zip(unique, counts):
print(f" {label_names[cls]}: {count} фреймов ({count / total:.1%})")
return predicted.numpy()
# Классифицируем тестовый файл (если есть) или создадим синтетический
label_names = ['Речь', 'Музыка', 'Шум']
# Создадим тестовый сигнал: первые 2 секунды — тон (музыка), затем шум, затем речь из файла
sr = 22050
t = np.linspace(0, 4.0, int(sr * 4.0), endpoint=False)
test_signal = np.zeros_like(t)
# Музыка: синусоида с обертонами
test_signal[:int(1.5 * sr)] = (np.sin(2 * np.pi * 440 * t[:int(1.5 * sr)]) +