Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite of vocabcompiler #181

Merged
merged 28 commits into from
Oct 13, 2014

Conversation

Holzhaus
Copy link
Member

EDIT: Just scroll down to this comment to see what this PR does. No need to read the whole conversation.

  • Separated generic code from pocketsphinx logic
  • Using OOP so that code can be reused for other STT engines, too
  • The pocketsphinx part of vocabcompiler now uses the cmuclmtk wrapper libary for compilation of the languagemodel/dictionary.
  • A revision check has been implemented, so that vocabulary won't get recompiled if there's no need.
  • Proper integration into jasper.py, client/stt.py and client/test.py is still missing due to pending pull requests that change these modules.

Please have a look and execute this module directly:

$ JASPER_HOME=~/Projekte python2 client/vocabcompiler.py --base-dir=/tmp 
Module phrases:    ['BIRTHDAY', 'EMAIL', 'FACEBOOK', 'FIRST', 'HACKER', 'INBOX', 'JOKE', 'KNOCK KNOCK', 'LIFE', 'MEANING', 'MUSIC', 'NEWS', 'NO', 'NOTIFICATION', 'OF', 'SECOND', 'SPOTIFY', 'THIRD', 'TIME', 'TODAY', 'TOMORROW', 'WEATHER', 'YES']
Vocabulary in:     /tmp/pocketsphinx-vocabulary/default
Revision file:     /tmp/pocketsphinx-vocabulary/default/revision
Compiled revision: None
Is compiled:       False
Matches phrases:   False
Compiling...
<snip>
idngram2lm : Done.

Vocabulary in:     /tmp/pocketsphinx-vocabulary/default
Revision file:     /tmp/pocketsphinx-vocabulary/default/revision
Compiled revision: 8c0e66f387b7177205726ecfcb3edd9df0d23653
Is compiled:       True
Matches phrases:   True

$ JASPER_HOME=~/Projekte python2 client/vocabcompiler.py --base-dir=/tmp
Module phrases:    ['BIRTHDAY', 'EMAIL', 'FACEBOOK', 'FIRST', 'HACKER', 'INBOX', 'JOKE', 'KNOCK KNOCK', 'LIFE', 'MEANING', 'MUSIC', 'NEWS', 'NO', 'NOTIFICATION', 'OF', 'SECOND', 'SPOTIFY', 'THIRD', 'TIME', 'TODAY', 'TOMORROW', 'WEATHER', 'YES']
Vocabulary in:     /tmp/pocketsphinx-vocabulary/default
Revision file:     /tmp/pocketsphinx-vocabulary/default/revision
Compiled revision: 8c0e66f387b7177205726ecfcb3edd9df0d23653
Is compiled:       True
Matches phrases:   True

As you can see, the instance detects that has already been compiled and that it's still up-to-date, so that recompilation is not neccessary and therefore skipped.

@Holzhaus
Copy link
Member Author

For the unittest section, i'll implementiert a dummy subclass.

I guess __init__() and compile() should happen inside the __init__() (or get_config()) method of the according STT engine.

@Holzhaus
Copy link
Member Author

The prevents unneccessary vocabulary recompilation and therefore saves CPU time and SD card write cycles, therefore I guess this can be considered kind of urgent.

I'd like to start to integrate this as soon as #176 is merged.

@Holzhaus
Copy link
Member Author

I rebased to include the changes from PR #197.


