Pocketsphinx — совершенствование распознавания горячих слов

Недавно я повторно посетил CMU Sphinx и попытался настроить базовый детектор горячих слов для Android, начиная с учебника и адаптируя пример приложения.

У меня возникают различные проблемы, которые я не смог решить, несмотря на глубокое изучение их документации, пока не могу больше читать...

Чтобы воспроизвести их, я сделал базовый проект, предназначенный для обнаружения ключевых слов разбуди тебя и разбуди меня.

Мой словарь:

me M IY
wakeup W EY K AH P
you Y UW

Моя языковая модель:

\data\
ngram 1=5
ngram 2=5
ngram 3=4

\1-grams:
-0.9031 </s> -0.3010
-0.9031 <s> -0.2430
-1.2041 me -0.2430
-0.9031 wakeup -0.2430
-1.2041 you -0.2430

\2-grams:
-0.3010 <s> wakeup 0.0000
-0.3010 me </s> -0.3010
-0.6021 wakeup me 0.0000
-0.6021 wakeup you 0.0000
-0.3010 you </s> -0.3010

\3-grams:
-0.6021 <s> wakeup me
-0.6021 <s> wakeup you
-0.3010 wakeup me </s>
-0.3010 wakeup you </s>

\end\

Оба вышеперечисленных были созданы с помощью рекомендуемого инструмента.

И мой файл ключевых фраз:

wakeup you /1e-20/
wakeup me /1e-20/

Адаптируя приведенный выше пример приложения, вот мой код:

public class PocketSphinxActivity extends Activity implements RecognitionListener {

    private static final String CLS_NAME = PocketSphinxActivity.class.getSimpleName();

    private static final String HOTWORD_SEARCH = "hot_words";

    private volatile SpeechRecognizer recognizer;

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        setContentView(R.layout.main);

        new AsyncTask<Void, Void, Exception>() {
            @Override
            protected Exception doInBackground(Void... params) {
                Log.i(CLS_NAME, "doInBackground");

                try {

                    final File assetsDir = new Assets(PocketSphinxActivity.this).syncAssets();

                    recognizer = defaultSetup()
                            .setAcousticModel(new File(assetsDir, "en-us-ptm"))
                            .setDictionary(new File(assetsDir, "basic.dic"))
                            .setKeywordThreshold(1e-20f)
                            .setBoolean("-allphone_ci", true)
                            .setFloat("-vad_threshold", 3.0)
                            .getRecognizer();

                    recognizer.addNgramSearch(HOTWORD_SEARCH, new File(assetsDir, "basic.lm"));
                    recognizer.addKeywordSearch(HOTWORD_SEARCH, new File(assetsDir, "hotwords.txt"));
                    recognizer.addListener(PocketSphinxActivity.this);

                } catch (final IOException e) {
                    Log.e(CLS_NAME, "doInBackground IOException");
                    return e;
                }

                return null;
            }

            @Override
            protected void onPostExecute(final Exception e) {
                Log.i(CLS_NAME, "onPostExecute");

                if (e != null) {
                    e.printStackTrace();
                } else {
                    recognizer.startListening(HOTWORD_SEARCH);
                }
            }
        }.execute();
    }

    @Override
    public void onBeginningOfSpeech() {
        Log.i(CLS_NAME, "onBeginningOfSpeech");
    }

    @Override
    public void onPartialResult(final Hypothesis hypothesis) {
        Log.i(CLS_NAME, "onPartialResult");

        if (hypothesis == null)
            return;

        final String text = hypothesis.getHypstr();
        Log.i(CLS_NAME, "onPartialResult: text: " + text);

    }

    @Override
    public void onResult(final Hypothesis hypothesis) {
        // unused
        Log.i(CLS_NAME, "onResult");
    }

    @Override
    public void onEndOfSpeech() {
        // unused
        Log.i(CLS_NAME, "onEndOfSpeech");
    }


    @Override
    public void onError(final Exception e) {
        Log.e(CLS_NAME, "onError");
        e.printStackTrace();
    }

    @Override
    public void onTimeout() {
        Log.i(CLS_NAME, "onTimeout");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(CLS_NAME, "onDestroy");

        recognizer.cancel();
        recognizer.shutdown();
    }
}

Примечание. Если я изменю выбранные ключевые фразы (и другие связанные файлы), чтобы они были более непохожими, и протестирую реализацию в тихой обстановке, примененные настройки и пороговые значения будут работать очень успешно.

Проблемы

  1. Когда я говорю либо разбуди тебя, либо разбуди меня, оба будут обнаружены.

Я не могу установить, как применить повышенный вес к конечным слогам.

  1. Когда я говорю просто пробуждение, часто (но не всегда) будут обнаружены оба.

Я не могу установить, как я могу избежать этого.

  1. При тестировании на фоновом шуме ложные срабатывания слишком часты.

Я не могу понизить базовые пороги, которые я использую, иначе ключевые фразы не будут последовательно определяться в нормальных условиях.

  1. При тестировании на фоновом шуме в течение длительного периода (5 минут должно быть достаточно для воспроизведения) немедленное возвращение в тихую среду и произнесение ключевых фраз не приводит к обнаружению.

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

Я нашел потенциально связанный вопрос, но ссылки больше не работают. Интересно, не следует ли мне чаще сбрасывать распознаватель, чтобы как-то сбросить фоновый шум от усреднения в пороги обнаружения?

  1. Наконец, интересно, позволят ли мои требования к ограниченному количеству ключевых фраз уменьшить размер акустической модели?

Любые накладные расходы при упаковке в моем приложении, конечно, будут полезны.

Наконец (честно!), и особенно надеясь, что @NikolayShmyrev заметит этот вопрос, есть ли какие-либо планы по завершению базовая реализация Android / SDK полностью через gradle?

Я благодарю тех, кто зашел так далеко...


person brandall    schedule 03.09.2016    source источник


Ответы (1)


Моя языковая модель:

Вам не нужна языковая модель, так как вы ее не используете.

Я не могу понизить базовые пороги, которые я использую, иначе ключевые фразы не будут последовательно определяться в нормальных условиях.

1e-20 — разумный порог, вы можете предоставить образец записи, где у вас есть ложные обнаружения, чтобы дать мне лучшее представление о том, что происходит.

При тестировании на фоновом шуме в течение длительного периода (5 минут должно быть достаточно для воспроизведения) немедленное возвращение в тихую среду и произнесение ключевых фраз не приводит к обнаружению.

Это ожидаемое поведение. В целом, длительный фоновый шум затрудняет быструю адаптацию распознавателя к звуковым параметрам. Если ваша задача подобрать слова в шумном месте, лучше использовать какое-нибудь аппаратное шумоподавление, например, блютуз-гарнитуру с шумоподавлением.

Наконец, интересно, позволят ли мои требования к ограниченному количеству ключевых фраз уменьшить размер акустической модели?

Сейчас это невозможно. Если вы ищете только для обнаружения, вы можете попробовать https://snowboy.kitt.ai

person Nikolay Shmyrev    schedule 03.09.2016
comment
Спасибо за ответ Николай и за ссылку на снежинка. Теперь, после некоторого дальнейшего чтения, я понимаю, что LM не используется. Есть ли у вас какие-либо предложения относительно того, как я могу предотвратить обнаружение обеих ключевых фраз? Я поищу ссылку на аудиофайл, где происходят ложные срабатывания. - person brandall; 04.09.2016
comment
Сделайте ключевые фразы достаточно длинными и отчетливыми, и каждая из них будет надежно обнаружена с учетом указанного вами порога. Я не совсем понимаю ваш вариант использования, когда вы хотите использовать две похожие фразы. - person Nikolay Shmyrev; 04.09.2016
comment
Я подумал, что если бы я начал делать фразы похожими и совершенствовать систему, когда дело дошло бы до реализации реальных, более четких фраз, это было бы проще, и я был бы более осведомлен. По крайней мере, это была моя надежда! - person brandall; 04.09.2016
comment
Обнаружение всегда представляет собой трудный выбор между пользователем, говорящим немного другую фразу, или другим пользователем, говорящим ту же фразу только с акцентом. В первом случае вы не должны допускать даже незначительных изменений в акустике, во втором случае вам нужно расслабить модель, чтобы она все же восприняла фразу. Могут быть лучшие алгоритмы обнаружения, чтобы гарантировать, что все звуки ключевой фразы четко артикулированы, но это не то, что реализовано в pocketsphinx, он просто рассматривает всю фразу и пытается измерить различия. - person Nikolay Shmyrev; 05.09.2016
comment
Спасибо Николай. Последний вопрос, пожалуйста. Отменяет ли использование setKeywordThreshold(1e-20f) какие-либо пороговые значения, которые могут быть установлены выше в файле ключевых слов? - person brandall; 05.09.2016
comment
Нет, пороговые значения в файле имеют приоритет над глобальным пороговым значением - person Nikolay Shmyrev; 05.09.2016