Мы познакомились с основами машинного обучения, классификации и регрессии. В этой статье мы немного углубимся и поработаем над тем, как провести классификацию аудио. Мы обучим свёрточную нейронную сеть, многослойный персептрон и SVM для этой задачи. Тот же код можно легко расширить для обучения и других моделей классификации. Я настоятельно рекомендую вам ознакомиться с предыдущими статьями по основам классификации, если вы еще этого не сделали.
Главный вопрос здесь в том, как мы можем обрабатывать аудиофайлы и преобразовывать их в форму, которую мы можем передать в наши нейронные сети.
На настройку и получение вашего первого рабочего аудиоклассификатора уйдет меньше часа! Итак, приступим! 😉
Зависимости
Мы будем использовать Python. Прежде чем мы сможем начать кодирование, нам нужны следующие модули. Его можно легко загрузить с помощью pip.
- Керас
- либроза
- звуковое устройство
- SoundFile
- scikit-learn
- matplotlib
Набор данных
Мы собираемся использовать набор данных ESC-10 для классификации звука. Это маркированный набор из 400 записей окружающей среды (10 классов, 40 клипов на класс, 5 секунд на клип). Это подмножество более крупного набора данных ESC-50.
Https://github.com/karoldvl/ESC-50/
Каждый класс содержит 40 файлов .ogg. Наборы данных ESC-10 и ESC-50 были предварительно сгруппированы в 5 складок одинакового размера, так что клипы, извлеченные из одной и той же исходной исходной записи, всегда содержались в одной складке.
Визуализировать набор данных
Прежде чем мы сможем извлечь функции и обучить нашу модель, нам нужно визуализировать форму волны для различных классов, присутствующих в нашем наборе данных.
import matplotlib.pyplot as plt
import numpy as np
import wave
import soundfile as sf
Приведенная ниже функция visualize_wav()
принимает файл ogg, читает его с помощью модуля звукового файла и возвращает данные и частоту дискретизации. Мы можем использовать функцию sf.wav()
для записи файла wav для соответствующего файла ogg. Используя matplotlib, мы строим график сигнала во времени и генерируем график.
def visualize_wav(oggfile):
data, samplerate = sf.read(oggfile)
if not os.path.exists('sample_wav'): os.mkdir('sample_wav')
sf.write('sample_wav/new_file.wav', data, samplerate) spf = wave.open('sample_wav/new_file_Fire.wav') signal = spf.readframes(-1) signal = np.fromstring(signal,'Int16')
if spf.getnchannels() == 2: print('just mono files. not stereo') sys.exit(0)
# plotting x axis in seconds. create time vector spaced linearly with size of audio file. divide size of signal by frame rate to get stop limit Time = np.linspace(0,len(signal)/samplerate, num = len(signal)) plt.figure(1) plt.title('Signal Wave Vs Time(in sec)') plt.plot(Time, signal) plt.savefig('sample_wav/sample_waveplot_Fire.png', bbox_inches='tight') plt.show()
Вы можете запустить один и тот же код, чтобы сгенерировать волновой график для разных классов и визуализировать разницу.
Извлечение функций
Для каждого аудиофайла в наборе данных мы извлечем MFCC (мел-частотный кепстр - у нас будет представление изображения для каждого аудиосэмпла) вместе с его классификационной меткой. Для этого мы будем использовать mfcc()
функцию Librosa, которая генерирует MFCC из аудиоданных временного ряда.
get_features()
берет файл .ogg и извлекает mfcc с помощью библиотеки Librosa.
def get_features(file_name):
if file_name: X, sample_rate = sf.read(file_name, dtype='float32')
# mfcc (mel-frequency cepstrum) mfccs = librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40) mfccs_scaled = np.mean(mfccs.T,axis=0) return mfccs_scaled
Набор данных загружается в папку «набор данных». Мы будем перебирать подкаталоги (каждый класс) и извлекать функции из их файлов ogg. Наконец, мы создадим фрейм данных с функцией mfcc и соответствующей меткой класса.
def extract_features():
# path to dataset containing 10 subdirectories of .ogg files sub_dirs = os.listdir('dataset') sub_dirs.sort() features_list = [] for label, sub_dir in enumerate(sub_dirs): for file_name in glob.glob(os.path.join('dataset',sub_dir,"*.ogg")): print("Extracting file ", file_name) try: mfccs = get_features(file_name) except Exception as e: print("Extraction error") continue features_list.append([mfccs,label])
features_df = pd.DataFrame(features_list,columns = ['feature','class_label']) print(features_df.head()) return features_df
Модель поезда
После того, как мы извлекли функции, нам нужно преобразовать их в массив numpy, чтобы их можно было передать в нейронную сеть.
def get_numpy_array(features_df):
X = np.array(features_df.feature.tolist()) y = np.array(features_df.class_label.tolist()) # encode classification labels le = LabelEncoder() # one hot encoded labels yy = to_categorical(le.fit_transform(y)) return X,yy,le
X
и yy
разделены на данные поездов и испытаний в соотношении 80-20.
def get_train_test(X,y):
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.2, random_state = 42) return X_train, X_test, y_train, y_test
Теперь определим архитектуру нашей модели. Мы будем использовать Keras для создания нашей многослойной сети Perceptron.
def create_mlp(num_labels):
model = Sequential() model.add(Dense(256,input_shape = (40,))) model.add(Activation('relu')) model.add(Dropout(0.5))
model.add(Dense(256,input_shape = (40,))) model.add(Activation('relu')) model.add(Dropout(0.5))
model.add(Dense(num_labels)) model.add(Activation('softmax')) return model
Как только модель определена, нам нужно скомпилировать ее, указав потери, метрики и оптимизатор. Затем модель адаптируется к обучающим данным X_train
и y_train
. Наша модель обучена для 100 эпох с размером пакета 32. Обученная модель, наконец, сохраняется как файл .hd5 на диске. Эта модель может быть загружена позже для прогнозирования.
def train(model,X_train, X_test, y_train, y_test,model_file):
# compile the model model.compile(loss = 'categorical_crossentropy',metrics=['accuracy'],optimizer='adam')
print(model.summary())
print("training for 100 epochs with batch size 32")
model.fit(X_train,y_train,batch_size= 32, epochs = 100, validation_data=(X_test,y_test))
# save model to disk print("Saving model to disk") model.save(model_file)
Это оно! Мы разработали собственный классификатор звуков окружающей среды !! 😃
Точность вычислений
Теперь, очевидно, мы хотим проверить, насколько хорошо работает наша модель 😛
def compute(X_test,y_test,model_file):
# load model from disk loaded_model = load_model(model_file) score = loaded_model.evaluate(X_test,y_test) return score[0],score[1]*100
Выходная точность для MLP -
Test loss 1.5628961682319642
Test accuracy 78.7
Делать предсказания
Мы также можем предсказать метку класса для любого входного файла, который мы предоставляем, используя приведенный ниже код -
def predict(filename,le,model_file):
model = load_model(model_file) prediction_feature = extract_features.get_features(filename) if model_file == "trained_mlp.h5": prediction_feature = np.array([prediction_feature]) elif model_file == "trained_cnn.h5": prediction_feature = np.expand_dims(np.array([prediction_feature]),axis=2)
predicted_vector = model.predict_classes(prediction_feature) predicted_class = le.inverse_transform(predicted_vector) print("Predicted class",predicted_class[0]) predicted_proba_vector = model.predict_proba([prediction_feature])
predicted_proba = predicted_proba_vector[0] for i in range(len(predicted_proba)): category = le.inverse_transform(np.array([i])) print(category[0], "\t\t : ", format(predicted_proba[i], '.32f') )
Эта функция загрузит нашу предварительно обученную модель, извлечет mfcc из входного файла ogg, который вы предоставили, и выведет диапазон вероятностей для каждого класса. Тот, у кого максимальная вероятность, - это наш желаемый класс! 😃
Для образца файла ogg класса собак были следующие вероятностные прогнозы:
Predicted class 0
0 : 0.96639919281005859375000000000000
1 : 0.00000196780410988139919936656952
2 : 0.00000063572736053174594417214394
3 : 0.00000597824555370607413351535797
4 : 0.02464177832007408142089843750000
5 : 0.00003698830187204293906688690186
6 : 0.00031352625228464603424072265625
7 : 0.00013375715934671461582183837891
8 : 0.00846461206674575805664062500000
9 : 0.00000165236258453660411760210991
Прогнозируемый класс 0
, который был меткой класса для Dog
.
Заключение
Работать с аудиофайлами не так сложно, как казалось изначально. Аудио файлы могут быть легко представлены в виде данных временных рядов. У нас есть предопределенные библиотеки на Python, что упрощает нашу задачу.
Вы также можете проверить весь код в моем репозитории на Github. Здесь я обучил SVM, MLP и CNN для одного и того же набора данных, а код организован в соответствующие файлы, что упрощает понимание.
Хотя я обучил для этого 3 разные модели, разница в точности между ними была очень небольшой. Оставляйте комментарии, если найдете способ улучшить этот результат.
Удачного обучения 😸