Предыдущая часть: Часть 1
Сверточные нейронные сети (CNN) схожи с обычными нейронными сетями: они состоят из нейронов с обучаемыми весами и сдвигами. Каждый нейрон получает входные данные, выполняет скалярное произведение и при необходимости добавляет нелинейную оптимизацию. Вся сеть выражает одну дифференцируемую функцию оценки: начиная от пикселей «сырых» изображений и заканчивая оценкой класса. Они также обладают функцией потерь (например, SVM/Softmax) на последнем (полностью подключенном) слое.
В чем же заключаются различия? Архитектуры ConvNet делают предположение, что входные данные являются изображениями, благодаря чему определенные свойства могут быть зашифрованы в архитектуру. В результате функция пересылки становится более эффективной для реализации, а количество параметров в сети значительно уменьшается.
Они способны обнаруживать первичные функции, которые затем объединяются последующими слоями архитектуры CNN, что приводит к обнаружению более сложных и релевантных признаков.
Для работы с нейронными сетями мы будем использовать Google Colab — бесплатный сервис, предоставляющий GPU и TPU в качестве сред выполнения.
Для начала загружаем все необходимые библиотеки:
import pandas as pd
import numpy as np
from numpy import argmax
import matplotlib.pyplot as plt
%matplotlib inline
import librosa
import librosa.display
import IPython.display
import random
import warnings
import os
from PIL import Image
import pathlib
import csv
# Предварительная обработка sklearn
from sklearn.model_selection import train_test_split
# Keras
import keras
import warnings
warnings.filterwarnings('ignore')
from keras import layers
from keras.layers import Activation, Dense, Dropout, Conv2D, Flatten, MaxPooling2D, GlobalMaxPooling2D, GlobalAveragePooling1D, AveragePooling2D, Input, Add
from keras.models import Sequential
from keras.optimizers import SGD
Теперь преобразуем файлы аудиоданных в PNG или извлекаем спектрограмму для каждого аудио с помощью библиотеки Python librosa:
genres = 'blues classical country disco hiphop jazz metal pop reggae rock'.split()
for g in genres:
pathlib.Path(f'img_data/{g}').mkdir(parents=True, exist_ok=True)
for filename in os.listdir(f'./drive/My Drive/genres/{g}'):
songname = f'./drive/My Drive/genres/{g}/{filename}'
y, sr = librosa.load(songname, mono=True, duration=5)
print(y.shape)
plt.specgram(y, NFFT=2048, Fs=2, Fc=0, noverlap=128, cmap=cmap, sides='default', mode='default', scale='dB');
plt.axis('off');
plt.savefig(f'img_data/{g}/{filename[:-3].replace(".", "")}.png')
plt.clf()
Приведенный выше код создает директорию img_data, содержащую все изображения, классифицированные по жанрам.
Ниже приведены спектрограммы семплов:
Диско Классика Блюз КантриСледующий шаг — разделение данных на наборы для обучения и тестирования.
Устанавливаем split_folders:
pip install split_folders80% данных будет использоваться для обучения и 20% для тестирования.
import split_folders
# Для создания наборов для обучения и тестирования устанавливаем кортеж в `ratio`, т.е., `(.8, .2)`.
split_folders.ratio('./img_data/', output="./data", seed=1337, ratio=(.8, .2)) # значения по умолчанию
Приведенный выше код возвращает две директории для обучающего и тестового набора в родительскую:
Увеличение числа изображений
Увеличение числа изображений представляет собой искусственное создание обучающих изображений с помощью различных способов обработки, таких как случайная ротация, переходы, сдвиги, перевороты и т.д.
В Keras есть класс ImageDataGenerator, значительно упрощающий этот процесс. Ознакомиться с ним можно в официальной документации Keras.
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
rescale=1./255, # изменение масштаба всех значений пикселей с 0 до 255, после этого шага они будут находится в диапазоне (0,1)
shear_range=0.2, # применение случайных преобразований
zoom_range=0.2, # увеличение масштаба
horizontal_flip=True) # горизонтальный поворот
test_datagen = ImageDataGenerator(rescale=1./255)
У класса ImageDataGenerator есть три метода: flow(), flow_from_directory() и flow_from_dataframe() для чтения изображений из массива и папок. Мы рассмотрим только flow_from_directory().
training_set = train_datagen.flow_from_directory(
'./data/train',
target_size=(64, 64),
batch_size=32,
class_mode='categorical',
shuffle = False)
test_set = test_datagen.flow_from_directory(
'./data/val',
target_size=(64, 64),
batch_size=32,
class_mode='categorical',
shuffle = False )
Он обладает следующими аргументами:
Создаем сверточную нейронную сеть:
model = Sequential()
input_shape=(64, 64, 3)
# первый скрытый слой
model.add(Conv2D(32, (3, 3), strides=(2, 2), input_shape=input_shape))
model.add(AveragePooling2D((2, 2), strides=(2,2)))
model.add(Activation('relu'))
# второй скрытый слой
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(AveragePooling2D((2, 2), strides=(2,2)))
model.add(Activation('relu'))
# третий скрытый слой
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(AveragePooling2D((2, 2), strides=(2,2)))
model.add(Activation('relu'))
# слой выравнивания
model.add(Flatten())
model.add(Dropout(rate=0.5))
# полносвязный слой
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(rate=0.5))
# выходной слой
model.add(Dense(10))
model.add(Activation('softmax'))
model.summary()
Скомпилируйте/обучите сеть с помощью стохастического градиентного спуска (SGD). При использовании этого метода несколько семплов выбираются случайным образом вместо полного набора данных для каждой итерации.
epochs = 200
batch_size = 8
learning_rate = 0.01
decay_rate = learning_rate / epochs
momentum = 0.9
sgd = SGD(lr=learning_rate, momentum=momentum, decay=decay_rate, nesterov=False)
model.compile(optimizer="sgd", loss="categorical_crossentropy", metrics=['accuracy'])
Теперь подгоняем модель с 50 эпохами:
model.fit_generator(
training_set,
steps_per_epoch=100,
epochs=50,
validation_data=test_set,
validation_steps=200)
После обучения модели CNN переходим к ее оценке. evaluate_generator()
использует как тестовый ввод, так и вывод. Сначала он прогнозирует выходные данные с помощью набора для обучения, а затем оценивает производительность в сравнении с тестовым набором. Таким образом, он выдает показатель эффективности, в данном случае точность.
# Оценка модели
model.evaluate_generator(generator=test_set, steps=50)
# Вывод
[1.704445120342617, 0.33798882681564246]
Таким образом, потеря составляет 1,70, а точность — 33,7%.
Наконец, переходим к прогнозированию на тестовом наборе данных. Перед вызовом predict_generator необходимо перезагрузить test_set. В противном случае выходные данные будут получены в странном порядке.
test_set.reset()
pred = model.predict_generator(test_set, steps=50, verbose=1)
На данный момент у predicted_class_indices есть прогнозируемые метки, однако сами прогнозы невозможно определить. Теперь нужно сопоставить эти метки с их уникальными id, такими как имена файлов.
predicted_class_indices=np.argmax(pred,axis=1)
labels = (training_set.class_indices)
labels = dict((v,k) for k,v in labels.items())
predictions = [labels[k] for k in predicted_class_indices]
predictions = predictions[:200]
filenames=test_set.filenames
Добавьте имена файлов и прогнозы к единому фрейму данных Pandas в виде двух отдельных столбцов. Но перед этим убедитесь, что они одинакового размера.
print(len(filename, len(predictions)))
# (200, 200)
Наконец, сохраняем результаты в файл CSV:
results=pd.DataFrame({"Filename":filenames,
"Predictions":predictions},orient='index')
results.to_csv("prediction_results.csv",index=False)
Вывод
Модель была обучена на 50 эпохах (на выполнение на Nvidia K80 GPU потребовалось 1,5 часа). Для повышения точности количество эпох можно увеличить до 1000 и более.
CNN — это эффективная альтернатива для автоматического извлечения признаков, что подтверждает гипотезу о том, что внутренние характеристики вариаций музыкальных данных аналогичны характеристикам данных изображений. Созданная модель CNN обладает высокой масштабируемостью, но недостаточно надежна для обобщения результатов обучения для невидимых ранее музыкальных данных. Эта проблема решается с помощью расширенного набора данных.
На этом все. Спасибо за внимание!
Перевод статьи Nagesh Singh Chauhan: Audio Data Analysis Using Deep Learning with Python (Part 2)
Комментарии