Мы познакомились с основами машинного обучения, классификации и регрессии. В этой статье мы немного углубимся и поработаем над тем, как провести классификацию аудио. Мы обучим свёрточную нейронную сеть, многослойный персептрон и SVM для этой задачи. Тот же код можно легко расширить для обучения и других моделей классификации. Я настоятельно рекомендую вам ознакомиться с предыдущими статьями по основам классификации, если вы еще этого не сделали.

Главный вопрос здесь в том, как мы можем обрабатывать аудиофайлы и преобразовывать их в форму, которую мы можем передать в наши нейронные сети.



На настройку и получение вашего первого рабочего аудиоклассификатора уйдет меньше часа! Итак, приступим! 😉

Зависимости

Мы будем использовать Python. Прежде чем мы сможем начать кодирование, нам нужны следующие модули. Его можно легко загрузить с помощью pip.

  1. Керас
  2. либроза
  3. звуковое устройство
  4. SoundFile
  5. scikit-learn
  6. 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 разные модели, разница в точности между ними была очень небольшой. Оставляйте комментарии, если найдете способ улучшить этот результат.

Удачного обучения 😸