Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[35.173.48.18] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здравствуйте.
Я делаю простую систему авторизации по голосу. Я реализовал простенькую программу, которая разбивает аудиофайл на фреймы и вычисляет MFCC коэффициенты. В результате я получаю матрицу коэффициентов, а дальше скармливаю ее в алгоритм LBG и получаю на выходе кодовою книгу. Дальше я вычисляю расстояние Евклида и получаю некоторое значение. Если это значение минимально, то я примерно могу определить, кто говорил из зарегистрированных в базе пользователей. Но проблема в том, что таким способом я не смогу определить пользователя если в БД он не зарегистрирован. Т.е., чтобы предоставить пользователю доступ мне нужно сравнить кодовые книги 1 пользователя и принять решение о предоставлении доступа. Но как принять это решение? Подскажите, пожалуйста, какой-нибудь алгоритм, чтобы определить с какой вероятностью голос 2-х человек похож. P.S. Я понимаю, что это все очень сложно на самом деле, но я пытаюсь сделать очень простую систему. |
Сообщ.
#2
,
|
|
|
Цитата В результате я получаю матрицу коэффициентов, а дальше скармливаю ее в алгоритм LBG и получаю на выходе кодовою книгу. Дальше я вычисляю расстояние Евклида и получаю некоторое значение. Если это значение минимально, то я примерно могу определить, кто говорил из зарегистрированных в базе пользователей. Нужно тренировать не кодовую книгу, а распределение GMM. В результате тогда будет получаться не расстояние Евклида, а вероятность. Преимущество GMM перед кодовой книгой в том, что кроме среднего GMM включает вариацию, что позволяет понимать, в каких пределах может изменяться сигнал. Или, кроме кодовой книги нужно вычислять границы изменения сигнала. Цитата Но проблема в том, что таким способом я не смогу определить пользователя если в БД он не зарегистрирован. Для того, чтобы выделить пользователя от остальных нужно натренировать общее распределение сигнала для всех пользователей (UBM, или universal background model). Тогда можно принимать решение между гипотезами - пользователь ли это или другой человек, и оптимальное решение будет соотношением вероятностей P(пользователь)/P(все люди). GMM для всех людей будет иметь больший разброс по вариации и, таким образом, будет больше для человека со стороны. Про алгоритмы идентификации диктора можно прочесть в хорошей книге: http://www.amazon.com/Fundamentals-Speaker...i/dp/0387775919 Скачать систему идентификации можно тут: http://mistral.univ-avignon.fr/publi_en.html Там же в статьях можно прочесть подробные описания применяемых алгоритмов, например, тут http://mistral.univ-avignon.fr/doc/publi/0...EY_Scheffer.pdf |
Сообщ.
#3
,
|
|
|
поделитесь, пожалуйста, простым для понимания исходником GMM, а то я не могу никак разобраться...
желательно на Java или С#. Добавлено я долго искал примеры GMM: http://staff.aist.go.jp/s.akaho/MixtureEM.html http://www.lix.polytechnique.fr/~nielsen/MEF/index_old.htm http://www.scale.uni-saarland.de/cms/tl_fi...assp10-sgmm.pdf http://consortium.simple4all.org/files/201...amiya_et_al.pdf и много других... Но везде или много непонятных формул без исходного кода, или есть код, но не понятно как его применить на практике. У меня есть массив коеф. MFCC: double [][] = new double[12][N]; N - количество векторов 12 - количество коеф. MFCC. Еще есть библиотека WEKA, но там непонятно как создавать *.arff файлы. Также встречал примеры с обработкой изображений с помощью GMM. |
Сообщ.
#4
,
|
|
|
Цитата поделитесь, пожалуйста, простым для понимания исходником GMM, а то я не могу никак разобраться... Чтобы понимать GMM, нужно разобраться в теории сначала, в алгоритме EM (expectation maximization). Без понимания теории исходный код не понять. Цитата Еще есть библиотека WEKA, но там непонятно как создавать *.arff файлы. Также встречал примеры с обработкой изображений с помощью GMM. В WEKA, например, можно использовать csv файлы вместо ARFF (текстовый файл со значениями, разделённый запятыми). http://weka.wikispaces.com/Can+I+use+CSV+files%3F |
Сообщ.
#5
,
|
|
|
В этой статье http://www.mathworks.com/company/newslette...-in-matlab.html для распознавания слов также используют MFCC+GMM.
В чем отличия при использовании MFCC+GMM для распознавания человека по голосу и распознавания слов? Если я правильно понимаю, то алгоритм примерно тот, же: нормалиация->FFT->log->DCT->MFCC->GMM. Цитата В WEKA, например, можно использовать csv файлы вместо ARFF (текстовый файл со значениями, разделённый запятыми). http://weka.wikispaces.com/Can+I+use+CSV+files%3F Проблема у меня не в формате файла (CSV, ARFF), а в том как правильно создать этот файл и что дальше делать. Я создал такой файл (формат согласно http://www.cs.waikato.ac.nz/~ml/weka/arff.html): Скрытый текст Цитата @RELATION train_mfcc @ATTRIBUTE k1 NUMERIC @ATTRIBUTE k2 NUMERIC @ATTRIBUTE k3 NUMERIC @ATTRIBUTE k4 NUMERIC @ATTRIBUTE k5 NUMERIC @ATTRIBUTE k6 NUMERIC @ATTRIBUTE k7 NUMERIC @ATTRIBUTE k8 NUMERIC @ATTRIBUTE k9 NUMERIC @ATTRIBUTE k10 NUMERIC @ATTRIBUTE k11 NUMERIC @ATTRIBUTE k12 NUMERIC @ATTRIBUTE k13 NUMERIC @ATTRIBUTE k14 NUMERIC @ATTRIBUTE k15 NUMERIC @ATTRIBUTE k16 NUMERIC @ATTRIBUTE k17 NUMERIC @ATTRIBUTE k18 NUMERIC @ATTRIBUTE k19 NUMERIC @ATTRIBUTE k20 NUMERIC @DATA -32.3498, 4.0605, 5.8301, 3.0689, -2.8713, 4.5942, 1.2795, 4.3517, 0.5966, 1.0423, 0.2772, 1.8529, -0.3554, 0.682, -1.1851, 0.5094, -0.3388, -0.447, -0.477, -0.1983 -22.1714, 11.6567, 0.9019, 3.1513, -4.0799, -0.1471, 0.0523, 3.1226, 0.4186, 0.3383, -0.1819, 0.2799, 0.9002, -0.1322, -0.0654, -0.4336, 0.0645, 0.0541, -0.4947, 0.4486 -17.7415, 12.9399, -1.1669, 4.0394, -4.5064, -0.848, 0.8684, 3.3472, 0.1241, 0.7678, -0.437, 1.142, 1.1662, -0.4765, 0.1562, -0.6562, 0.1151, -0.4745, -0.2884, 0.5798 -15.7587, 11.7175, -1.3064, 3.4384, -4.5473, 0.0878, -0.0937, 3.8573, -0.9389, 0.5959, -1.583, 2.5714, 0.0397, 0.1557, -0.2259, -0.5382, 0.0895, -0.5952, -0.1294, 0.5923 -14.8299, 11.5163, -0.8506, 2.6221, -3.7514, -1.5211, 0.0827, 2.8456, -0.3039, -0.2845, -0.4518, 1.9514, 1.0591, -0.4259, -0.0208, -0.9849, 0.2597, -0.1178, 0.0367, 0.5465 -16.5354, 13.0119, -0.7588, 2.7527, -4.0031, -1.4531, -0.014, 1.9984, -0.2771, -0.7085, -0.2466, 1.4909, 0.9616, -0.9521, -0.2399, -0.6355, 0.0683, 0.4254, -0.2596, 0.5112 -17.0784, 12.9701, -0.3731, 3.6204, -4.8669, -0.7527, -0.0437, 2.3372, -0.9504, 0.6396, -1.045, 1.9671, 0.3374, -0.8312, 0.1097, -0.8346, 0.2744, -0.299, 0.1362, 0.584 17.8279, 11.8431, -0.0373, 3.2749, -5.9843, -0.5036, -0.0407, 1.9581, -0.9016, -0.0151, -0.3362, 2.2256, 0.8158, -1.1666, -0.0412, -0.2118, 0.1392, -0.0786, -0.195, 0.3339 -17.5583, 14.0317, 0.6605, 2.9566, -5.1855, 1.2289, 0.342, 1.768, -0.5752, -0.7489, 0.0884, 2.3976, 0.7062, -0.7034, -0.1701, 0.1148, -0.2311, 0.3706, -0.4088, 0.0948 -14.2456, 11.5991, -0.8751, 2.7092, -5.1847, 1.0162, -0.1195, 1.3294, -1.4993, -0.5606, -0.3121, 2.1927, 0.5673, -0.3341, -0.7374, 0.2916, -0.3252, 0.368, -0.3364, 0.0532 -14.96, 12.7157, -1.6107, 3.1761, -4.815, 1.2706, -0.0858, 1.4589, -1.7943, -0.3679, -0.0455, 1.2875, 0.6884, -0.5105, -1.2056, 0.1294, -0.3311, 0.3149, 0.0293, -0.1 -16.1005, 13.5202, -1.0193, 4.1524, -4.2875, 1.1936, 1.3232, 0.2577, -1.629, -0.1102, 0.8293, 2.0851, 0.804, -0.3667, -0.3707, -0.194, -0.2832, 0.7501, 0.5325, 0.1284 -16.9499, 11.8779, -0.5173, 4.1349, -4.0047, -0.9061, 2.6433, -1.121, -1.4609, -0.7473, 0.0262, 2.1373, 0.4892, -0.2107, 0.3484, -0.6026, -0.5675, 0.517, 0.2577, -0.4453 -21.813, 12.656, -2.1174, 5.9518, -3.6495, -1.899, 1.914, -0.5438, -3.0692, -0.0507, -1.0886, 1.277, -0.535, -0.7092, 0.4369, -0.2334, -0.7128, 0.0336, 0.5755, 0.0062 -29.7809, 10.5696, 1.8924, 4.8169, -0.6066, -1.1082, 2.8271, 0.4978, -1.384, 0.2966, 0.2374, 0.47, 1.0145, 0.3163, -0.3014, -0.5509, -0.9247, -0.0763, 0.3708, -0.2323 -39.4665, 11.7038, 5.5216, 5.4122, 2.6301, 0.9113, 1.5733, 0.399, -0.6269, 0.9535, 0.7488, 0.5937, -0.1416, 0.2795, -0.2759, -0.4314, -0.2536, 0.5792, -0.3839, -0.8368 -40.1275, 10.5679, 5.5873, 4.7788, 1.537, 0.9708, 0.9561, 0.7576, -0.1029, 0.252, 0.4989, 0.6563, 0.2654, -0.6313, -0.4296, 0.1563, -0.154, -0.0511, -0.0243, -0.5802 -40.6595, 11.3106, 5.3157, 4.9205, 1.8858, 1.2899, 1.2226, 0.7896, -1.1021, -0.0255, 0.388, 1.4903, -0.946, -0.8741, -0.4228, -0.5073, -0.3334, 0.2134, 0.4922, 0.6576 -40.7937, 9.4612, 6.3366, 5.3235, 1.7335, 2.8178, 1.3118, -0.0597, -0.5287, 0.6929, 0.1539, 0.4845, -0.2175, -0.1465, 0.0515, 0.2726, 0.0592, -0.1556, 0.1291, -0.2017 -41.1384, 11.4818, 5.6535, 4.7051, 1.9337, 2.4688, 1.5602, 0.8369, -0.1301, 0.9709, 0.56, 0.5075, -0.1387, -0.4169, 0.1217, 0.5877, -0.294, 0.1396, -0.0018, -0.2662 -40.8711, 10.9265, 6.0457, 5.6562, 2.0577, 1.0463, 0.546, 0.807, 0.6733, 1.3445, -0.2982, 0.0871, -0.4798, -0.1801, 0.5497, 0.607, -0.4527, -0.0106, -0.1941, -0.0726 k1-k20 - это коэффициенты MFCC, каждая строка - это вектор, который я получаю для каждого фрейма. Log likelihood: -26.14818 Дальше у меня будут, например, тестовые вектора, которые я хочу сравнить. А как это сделать? |
Сообщ.
#6
,
|
|
|
Цитата В чем отличия при использовании MFCC+GMM для распознавания человека по голосу и распознавания слов? При распознавании слов MFCC+GMM недостаточно, кроме выделения классов (звуков) нужно ещё и найти эти классы во времени (где каждый звук находится, какая последовательность звуков). Для распознавания речи используется MFCC + GMM + HMM (скрытая марковскаям модель). Именно использование скрытой марковской модели позволяет находить слова в непрерывном потоке речи. При распознавании человека не нужно выделять человека в потоке речи, записи каждого отдельного человека уже доступны. Достаточно их классифицировать (понять, к какому классу каждый образе относится). Цитата Если я правильно понимаю, то алгоритм примерно тот, же: нормалиация->FFT->log->DCT->MFCC->GMM. Алгоритм на этом не заканчивается - следующий этап это принятие решение о классификации. Если у нас есть набор распределений GMM, соответствующих классам, и тестовый образец, нам нужно сравнить оценки P(образец|GMM_i) и выбрать наилучший. Это и будет распознанный клас. Алгоритм одинаковый, и на странице matlab он изложен хорошо. Цитата Дальше у меня будут, например, тестовые вектора, которые я хочу сравнить. А как это сделать? Нужно построить набор GMM сначала для каждого человека. Затем вычислить P(образец|GMM_i), найти наилучший. Добавлено Weka не очень удобный инструмент для таких задач, по большому счету он не подходит, например, в Weka нет многомерных векторов в качестве признаков, только одномерные. Чтобы поэкспериментировать с классификацией в weka нужно создать один большой файл следующего формата с фреймами разных человек: class_label1, feature1, feature2, feature3, feature4 class_label1, feature1, feature2, feature3, feature4 class_label2, feature1, feature2, feature3, feature4 class_label2, feature1, feature2, feature3, feature4 И запускать на закладке classify разные методы по классификации class_label по данным feature. Тестовый файл в подобном формате можно приложить тоже. Попробовать можно libSVM, но ничего хорошего не будет. Лучше использовать приведённый выше пример на matlab или, например, более продвинутые инструменты для машинного обучения - scikit-learn http://scikit-learn.org/stable/modules/gen...ixture.GMM.html (python) или на java что-нибудь поискать. Реализаций много, но толковых мало. Comirva можно посмотеть, там вроде было http://www.cp.jku.at/people/schedl/Researc...ge/CoMIRVA.html |
Сообщ.
#7
,
|
|
|
Пытаюсь использовать для GMM библиотеку Comirva: подключил библиотеку и с ее помощью получил MFCC коэффициенты. Дальше пытаюсь получить GMM так как показано в примерах, но почему-то возникает CovarianceSingularityException на этой строчке кода:
user1_gmm.runEM(user1_pointList); //запуск Expectation-Maximization user1_pointList - список векторов с MFCC коэффициентами. Согласно http://www.cp.jku.at/people/schedl/researc...ianMixture.html Цитата Covariance Singularity Exception Description: This class indicates that during the EM training algorithm of a Gaussian Mixture Model one of the components got singular. A corrected list of points Might be passed through this exception, such that one can rerun the EM algorithm with the corrected list of points. Сделал еще один try/catch с getCorrectedPointList(), но все равно не работает - снова возникает Covariance Singularity Exception. Скрытый текст package net.test.VoiceControl; import java.io.File; import java.io.IOException; import net.test.VoiceControl.audio.AudioRecorder; import net.test.VoiceControl.audio.WaveData; import comirva.audio.util.MFCC; import comirva.audio.util.PointList; import comirva.audio.util.gmm.CovarianceSingularityException; import comirva.audio.util.gmm.GaussianMixture; import comirva.audio.util.kmeans.KMeansClustering; public class VoiceTest { //SAMPLE_RATE,WINDOW_SIZE,NUMCOEFICCIENT - window size = (1/22050)*512 = 23.2 ms private final int WINDOW_SIZE = 512; private final int SAMPLE_RATE = 22050; private final int MFCC_NUM = 13; private final int GAUSSIANS_NUM = 16; public VoiceTest() { //get input signal float [] signal1 = getSignalFromFile("user1_auth1.wav"); //cut signal int size = size = signal1.length / WINDOW_SIZE; double [] inputData1 = new double[size * WINDOW_SIZE]; for(int z=0;z<size*WINDOW_SIZE;z++) inputData1[z] = signal1[z]; //get MFCC MFCC mfcc = new MFCC(SAMPLE_RATE,WINDOW_SIZE,MFCC_NUM,true); double [][] user1_mfcc = null; try { user1_mfcc = mfcc.process(inputData1); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } ////get GMM //create a point list with appropriate dimensions PointList user1_pointList = new PointList(user1_mfcc[0].length); for(int z=0;z<user1_mfcc.length;z++) {double [] vector = user1_mfcc[z]; user1_pointList.add(vector);} GaussianMixture user1_gmm = null; try { //run k-means clustering algorithm to initialize the EM algorithem KMeansClustering kmeans = new KMeansClustering(GAUSSIANS_NUM, user1_pointList, false); kmeans.run(); //run EM algorithem for gaussian mixture model user1_gmm = new GaussianMixture(kmeans.getClusterWeights(), kmeans.getMeans(), kmeans.getFullCovariances()); user1_gmm.runEM(user1_pointList); } catch(CovarianceSingularityException cse) { //try to do the whole stuff once more with the corrected pointset try { //run k-means clustering algorithm to initialize the EM algorithem KMeansClustering kmeans = new KMeansClustering(GAUSSIANS_NUM, cse.getCorrectedPointList(), false); kmeans.run(); //run EM algorithem for gaussian mixture model user1_gmm = new GaussianMixture(kmeans.getClusterWeights(), kmeans.getMeans(), kmeans.getFullCovariances()); user1_gmm.runEM(cse.getCorrectedPointList()); } catch(CovarianceSingularityException cse2) { //well at this point we give up, we don't try further throw new IllegalArgumentException("cannot create GMM for this song;"); } } System.out.println("ok"); } public float [] getSignalFromFile(String filename) { File audiofile = new File(filename); WaveData waveData = new WaveData(); float[] signal = waveData.extractAmplitudeFromFile(audiofile); ////Input signal normalization AudioPreprocessor audioPreprocessor = new AudioPreprocessor(); float [] del_mic = audioPreprocessor.deleteMICEffects(signal,500); //delete MIC effect //authAudioRecorder.DisplayAmplitude(del_mic); float [] zero_amplitudes = audioPreprocessor.ZeroNormalization(del_mic); //authAudioRecorder.DisplayAmplitude(zero_amplitudes); float [] norm_amplitudes = audioPreprocessor.amplitudeNormalize(zero_amplitudes); //AudioRecorder.DisplayAmplitude(norm_amplitudes); float [] no_silence = audioPreprocessor.GauseSilenceRemover(norm_amplitudes, 22050); //AudioRecorder.DisplayAmplitude(no_silence); return no_silence; } } |
Сообщ.
#8
,
|
|
|
Цитата float [] norm_amplitudes = audioPreprocessor.amplitudeNormalize(zero_amplitudes); Нужно делать нормализацию среднего коэффициентов MFCC (cepstral mean normalization, PointList.normalize()), что обеспечивает нормализацию амплитуды по различным частотным каналам, а не просто нормализовать амплитуду сигнала. Цитата for(int z=0;z<size*WINDOW_SIZE;z++) inputData1[z] = signal1[z]; На окна нужно нарезать с перекрытием, лучше использовать AudioPreProcessor из comirva Цитата private final int GAUSSIANS_NUM = 16; Слишком много гауссианов, поэтому и не удаётся оценить GMM параметры. Попробуйте 1 гауссиан сначала или 2, если запись небольшая. Чтобы оценить 8 гауссианов нужна где-то минута записей. |
Сообщ.
#9
,
|
|
|
Цитата На окна нужно нарезать с перекрытием, лучше использовать AudioPreProcessor из comirva Переписал код с использованием AudioPreProcessor, стандартное перекрытие 50%. Раньше у меня было перекрытие 60% и я удалял тишину из файлов, но судя по исходниках AudioPreProcessor.java (http://www.cp.jku.at/people/schedl/Researc.../doc/index.html и http://code.google.com/p/mirlastfm/source/...cessor.java?r=3) не удаляет фрагменты тишины из файлов. Цитата Нужно делать нормализацию среднего коэффициентов MFCC (cepstral mean normalization, PointList.normalize()), что обеспечивает нормализацию амплитуды по различным частотным каналам, а не просто нормализовать амплитуду сигнала. Если делаю pointList.normalize(), то при создании GaussianMixture(kmeans.getClusterWeights(), kmeans.getMeans(), kmeans.getFullCovariances()) получаю IllegalArgumentException: mean and covariance matrix must have compatible shapes and the covarince matrix must not be singular. Скрытый текст Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: mean and covariance matrix must have compatible shapes and the covarince matrix must not be singular; at comirva.audio.util.gmm.GaussianComponent.<init>(GaussianComponent.java:86) at comirva.audio.util.gmm.GaussianMixture.<init>(GaussianMixture.java:94) //z-normalization //The normalization is done for every coordinate by subtracting //the mean and dividing by the standard deviation. user1_pointList = user1_pointList.normalize(); user2_pointList = user2_pointList.normalize(); user3_pointList = user3_pointList.normalize(); Цитата Слишком много гауссианов, поэтому и не удаётся оценить GMM параметры. Попробуйте 1 гауссиан сначала или 2, если запись небольшая. Чтобы оценить 8 гауссианов нужна где-то минута записей. Сделал 1 гауссиан - вроде работает(без pointList.normalize), но когда уже 2 гауссиана - то Covariance matrix got singular. package net.test.VoiceControl; import java.io.File; import java.io.IOException; import java.util.Vector; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; import comirva.audio.util.AudioPreProcessor; import comirva.audio.util.MFCC; import comirva.audio.util.PointList; import comirva.audio.util.gmm.CovarianceSingularityException; import comirva.audio.util.gmm.GaussianMixture; import comirva.audio.util.kmeans.KMeansClustering; import comirva.audio.util.math.Matrix; public class VoiceTest { //SAMPLE_RATE,WINDOW_SIZE,NUMCOEFICCIENT - window size = (1/22050)*512 = 23.2 ms private final int WINDOW_SIZE = 512; private final int SAMPLE_RATE = 22050; private final int MFCC_NUM = 13; private final int GAUSSIANS_NUM = 1; public VoiceTest() { //get input signal AudioPreProcessor audioPreProcessor1 = getAudioPreProcessor("user1_auth1.wav"); AudioPreProcessor audioPreProcessor2 = getAudioPreProcessor("user1_auth2.wav"); AudioPreProcessor audioPreProcessor3 = getAudioPreProcessor("user1_auth3.wav"); //get MFCC MFCC mfcc = new MFCC(SAMPLE_RATE,WINDOW_SIZE,MFCC_NUM,true); Vector<double[]> user1_mfcc = null; Vector<double[]> user2_mfcc = null; Vector<double[]> user3_mfcc = null; try { user1_mfcc = mfcc.process(audioPreProcessor1); user2_mfcc = mfcc.process(audioPreProcessor2); user3_mfcc = mfcc.process(audioPreProcessor3); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } ////get GMM //create a point list with appropriate dimensions PointList user1_pointList = new PointList(user1_mfcc.get(0).length); PointList user2_pointList = new PointList(user2_mfcc.get(0).length); PointList user3_pointList = new PointList(user3_mfcc.get(0).length); for(int z=0;z<user1_mfcc.size();z++) {double [] vector = user1_mfcc.get(z); user1_pointList.add(vector);} for(int z=0;z<user2_mfcc.size();z++) {double [] vector = user2_mfcc.get(z); user2_pointList.add(vector);} for(int z=0;z<user3_mfcc.size();z++) {double [] vector = user3_mfcc.get(z); user3_pointList.add(vector);} //z-normalization //The normalization is done for every coordinate by subtracting //the mean and dividing by the standard deviation. user1_pointList = user1_pointList.normalize(); user2_pointList = user2_pointList.normalize(); user3_pointList = user3_pointList.normalize(); GaussianMixture user1_gmm = null; GaussianMixture user2_gmm = null; GaussianMixture user3_gmm = null; //run k-means clustering algorithm to initialize the EM algorithem KMeansClustering kmeans = new KMeansClustering(GAUSSIANS_NUM, user1_pointList, false); kmeans.run(); user1_gmm = new GaussianMixture(kmeans.getClusterWeights(), kmeans.getMeans(), kmeans.getFullCovariances()); try { user1_gmm.runEM(user1_pointList); } catch (CovarianceSingularityException e) { // TODO Auto-generated catch block e.printStackTrace(); } double d1 = user1_gmm.getLogLikelihood(user1_pointList); double d2 = user1_gmm.getLogLikelihood(user2_pointList); double d3 = user1_gmm.getLogLikelihood(user3_pointList); System.out.println("LogLikelihood: d1="+Double.toString(d1)+"; d2="+Double.toString(d2)+"; d3="+Double.toString(d3)); } public float [] getSignalFromFile(String filename) { File audiofile = new File(filename); WaveData waveData = new WaveData(); float[] signal = waveData.extractAmplitudeFromFile(audiofile); ////Input signal normalization AudioPreprocessor audioPreprocessor = new AudioPreprocessor(); float [] del_mic = audioPreprocessor.deleteMICEffects(signal,500); //delete MIC effect //authAudioRecorder.DisplayAmplitude(del_mic); float [] zero_amplitudes = audioPreprocessor.ZeroNormalization(del_mic); //authAudioRecorder.DisplayAmplitude(zero_amplitudes); float [] norm_amplitudes = audioPreprocessor.amplitudeNormalize(zero_amplitudes); //AudioRecorder.DisplayAmplitude(norm_amplitudes); float [] no_silence = audioPreprocessor.GauseSilenceRemover(norm_amplitudes, 22050); //AudioRecorder.DisplayAmplitude(no_silence); return no_silence; } public AudioPreProcessor getAudioPreProcessor(String filename) { File audiofile = new File(filename); AudioInputStream audioInputStream = null; AudioPreProcessor audioPreProcessor = null; try { audioInputStream = AudioSystem.getAudioInputStream(audiofile); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //check input type if(audioInputStream == null || !(audioInputStream instanceof AudioInputStream)) throw new IllegalArgumentException("input type for the td feature extraction process should be AudioPreProcessor and must not be null"); else audioPreProcessor = new AudioPreProcessor((AudioInputStream) audioInputStream); double sample_rate = audioPreProcessor.getSampleRate(); return audioPreProcessor; } } LogLikelihood: d1=-527.3006807672704; d2=-3111.5296058075746; d3=-Infinity Если я правильно понимаю, то для того, чтобы получить Lamda_UBM = {mu_i;w_i;sigma_i} - мне нужно получить GMM модель для всех пользователей, тоесть в PointList будут вектора коэффициентов MFCC для всех пользователей. У меня будет GMM модель пользователя Lamda_user = {mu_i;w_i;sigma_i}, а дальше нужно получить LogLikelihood(gmm.getLogLikelihood(pointList)): S = log[P(X|Lamda_user)] - log[P(X|Lamda_UBM)]; Если S < меньше порогового значения Q, то данный фрагмент речи не принадлежит человеку. |
Сообщ.
#10
,
|
|
|
Цитата mean and covariance matrix must have compatible shapes and the covarince matrix must not be singular. Слишком мало данных для тренировки. Comirva тренирует full-covariance GMM, ему нужно очень много данных. Или нужно диагональный GMM реализовать Цитата Сделал 1 гауссиан - вроде работает(без pointList.normalize), но когда уже 2 гауссиана - то Covariance matrix got singular. Для экспериментов попробуйте начать хотя бы с минуты записей для каждого человека. С одного слова ничего хорошего не получится Цитата Если я правильно понимаю, то для того, чтобы получить Lamda_UBM = {mu_i;w_i;sigma_i} - мне нужно получить GMM модель для всех пользователей, тоесть в PointList будут вектора коэффициентов MFCC для всех пользователей. Правильно |
Сообщ.
#11
,
|
|
|
Записал 2 аудио файла по 1 минуте каждый. Прочитал файлы с помощью AudioPreProcessor, получил MFCC, создал GMM для пользователя и UBM (сейчас только для 1 пользователя, но 2 разные аудиофайлы). Дальше пытаюсь получить LogLikelihood:
double d1 = user1_gmm.getLogLikelihood(user2_pointList); double d2 = ubm_gmm.getLogLikelihood(user2_pointList); double L = user1_gmm.getLogLikelihood(user2_pointList) - ubm_gmm.getLogLikelihood(user2_pointList); System.out.println("LogLikelihood: d1="+Double.toString(d1)+"; d2="+Double.toString(d2)+"; L="+Double.toString(L)); В ответ получаю LogLikelihood: d1=NaN; d2=NaN; L=NaN. Цитата К операциям, приводящим к появлению NaN в качестве ответа, относятся: -все математические операции, содержащие NaN в качестве одного из операндов; -деление ноля на ноль; -деление бесконечности на бесконечность; -умножение ноля на бесконечность; -сложение бесконечности с бесконечностью противоположного знака; -вычисление квадратного корня отрицательного числа[1]; -логарифмирование отрицательного числа. Цитата Чтобы оценить 8 гауссианов нужна где-то минута записей. Длина записи 1 минута, но если увеличиваю количество гауссианов до 2, то получаю ошибку: mean and covariance matrix must have compatible shapes and the covarince matrix must not be singular. А тишину нужно удалять из файлов? import java.io.File; import java.io.IOException; import java.util.Vector; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; import net.mobfix.VoiceControl.audio.AudioRecorder; import net.mobfix.VoiceControl.audio.WaveData; import net.mobfix.VoiceControl.util.Graphics; import comirva.audio.util.AudioPreProcessor; import comirva.audio.util.MFCC; import comirva.audio.util.PointList; import comirva.audio.util.gmm.CovarianceSingularityException; import comirva.audio.util.gmm.GaussianMixture; import comirva.audio.util.kmeans.KMeansClustering; import comirva.audio.util.math.Matrix; public class VoiceTest { //SAMPLE_RATE,WINDOW_SIZE,NUMCOEFICCIENT - window size = (1/22050)*512 = 23.2 ms private final int WINDOW_SIZE = 512; private final int SAMPLE_RATE = 22050; private final int MFCC_NUM = 13; private final int GAUSSIANS_NUM = 1; public VoiceTest() { //get input signal AudioPreProcessor audioPreProcessor1 = getAudioPreProcessor("user1_long_auth1.wav"); AudioPreProcessor audioPreProcessor2 = getAudioPreProcessor("user1_long_auth2.wav"); //get MFCC MFCC mfcc = new MFCC(SAMPLE_RATE,WINDOW_SIZE,MFCC_NUM,true); Vector<double[]> user1_mfcc = null; Vector<double[]> user2_mfcc = null; try { user1_mfcc = mfcc.process(audioPreProcessor1); user2_mfcc = mfcc.process(audioPreProcessor2); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } ////get GMM //create a point list with appropriate dimensions PointList user1_pointList = new PointList(MFCC_NUM); PointList user2_pointList = new PointList(MFCC_NUM); PointList ubm_pointList = new PointList(MFCC_NUM); for(int z=0;z<user1_mfcc.size();z++) {double [] vector = user1_mfcc.get(z); user1_pointList.add(vector);} for(int z=0;z<user2_mfcc.size();z++) {double [] vector = user2_mfcc.get(z); user2_pointList.add(vector);} //add points to UBM for(int z=0;z<user1_mfcc.size();z++) {double [] vector = user1_mfcc.get(z); ubm_pointList.add(vector);} for(int z=0;z<user2_mfcc.size();z++) {double [] vector = user2_mfcc.get(z); ubm_pointList.add(vector);} //z-normalization //The normalization is done for every coordinate by subtracting //the mean and dividing by the standard deviation. user1_pointList = user1_pointList.normalize(); user2_pointList = user2_pointList.normalize(); ubm_pointList = ubm_pointList.normalize(); GaussianMixture user1_gmm = null; GaussianMixture user2_gmm = null; GaussianMixture ubm_gmm = null; //run k-means clustering algorithm to initialize the EM algorithem KMeansClustering kmeans1 = new KMeansClustering(GAUSSIANS_NUM, user1_pointList, false); kmeans1.run(); user1_gmm = new GaussianMixture(kmeans1.getClusterWeights(), kmeans1.getMeans(), kmeans1.getFullCovariances()); //UBM-GMM KMeansClustering kmeans_ubm = new KMeansClustering(GAUSSIANS_NUM, ubm_pointList, false); kmeans_ubm.run(); ubm_gmm = new GaussianMixture(kmeans_ubm.getClusterWeights(), kmeans_ubm.getMeans(), kmeans_ubm.getFullCovariances()); try { user1_gmm.runEM(user1_pointList); ubm_gmm.runEM(ubm_pointList); } catch (CovarianceSingularityException e) { e.printStackTrace(); } double d1 = user1_gmm.getLogLikelihood(user2_pointList); double d2 = ubm_gmm.getLogLikelihood(user2_pointList); double L = user1_gmm.getLogLikelihood(user2_pointList) - ubm_gmm.getLogLikelihood(user2_pointList); System.out.println("LogLikelihood: d1="+Double.toString(d1)+"; d2="+Double.toString(d2)+"; L="+Double.toString(L)); } public AudioPreProcessor getAudioPreProcessor(String filename) { File audiofile = new File(filename); AudioInputStream audioInputStream = null; AudioPreProcessor audioPreProcessor = null; try { audioInputStream = AudioSystem.getAudioInputStream(audiofile); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //check input type if(audioInputStream == null || !(audioInputStream instanceof AudioInputStream)) throw new IllegalArgumentException("input type for the td feature extraction process should be AudioPreProcessor and must not be null"); else audioPreProcessor = new AudioPreProcessor((AudioInputStream) audioInputStream); double sample_rate = audioPreProcessor.getSampleRate(); return audioPreProcessor; } } |
Сообщ.
#12
,
|
|
|
Лучше весь проект выложить в архиве вместе с данными, чтобы воспроизвести проблему, а не один исходный файл.
|
Сообщ.
#13
,
|
|
|
Проект Java Eclipse
https://www.dropbox.com/s/pay1jalcmimtfoj/VoiceTest.rar Добавлено Основная часть кода в файле VoiceVerify.java. |
Сообщ.
#14
,
|
|
|
Посмотрел я код, проблем там много, в большей части в Comirva, но проблемы могут быть решаемы:
1. MFCC почему-то иногда выдает фреймы с нулями в кепстре. Нужно разобраться откуда и по-хорошему решить эту проблему. Пока же можно их удалять: for (int z = 0; z < user2_mfcc.size(); z++) { double[] vector = user2_mfcc.get(z); if (vector[0] < 1) continue; ubm_pointList.add(vector); } 2. Пока можно нормализовать только средние, не делать нормализацию вариации. 3. Точности реализации матричных операций не хватает. Все операции нужно делать в логарифмической шкале, во многих местах идет значительная потеря точности. 4. Код по тренировке может быть таким, список точек обновляется по результатам exception, чтобы более стабильно тренировать. Тоже студент придумал такое, наверное: success = false; while (!success) { success = true; try { KMeansClustering kmeans_ubm = new KMeansClustering( GAUSSIANS_NUM, ubm_pointList, false); kmeans_ubm.run(); ubm_gmm = new GaussianMixture(kmeans_ubm.getClusterWeights(), kmeans_ubm.getMeans(), kmeans_ubm.getFullCovariances()); try { ubm_gmm.runEM(ubm_pointList); } catch (CovarianceSingularityException e) { ubm_pointList = e.getCorrectedPointList(); } } catch (Exception e) { success = false; } } Когда считается likelihood, по хорошему нужно считать в логарифмической шкале: logTotalFrameLikelihood = logadd(logTotalFrameLikelihhood, logComponentLikelihood); где logadd(x,y) = max(x,y) + log(1+e^(x-y)) Но на крайний случай можно хотя бы на 0 проверять: public double getLogLikelihood(PointList points) { double p = 0; for (int j = 0; j < points.size(); j++) { double pr = getProbability((Matrix) points.get(j)); if (pr < 1e-50) { continue; } p += Math.log(pr); } return p; } 5. Variance flooring нужно ещё делать, чтобы не было компонент с малой вариацией. Для полного счастья хорошо бы обработать напильником. |
Сообщ.
#15
,
|
|
|
nsh, большое спасибо за то, что посмотрели код!
В Comirva явно проблемы MFCC. Я переписал код для получения MFCC коэффициентов (остался тот вариант, который использовал до Comirva), сделал нормализацию MFCC по средним значениям: private void doCepstralMeanNormalization() { double sum; double mean; double mCeps[][] = new double[noOfFrames][numCepstra - 1];// same size // as mfcc // 1.loop through each mfcc coeff for (int i = 0; i < numCepstra - 1; i++) { // calculate mean sum = 0.0; for (int j = 0; j < noOfFrames; j++) { sum += mfccFeature[j][i];// ith coeff of all frame } mean = sum / noOfFrames; // subtract for (int j = 0; j < noOfFrames; j++) { mCeps[j][i] = mfccFeature[j][i] - mean; } } } Вроде начали получаться адекватные результаты, но не совсем. Максимальное число гауссианов, которое мне удалось сделать - 3. Количество кепстральных коэффициентов - 13, размер фрейма 256 (примерно 32 ms при 8 кГц). Длина аудиозаписи для 1 пользователя 50-60сек вместе с тишиной, но я удаляю тишину. Likelihood делал так: L = user1_gmm.getLogLikelihood(user1_auth1_pointList) / ubm_gmm.getLogLikelihood(user1_auth1_pointList); Значения Likelihood не сильно отличаются, особенно для тех пользователей, которых нет в UBM (user4,user5,user6,user7 - не зарегистрированные пользователи). Цитата Verify user1 LogLikelihood(user1): L=0.8249521641940379 LogLikelihood(user2): L=1.1039434059625899 LogLikelihood(user3): L=1.020745193753429 LogLikelihood(user4): L=1.0241411114917134 LogLikelihood(user5): L=1.0805579201852602 LogLikelihood(user6): L=1.0127635231868999 LogLikelihood(user7): L=1.0356999111444292 Verify user2 LogLikelihood(user1): L=1.1695328088311627 LogLikelihood(user2): L=0.8453888963858318 LogLikelihood(user3): L=0.9834534072276123 LogLikelihood(user4): L=0.8796451716059582 LogLikelihood(user5): L=0.9084670757557486 LogLikelihood(user6): L=0.9166752706497352 LogLikelihood(user7): L=0.8799651912831838 Verify user3 LogLikelihood(user1): L=1.3761136000430545 LogLikelihood(user2): L=1.2776926979500356 LogLikelihood(user3): L=1.0156711637686784 LogLikelihood(user4): L=1.1377308499139034 LogLikelihood(user5): L=1.1814099472592825 LogLikelihood(user6): L=1.1155796762381176 LogLikelihood(user7): L=1.215022606631276 А иногда получается так, что для незарегистрированного пользователя L меньше чем для зарегистрированного: Цитата Verify user3 LogLikelihood(user1): L=1.1261525431561095 LogLikelihood(user2): L=1.0537272429065274 LogLikelihood(user3): L=1.0128126733670213 - зарегистрированный LogLikelihood(user4): L=1.0930707321101896 LogLikelihood(user5): L=1.0314592923360855 LogLikelihood(user6): L=0.9491107399398667 - не зарегистрированный LogLikelihood(user7): L=1.0422861426032701 |