Автор работы: Пользователь скрыл имя, 11 Октября 2013 в 17:10, курсовая работа
Также стоит отметить статью Мел-кепстральные коэффициенты (MFCC) и распознавание речи и выполненную на её основе работу по идентификации человека по голосу: Кто там? — Идентификация человека по голосу.
В данной работе предлагается простой алгоритм (и его реализация на C++) системы распознавания речи по короткому словарю, основанный на анализе статистического распределения мел-кепстральных коэффициентов (Mel-frequency cepstrum coefficients, MFCC).
Существуют множество методов
распознавания речи, в подавляющем
большинстве случаев они
Итак, для распознавания речи будем
использовать MFCC. Чтобы не вдаваться
в подробности скажу, что относиться
к ним стоит лишь как к некоторому
фильтру, на входе которого — фонограмма, на выходе — набор векторов
(коэффициенты), который мы и будем распознавать
как некоторое слово или набор слов. Справедливости
ради стоит отметить, что существуют множество
других акустических признаков, использующихся
для распознавания речи: Perceptual linear predictive
(PLP), Linear prediction cepstral coefficient (LPCC), Linear frequency
cepstral coefficients (LFCC).
Основная идея заключается в использовании линейного дискриминантного
анализа для идентификации слова. Однако, он применим
лишь для векторов одинаковой размерности.
Т.к. слова могут быть различной длины,
возникает вопрос: каким образом преобразовать
последовательность произвольного числа
MFCC-векторов в вектор фиксированной размерности?
Можно поступить следующим образом: находить
места «сгущения» распределения этих
векторов и в качества результирующего
вектора брать конкатенацию векторов,
являющихся центрами «сгущений». Такой
конкатенированный вектор будем называть
супервектором средних, а сами центры
— средними значениями. При этом в качестве
«отправной точки» будем использовать
супервектор средних, полученный на всех
MFCC-векторах всей базы обучения. Преобразовав
таким образом последовательность MFCC-векторов
в один супервектор средних фиксированной
размерности, мы можем применять различные
методы классификации.
Очевиден принципиальный недостаток такого
подхода: не учитывается динамика распределения
MFCC-признаков по времени, следовательно,
система априори не способна различать,
к примеру, слова «главрыба» и «абырвалг»,
т.к. общее распределение MFCC-векторов таких
слов будет примерно одинаковым (соответственно,
центры «сгущений» будут совпадать).
В качестве базы обучения будем использовать множество файлов, каждый из которых
представляет собой набор MFCC-векторов,
полученных из фонограммы с записью того
или иного слова. При этом файлы с записью
одного и того же слова должны быть объединены
в одну группу.
Вот как выглядит распределение первых
двух компонент MFCC-векторов всей базы
обучения:
Алгоритм состоит из следующих этапов:
Создание собственной системы
распознавания слов состоит из следующих
этапов:
В качестве эксперимента я создал систему,
которая умеет распознавать 14 слов,
записанных моим голосом. Для обучения
системы я записал каждое слово
4-5 раз, а для тестирования — 7 раз. Итого база обучения
содержит 63 файла, а база тестирования
— 98. Использовались следующие параметры
при обучении:
Результат тестирования на базе обучения
показал уровень ошибки распознавания
слов (WER) 1,6%, а на базе тестирования
5,1%.
Хотелось бы сказать несколько замечаний. Во-первых, для того, чтобы
любая система (включая описанную здесь)
могла качественно распознавать речь
любого человека, необходимо иметь огромную
базу обучения с записью всех слов, произнесенных
разными людьми в разном эмоциональном
состоянии с использованием различных
записывающих устройств (телефон, микрофон,
подслушивающее устройство и т.п.). Т.е.
система, которую вы обучите, используя
только свой голос и только вашу домашнюю
гарнитуру, наверняка не будет работать
для ваших знакомых и даже для вас, если
вы будете использовать какой-нибудь другой
микрофон. Во-вторых, описанная система
имеет сильно ограниченный потенциал
в силу своей тривиальности. Не смотря
на то, что она работает, данный подход
был предложен только в качестве эксперимента
и не подходит для промышленного использования
без каких-либо доработок.
#include "WordRecognizer.h"
#include <exception>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <float.h>
#include <math.h>
using namespace std;
using namespace WordRecognizer;
//! Реализация интерфейса IVectorsSet с хранением всех данных в оперативной памяти
class MemoryVectorsSet : public IVectorsSet
{
private:
vector<vector<float> > m_data;
int m_dim;
public:
MemoryVectorsSet() : m_dim(0)
{
}
void SetDim(const int &_dim)
{
if (_dim < 0)
throw exception("MemoryVectorsSet::
m_dim = _dim;
}
const int GetDim() const
{
return m_dim;
}
void SetSize(const int &_size)
{
if (_size < 0)
throw exception("MemoryVectorsSet::
m_data.resize(_size);
}
const int GetSize() const
{
return (const int)m_data.size();
}
void SetVectorsNum(const int &_indx, const int &_vectorsNum)
{
if (_indx >= GetSize())
throw exception("MemoryVectorsSet::
if (m_dim <= 0)
throw exception("MemoryVectorsSet::
m_data[_indx].resize(_
memset(&m_data[_indx][0], 0, sizeof(float) * _vectorsNum * m_dim);
}
void GetVectors(
const int &_indx,
int &_vectorsNum,
const float* &_vectors) const
{
if (_indx >= GetSize())
throw exception("MemoryVectorsSet::
if (m_dim <= 0)
throw exception("MemoryVectorsSet::
_vectorsNum = (int)m_data[_indx].size() / m_dim;
_vectors = (_vectorsNum > 0) ? &m_data[_indx][0] : NULL;
}
void GetVectors(
const int &_indx,
int &_vectorsNum,
float* &_vectors)
{
const float* pVectors;
GetVectors(_indx, _vectorsNum, pVectors);
_vectors = const_cast<float*>(pVectors);
}
};
//! Класс-оболочка для упрощения
работы с системой
class WordRecognizerWrapper
{
public:
vector<vector<string> > m_files;
vector<string> m_wordsBase;
MemoryVectorsSet m_mfcc;
int m_dim;
int meansNum;
vector<float> m_means;
float m_adaptWeight;
MemoryVectorsSet m_adaptMeans;
int m_LDASize;
vector<float> m_LDAMatrix;
vector<float> m_mean;
MemoryVectorsSet m_projections;
vector<string> m_learnWords;
vector<float> m_wordsMean;
vector<float> m_wordsSigma;
bool m_baseOK;
bool m_meansOK;
bool m_adaptMeansOK;
bool m_LDAOK;
bool m_projectionsOK;
bool m_compareSystemOK;
public:
WordRecognizerWrapper() : m_baseOK(false), m_meansOK(false), m_adaptMeansOK(false), m_LDAOK(false),
m_projectionsOK(false), m_compareSystemOK(false), meansNum(0), m_adaptWeight(50.), m_LDASize(0)
{
}
~WordRecognizerWrapper()
{
}
void LoadBase(const char* _baseFile)
{
string fileName(_baseFile);
string path = fileName.substr(0, fileName.find_last_of("/\\"));
path += "/";
ifstream baseInfo(_baseFile);
if (!baseInfo.is_open())
throw exception("can't open base file");
const int maxStr = 5000;
char tmpStr[maxStr];
int wordsNum = 0;
baseInfo.getline(tmpStr, maxStr);
wordsNum = atoi(tmpStr);
if (wordsNum <= 0)
throw exception("words num <= 0");
m_wordsBase.resize(wordsNum);
m_files.resize(wordsNum);
int filesNum = 0;
int filesCount = 0;
for (int i = 0; i < wordsNum; i++)
{
baseInfo.getline(tmpStr, maxStr);
m_wordsBase[i] = tmpStr;
if (m_wordsBase[i].length() == 0)
ThrowFormatException("word[%d] name length == 0", i);
baseInfo.getline(tmpStr, maxStr);
filesNum = atoi(tmpStr);
if (filesNum <= 0)
ThrowFormatException("files num for word %s <= 0", m_wordsBase[i].c_str());
m_files[i].resize(filesNum);
filesCount += filesNum;
for (int j = 0; j < filesNum; j++)
{
if (baseInfo.eof())
ThrowFormatException("
baseInfo.getline(tmpStr, maxStr);
m_files[i][j] = tmpStr;
if (m_files[i][j].length() == 0)
ThrowFormatException("file name [%d] length for word %s == 0", j, m_wordsBase[i].c_str());
}
}
baseInfo.close();
m_mfcc.SetSize(filesCount);
filesCount = 0;
for (int i = 0; i < wordsNum; i++)
{
for (size_t j = 0; j < m_files[i].size(); j++)
{
ifstream fileMFCC((path + m_files[i][j]).c_str(), ios_base::in | ios_base::binary);
if (!fileMFCC.is_open())
ThrowFormatException("can't open file %s", (path + m_files[i][j]).c_str());
// Read SPRO file
unsigned short dim = 0;
long flag = 0;
float freq = 0;
fileMFCC.seekg(0, ios_base::end);
size_t fileSize = (size_t)fileMFCC.tellg();
fileMFCC.seekg(0, ios_base::beg);
if (fileSize < 10)
ThrowFormatException("can't read file %s", (path + m_files[i][j]).c_str());
fileMFCC.read((char*)&dim, sizeof(dim));
fileMFCC.read((char*)&flag, sizeof(flag));