vocab = vocabcompiler.DummyVocabulary(path=tempdir)
self.assertTrue(vocab.compiled_revision is None)
self.assertTrue(not vocab.is_compiled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertFalse

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@Holzhaus
Copy link
Member Author

Bonus: the python cmuclmtk library won't clutter our screen with output messages we don't want to see. You can see the difference, when you call python2 client/vocabcompiler.py and python2 client/vocabcompiler.py --debug.

@Holzhaus
Copy link
Member Author

Rebased to upstream/master.

@Holzhaus
Copy link
Member Author

The vocabcompiler should now be working, but still needs testing.

cmd_exists = shutil.which
# Required binary for this class
cmd = 'phonetisaurus-g2p'
if not cmd_exists(cmd):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be if cmd_exists(cmd), I think

@charliermarsh
Copy link

Haven't read through it all, but my tests are failing. I think the TestG2P tests need to be refactored to use OOO.

@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 1, 2014

In case we merge PR #209, I'd like to change this (or create a follow-up PR to this one):

If you look at jasper.py and client/mic.py, we're using the Mic class like this:

class Mic:
    def__init__(self, speaker, passive_stt_engine, active_stt_engine):

So we pass in two different STT Engine instances:

  1. An STT Engine instance for passive listen
  2. An STT Engine Instance for active listen

But PocketsphinxSTT takes up to 3 lm/dict pairs:

  1. A pair for passive listen
  2. A pair for active listen
    3 A pair for active listen (musicmode)

This is a lot duplication, because in jasper.py, we're creating two separate SST Engine Instances for active listen and passive listen, so that the active listen STT Engine instance will only use the second lm/dict pair and the passive listen STT instance will only use the first pair.
In MusicMode, a third STT instance will be created that only uses the third pair.

Given the case that someone wants to write a new module that also has the ability to start a mode like the MusicMode, he'd either have to hijack the music lm/dict pair, or he'd need to add a new mode to STT Engines and change the PocketsphinxSTTEngine code.

Thus, I'd like to simplify the STT engine dramatically by removing two of the three dict pairs (or rather Vocabulary Instances) from the PocketsphinxSTT engine and the mode parameter in transcribe accordingly, so that you simply do this:

# This is just for demonstration purposes (not the actual code)
# normal operation
passive_vocabulary = PocketsphinxVocabulary(name='keyword')
passive_vocabulary.compile(vocabcompiler.get_keyword_phrases())
passive_stt_engine = PocketsphinxSTT(passive_vocabulary)

active_vocabulary = PocketsphinxVocabulary(name='default')
active_vocabulary.compile(vocabcompiler.get_all_phrases())
active_stt_engine = PocketsphinxSTT(active_vocabulary)

mic = Mic(speaker, passive_stt_engine, active_stt_engine)

# now let's create a new mode in a module
plugin_name = "mpdcontrol"
plugin_phrases = ['PLAY', 'PAUSE', 'STOP', ...]

music_vocabulary = PocketsphinxVocabulary(name=plugin_name)
music_vocabulary.compile(phrases)
music_stt_engine = PocketsphinxSTT(music_vocabulary)
mic = Mic(speaker, passive_stt_engine, music_stt_engine)

@crm416 What do you think?

@Holzhaus Holzhaus force-pushed the vocabcompiler-abstraction branch 2 times, most recently from 2cb471a to 0fdb9a9 Compare October 3, 2014 12:43
@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 3, 2014

OK, I rebased to fix merge conflicts with PR #209. G2P testcases are now fixed, so that they should be a.... pronounced success ;-) *_ba dum tss_* Additionally, I made some style fixes.

Please test. My suggestion (above) will be part of a future pull request.

@Holzhaus Holzhaus force-pushed the vocabcompiler-abstraction branch 2 times, most recently from aecdb48 to a81f889 Compare October 6, 2014 15:59
@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 6, 2014

Anyone willing to test this?

@Holzhaus Holzhaus force-pushed the vocabcompiler-abstraction branch 2 times, most recently from fa9d821 to 9616b1b Compare October 8, 2014 11:04
@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 8, 2014

Rebased to lastest upstream/master.

@coveralls
Copy link

Coverage Status

Coverage increased (+9.09%) when pulling bd9e667 on Holzhaus:vocabcompiler-abstraction into ea91735 on jasperproject:master.

@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 8, 2014

Just an update on what this PR does:

  • makes recompilation of a vocabulary unneccessary if phrases didn't change
  • therefore saves CPU time and SD card write cycles
  • combines lm/dict arguments for PocketsphinxSTT
  • creates an abstract vocabulary class, so that new vocabulary types (e.g. HTK/Julius or the like) can be implemented easily will full revision/recompilation and error handling support
  • hides unwanted CMUCLMTK output from the user (unless the loglevel is set to DEBUG)
  • uses tempfiles for compilation and thus fixes Why must everything be world writeable? #119 (world writable app dir)
  • improves phonetisaurus-g2p wrapper code
  • adds support for Phonetisaurus-G2P's nbest argument via profile.yml
  • raises overall unittest coverage by over 9%
  • raises vocabcompiler.py unittest coverage to 100%
  • have I forgotten something?

IMO, we're ready for merging, but I'd like someone else to test this. Please.

@Holzhaus
Copy link
Member Author

Holzhaus commented Oct 9, 2014

@crm416 @shbhrsaha Can you please test this?

@shbhrsaha
Copy link
Member

Sure I'll test it this weekend and report back!

Shubhro

On Wed, Oct 8, 2014 at 9:13 PM, Jan Holthuis [email protected]
wrote:

@crm416 @shbhrsaha Can you please test this?

Reply to this email directly or view it on GitHub:
#181 (comment)

@Holzhaus
Copy link
Member Author

Thanks!

@shbhrsaha
Copy link
Member

LGTM. Slick feature, well done!

Holzhaus added a commit that referenced this pull request Oct 13, 2014
@Holzhaus Holzhaus merged commit f1ffdd7 into jasperproject:master Oct 13, 2014
@Holzhaus Holzhaus deleted the vocabcompiler-abstraction branch October 13, 2014 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants