February 14, 2013

Quick note on installing lightspeed.

If you're trying to install Tom Minka's lightspeed library for matlab, on a mac machine, you may have bumped into this error:
Compiling lightspeed 2.6 mex files...
Change directory to lightspeed for this to work.
util.c:32:1: warning: "INFINITY" redefined
In file included from /usr/include/math.h:28,
                 from util.c:6:
/usr/include/architecture/i386/math.h:76:1: warning: this is the location of the previous definition
util.c:33:1: warning: "NAN" redefined
/usr/include/architecture/i386/math.h:66:1: warning: this is the location of the previous definition
mex -largeArrayDims  -DBLAS64 -DUNDERSCORE_LAPACK_CALL solve_triu.c "-lmwlapack" "-lmwblas"
llvm-gcc-4.2 -c  -I/Applications/MATLAB_R2011b.app/extern/include -I/Applications/MATLAB_R2011b.app/simulink/include -DMATLAB_MEX_FILE -fno-common -no-cpp-precomp -arch x86_64  -fexceptions  -DMX_COMPAT_32 -O2 -DNDEBUG -c random.c; llvm-gcc-4.2 -c  -I/Applications/MATLAB_R2011b.app/extern/include -I/Applications/MATLAB_R2011b.app/simulink/include -DMATLAB_MEX_FILE -fno-common -no-cpp-precomp -arch x86_64  -fexceptions  -DMX_COMPAT_32 -dynamiclib -Wl,-install_name,`pwd`/librandom.dylib -o librandom.dylib random.o
i686-apple-darwin11-llvm-gcc-4.2: -install_name: linker input file unused because linking not done
i686-apple-darwin11-llvm-gcc-4.2: /Users/Tomer/Research/Common/lightspeed/librandom.dylib: linker input file unused because linking not done
i686-apple-darwin11-llvm-gcc-4.2: random.o: linker input file unused because linking not done

ans =

     0

i686-apple-darwin11-llvm-gcc-4.2: librandom.dylib: No such file or directory

    mex: link of ' "randomseed.mexmaci64"' failed.
To solve this, note the comment in 'install_lightspeed.m'
% tis installer is set up for 64-bit MacOSX 10.6 with gcc-4.0
% if you are using something else, run 'mex -v -c flops.c'
% and use the output to change these strings
which, for me outputs
llvm-gcc-4.2 -c  -I/Applications/MATLAB_R2011b.app/extern/include -I/Applications/MATLAB_R2011b.app/simulink/include -DMATLAB_MEX_FILE -fno-common -no-cpp-precomp -arch x86_64  -fexceptions  -DMX_COMPAT_32 -O2 -DNDEBUG  "flops.c"
However, even after changing the appropriate variables, I still got an error (the one above), To fix it, I simply removed that first '-c' flag, which results in the following settings:
options.COMPILER = 'llvm-gcc-4.2';
options.COMPFLAGS = ' -I/Applications/MATLAB_R2011b.app/extern/include -I/Applications/MATLAB_R2011b.app/simulink/include -DMATLAB_MEX_FILE -fno-common -no-cpp-precomp -arch x86_64  -fexceptions  -DMX_COMPAT_32';
options.OPTIMFLAGS = '-O2 -DNDEBUG';

December 06, 2012

Python and Multi-threadining

As a final project in one of the courses I'm taking, I proposed to implement a parallel optimization algorithm for the LASSO problem, in Python (see details in this paper and C implementation here). I immediately ruled out Matlab, my preferred weapon of choice for numerical optimization, since Its parallel computation toolbox is not free. After that, it was either Perl (which I know and love) or Python (which I practically knew nothing about).

The trouble is that lack of knowledge leads to really poor decision making. Naive as I was, I assumed that a language glorified by the open source community, known to be widely used in Google, and has been around for more than 20 years will, well basically support everything you think it should, and in a way any experienced developer will be able to anticipate before hand.

Well. The situation is a bit more complex than that: (/rant)

Here are some quick lessons I learned about Python and *multi-threading*:
  1. Python has several implementation (in C, in Java, in Python, in .Net…)
  2. The most common, widely used implementation is the C version, called CPython. It DOES NOT support threads in an expected manner - The GIL component (Global Interpreter Lock, satan take his soul) actually makes all the threads compete on a *single* core, even if your system has multiple cores. This means python threads do not run in parallel. They run one at a time (interleaved).
  3. Some of the non-C implementations for python do claim to support threading properly.
I tested (3) on jython and pypy (see code below).
Jython worked okay (however, acceleration scaled poorly on my mac).
pypy - I still don't understand if they claim to support threads properly or not. Practicaly it doesn't work (tested w/ pypy-1.9).

Unfortunately, the non-C implementations may not support external libraries (such as Numpy), so if you need real parallel computation with CPython, you should use the multiprocessing library.
Unfortunately++, in this case you have to manage the shared memory by yourself.
(To contrast with threads, in most programming languages, threads can easily access shared variables with almost not syntactic effort on the developers behalf. Processes however, are a different breed. They were designed to be memory disjoint, and when shared memory is required, some other explicit mechanism is used.)

My next planned post is about Python + multiprocessing + shared memory + numpy, where I hope to release a small library that encapsulates the basic requirements.
In the meantime, you can read the following:
  • Impressive and professionally written post on multiprocessing.
  • stackexchange discussion on numpy + shared memory
My code will be based on both.
-- Tomer


Other References
* A good overview of threading in python can be found here.

* Python code I used to measure thread performance (based on this):
#!/usr/bin/python
import threading
import sys
import time

class myThread (threading.Thread):
    def __init__(self, threadID, name, P, MAX, lock):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.MAX = MAX
        self.lock = lock
        self.P = P
    
    def run(self):
        global A
        for i in range(self.MAX):
            # do some work
            for j in range(1000):
                s = j
            k = (self.threadID+i) % self.P
            # REMOVE ME if you want counter locking
            #            with self.lock[k]:
            A[k] = A[k] + 1;

def runParallel(P,N):
    # distribute N to P 
    global A
    A = [0 for i in range(P)]; # zeros(P,1)
    lock = [threading.Lock() for i in range(P)]
    threads = []
    t = time.time()
    for p in range(0,P):
        thread = myThread(p, "Thread-"+str(p), P, N/P, lock)
        thread.start()
        threads.append(thread)

    for p in threads:
        p.join()
    elapsed = time.time() - t
    print 'time for', P, ':', elapsed

    print A[:]
    return elapsed

if __name__ == '__main__':
    global A
    N = int(sys.argv[1]) # counter
    e1 = runParallel(1,N)*1.0
    e2 = runParallel(2,N)
    e4 = runParallel(4,N)
    e8 = runParallel(8,N)
    print 'time:', e1, e2, e4, e8
    print 'efficiency:', e1/(e1), e1/(2*e2), e1/(4*e4), e1/(8*e8)

May 30, 2012

HTK Tutorial microblogging May 27.


In the microblog below I recorded my efforts to implement the first tutorial from the HTK book.
A word of caution:
In no way is this a complete account of the whole process,
or should this entry be regarded as a tutorial (as you will see soon enough)
My general impression is that it is very hard to go through the HTK tutorial without some external help.
A good reference tutorial can be found here
but maybe someone out there will find this useful too.

Also note that my timestamps below shouldn't be taken seriously.
This was done over the weekend, along with other things.
-- Tomer

General configuration:
I installed HTK 3.4.1 on windows+cygwin.
cygwin should be installed with perl as well as have the sox application
(used to concat wav files together)

Speech recognition settings:
I wanted to avoid recording.
Therefore, I used only a pre-recorded set of digits
available here
I used only the non-raw version.

For training and test data I therefore have 2x5x11 samples:
That is, five recordings per digit and 11 different utterances since zero is encoded by both "zero" and "oh".

I set up a very simple grammar:
Initially, a user can either say "0" or "1".
Subsequently,
"0" can be followed by a seq' of even numbers (e.g., 02824)
"1" can be followed by a seq' of odd numbers (e.g., 1775)


-- Start of microblog.

4:04pm:
Step 1 - the task grammar.

$even = TWO | FOUR | SIX | EIGHT | OH | ZERO;
$odd = ONE | THREE | FIVE | SEVEN | NINE;
( SENT-START ( (ZERO|OH) <$even> | ONE <$odd>) SENT-END )


4:16pm: HParse passes on first run,

4:24pm: Step 2 - the dictionary
created the file 'wlist' using 'prompt2wlist' perl script.

4:56pm:
Downloaded 'beep' dictionary here.
Unfortunetly, It isn't well sorted.
Moreover, sorting it according to unix/perl/python sort does not seem to help (maybe it does on non-cygwin system?)

5:14pm:
To overcome this problem, I wrote a script 'reduce.pl' that reduces a dictionary only to the given wlist.
The script can be found here, among other scripts I wrote in this session.

perl -w reduce.pl wlist beep-1.0 > beep.reduced.


I then added the recommended 'global.ded' in the same folder:
AS sp
RS cmu
MP sil sil sp


We obtain the file 'dict' (where "SENT-XXXX [] .." were *manually* added.")

EIGHT ey t sp
FIVE f ay v sp
FOUR f ao sp
FOUR f ao r sp
NINE n ay n sp
OH ow sp
ONE w ah n sp
SENT-END [] sil
SENT-START [] sil
SEVEN s eh v n sp
SIX s ih k s sp
THREE th r iy sp
TWO t uw sp
ZERO z ia r ow sp


5:27pm Step 3:
Previous experience shows that HSLab is not a very stable tool.
For example, it kept getting stuck after manual saving of marked and labeled files.
Fortunately, no labeling with HSLab is required here.

Two sets of sentences were created using HSGen.exe:

HSGen.exe -l -n 100 wdnet dict > trainprompts

HSGen.exe -l -n 100 wdnet dict > testprompts


Note that the digits prefixing every line should be changed to something like
"/*S00\d+" such that the output would look like:

*/S00099 ONE ONE NINE THREE THREE FIVE ONE FIVE ONE FIVE
*/S00100 OH EIGHT SIX FOUR EIGHT SIX SIX

5:37pm Step 4:
Generating the HTK label format file (mlf) for the training and test data:
perl -w ../../samples/HTKTutorial/prompts2mlf trainmlf trainprompts

perl -w ../../samples/HTKTutorial/prompts2mlf testmlf testprompts


5:45pm
The files 'mkphones0.led' was created (note the newline is required at the last line)
EX
IS sil sil
DE sp



as well as 'mkphones1.led':

EX
IS sil sil



Notice that there's no delete "sp" in the second .led file - this results in words being separated by 'sp':
for example: ('086')
sil ow sp ey t sp s ih k s sp

The following commands were run:
HLEd -l '*' -d dict -i phones0.mlf mkphones0.led trainmlf

HLEd -l '*' -d dict -i phones1.mlf mkphones1.led trainmlf


5:46: Validating that 'sil' was added at the start and end of every utterance.

5:47: step 5
...
I don't really plan on recording 100 sentences (corresponding the the HGen generated prompts)
Instead, I'm going to concat the single digit files according to the generated prompts
For each digit, I have 5 training recordings and 5 testing recordings.
the train prompts will be composed by concating the training recording,
and separately for the test prompts.

6:51 Done writing the digit-wav-concating script! available here,
The commmand
perl -w concatprompt.pl ../../def/trainprompts > codetrain.scp

generates two outputs:
1. the 'codetrain.scp' file with content
S00001.wav S00001.mfc
S00002.wav S00002.mfc
...


2. The 'SXXXX.wav' files - by concating the single digit wav files according to the prompt.
concating was done using the command 'sox' (was already installed on my cygwin).

Now I'm ready to run:
HCopy -T 1 -C configtrain -S codetrain.scp

which obviously fails, spewing:

ERROR [+6310] OpenParmChannel: cannot open Parm File reading
ERROR [+6313] OpenAsChannel: OpenParmChannel failed
ERROR [+6316] OpenBuffer: OpenAsChannel failed
ERROR [+1050] OpenParmFile: Config parameters invalid
FATAL ERROR - Terminating program HCopy


The problem seemed to be a missing 'SOURCEFORMAT' command in 'configtrain' suggest by the HTKBook (thank you internet forums).
So, my 'configtrain' now looks like this:
# Coding parameters
TARGETKIND = MFCC_0
TARGETRATE = 100000.0
SOURCEFORMAT = WAV
SAVECOMPRESSED = T
SAVEWITHCRC = T
WINDOWSIZE = 250000.0
USEHAMMING = T
PREEMCOEF = 0.97
NUMCHANS = 26
CEPLIFTER = 22
NUMCEPS = 12
ENORMALISE = F


and my 'configtest' now looks like this (the only difference is in TARGETKIND)
# Coding parameters
TARGETKIND = MFCC_0_D_A
TARGETRATE = 100000.0
SOURCEFORMAT = WAV
SAVECOMPRESSED = T
SAVEWITHCRC = T
WINDOWSIZE = 250000.0
USEHAMMING = T
PREEMCOEF = 0.97
NUMCHANS = 26
CEPLIFTER = 22
NUMCEPS = 12
ENORMALISE = F


7:22pm stop.
12:46am - step 6:

Running:
HCompV -C configtrain2 -f 0.01 -m -S trainmfc.scp -M hmm0 proto


Here the files:
1. 'trainmfc.scp' contains the .mfc files (one per line)
2. 'proto' is
~o <VecSize> 39 <MFCC_0_D_A>
~h "proto"
<BeginHMM>
<NumStates> 5
<State> 2
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0
<State> 3
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0
<State> 4
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0. 0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1. 0
<TransP> 5
0.0 1.0 0.0 0.0 0.0
0.0 0.6 0.4 0.0 0.0
0.0 0.0 0.6 0.4 0.0
0.0 0.0 0.0 0.7 0.3
0.0 0.0 0.0 0.0 0.0
<EndHMM>


3. 'configtrain2' is a modified version of 'configtrain' with
(a) the 'SOURCEFORMAT = WAV' removed (since we're using mfc files)
and (b) TARGETKIND = MFCC_0_D_A - matching the 'proto' first line, otherwise you get an error like
[+2050] CheckData: Parameterisation in S00001.mfc is incompatible with


1:29am - successful run.


instead of manually copying and pasting for each monophone, I use a script:
'monophone2hmmdef.pl' which takes a list of monophones and a proto file and outputs an hmmdefs file.
as instructed here
(for the script, see here).

The command line I use is:
perl -w monophone2hmmdef.pl hmm0/proto ../../def/monophones0 > hmmdefs

where 'monophones0' is 'monophones1' without the phone 'sp'.

1:48am: creating the macros file: (as specified by the same voxforge link above):
the resulting file is:
~o
<STREAMINFO> 1 39
<VECSIZE> 39<NULLD><MFCC_D_A_0><DIAGC>
~v varFloor1
<Variance> 39
9.718211e-01 9.532348e-01 8.965245e-01 1.231103e+00 1.152173e+00 7.287015e-01 6.180173e-01 3.474550e-01 5.032213e-01 5.217451e-01 3.275607e-01 4.168463e-01 9.035664e-01 2.967923e-02 2.530965e-02 2.388922e-02 4.786262e-02 3.260848e-02 3.308474e-02 3.244526e-02 2.310554e-02 2.778173e-02 2.565148e-02 2.570237e-02 2.567602e-02 3.337039e-02 3.829589e-03 3.403592e-03 3.239712e-03 6.049931e-03 4.571099e-03 5.151636e-03 5.374793e-03 3.918502e-03 4.568941e-03 4.490597e-03 4.577133e-03 4.227266e-03 4.098070e-03


To re-estimate, create the folder 'hmm1' and run
HERest -C configtrain2 -I ../../def/phones0.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm0/macros -H hmm0/hmmdefs -M hmm1 ../../def/monophones0


which outputs:
ERROR [+7321] CreateInsts: Unknown label sil


So, I manually added the 'sil' monophone to 'hmmdefs' and to 'monophones0'
(I could have just added it to monophones0 and regenerate hmmdefs..).

2:28am: that's it for today. messy!
=======
4:50pm
finishing step 6 - need to repeat 2 runs of HERest.
HERest -C configtrain2 -I ../../def/phones0.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm1/macros -H hmm1/hmmdefs -M hmm2 ../../def/monophones0

HERest -C configtrain2 -I ../../def/phones0.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm2/macros -H hmm2/hmmdefs -M hmm3 ../../def/monophones0

4:57pm done.

Step 7: Fixing the Silence Models
The description is indeed a bit cryptic here.
Here, 'fixing the silence model' means that we will copy the content of hmm3 to hmm4 and modify 'hmm4/hmmdefs' a bit.
the modifications will tie 'sp' to the center state of the 'sil' model.
that is, they will share the same HMM parameters.

The following describes what exactly is needed to be done.
http://www.voxforge.org/home/dev/acousticmodels/linux/create/htkjulius/tutorial/monophones/step-7

Note: At this point I started following the above tutorial as much as I could.
Below I record mainly the commands that I ran and some tricks,
Many problems were solved by looking over the user comments in each step, or just searching the error number HTK outputs.
...

After using a text editor as required, I run:
HHEd -A -D -T 1 -H hmm4/macros -H hmm4/hmmdefs -M hmm5 sil.hed ../../def/monophones1


Note that 'monophones1' contains 'sp'.

I got this error message:
WARNING [-2631] EditTransMat: No trans mats to edit! in HHEd


Afterwhich I noticed that my 'monophones1' doesn't have a 'sil' monophone. so I manually added it.
This seemed to resolve the problem.

5:35pm
Now two more re-estimations are done, using 'monophones1'

Running:
HERest -C configtrain2 -I ../../def/phones0.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm5/macros -H hmm5/hmmdefs -M hmm6 ../../def/monophones1


fails with:
WARNING [-2331] UpdateModels: sp[19] copied: only 0 egs


The reason is that we should use 'phones1.mlf'.
After correcting, the following two commands were executed:

HERest -C configtrain2 -I ../../def/phones1.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm5/macros -H hmm5/hmmdefs -M hmm6 ../../def/monophones1

HERest -C configtrain2 -I ../../def/phones1.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm6/macros -H hmm6/hmmdefs -M hmm7 ../../def/monophones1


5:49pm: Step 8 - Realigning the Training Data.
Note: How anyone can successfully follow the HTK tutorial without external help is beyond me at this stage.
Sorry.

Running:
HVite -A -D -T 1 -l '*' -o SWT -b SENT-END -C configtrain2 -H hmm7/macros -H hmm7/hmmdefs -i aligned.mlf -m -t 250.0 150.0 1000.0 -y lab -a -I ../../def/trainmlf -S trainmfc.scp ../../def/dict ../../def/monophones1 > HVite_log


Which outputs the file 'aligned.mlf'.
This command is somewhat different than the one suggested by the HTK book and was taken from here
This step is actually redundant considering that my dictionary has a single pronounciation per word.
Nevertheless, for the sake of completeness (and who knows what else will follow)...

HERest -C configtrain2 -I ../../def/phones1.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm7/macros -H hmm7/hmmdefs -M hmm8 ../../def/monophones1

HERest -C configtrain2 -I ../../def/phones1.mlf -t 250.0 150.0 1000.0 -S trainmfc.scp -H hmm8/macros -H hmm8/hmmdefs -M hmm9 ../../def/monophones1


6:31pm: Step 9 - Making Triphones from Monophones

the file 'mktri.led' was created
WB sp
WB sil
TC



and the following command was executed:
HLEd -A -D -T 1 -n triphones1 -l '*' -i wintri.mlf ../../def/mktri.led aligned.mlf


'triphones1' contains a list of triphones
(each word's monophone's were grouped to triphones. sil/sp were skipped by the 'WB' directive above)
'wintri.mlf' contains the new transcription of each file, in triphone format.

Next the following command was run:
perl -w ../../../samples/HTKTutorial/maketrihed monophones1 triphones1


Which creates 'mktri.hed' with content
CL triphones1
TI T_ey {(*-ey+*,ey+*,*-ey).transP}
TI T_t {(*-t+*,t+*,*-t).transP}
TI T_sp {(*-sp+*,sp+*,*-sp).transP}
TI T_f {(*-f+*,f+*,*-f).transP}
TI T_ay {(*-ay+*,ay+*,*-ay).transP}
TI T_v {(*-v+*,v+*,*-v).transP}
TI T_ao {(*-ao+*,ao+*,*-ao).transP}
TI T_r {(*-r+*,r+*,*-r).transP}
TI T_n {(*-n+*,n+*,*-n).transP}
TI T_ow {(*-ow+*,ow+*,*-ow).transP}
TI T_w {(*-w+*,w+*,*-w).transP}
TI T_ah {(*-ah+*,ah+*,*-ah).transP}
TI T_s {(*-s+*,s+*,*-s).transP}
TI T_eh {(*-eh+*,eh+*,*-eh).transP}
TI T_ih {(*-ih+*,ih+*,*-ih).transP}
TI T_k {(*-k+*,k+*,*-k).transP}
TI T_th {(*-th+*,th+*,*-th).transP}
TI T_iy {(*-iy+*,iy+*,*-iy).transP}
TI T_uw {(*-uw+*,uw+*,*-uw).transP}
TI T_z {(*-z+*,z+*,*-z).transP}
TI T_ia {(*-ia+*,ia+*,*-ia).transP}
TI T_sil {(*-sil+*,sil+*,*-sil).transP}



and thereafter,
HHEd -A -D -T 1 -H hmm9/macros -H hmm9/hmmdefs -M hmm10 mktri.hed monophones1


The HTK book says, you can disregard the 'T_sil' related warning:
WARNING [-2631] ApplyTie: Macro T_sil has nothing to tie of type t in HHEd


Running 2 times more:
HERest -A -D -T 1 -C configtrain2 -I wintri.mlf -t 250.0 150.0 3000.0 -S trainmfc.scp -H hmm10/macros -H hmm10/hmmdefs -M hmm11 triphones1

HERest -A -D -T 1 -C configtrain2 -I wintri.mlf -t 250.0 150.0 3000.0 -s stats -S trainmfc.scp -H hmm11/macros -H hmm11/hmmdefs -M hmm12 triphones1


7:28pm: Step 10 - Making Tied-State Triphones

HDMan -A -D -T 1 -b sp -n fulllist -g ../../def/global.ded -l flog dict-tri ../../def/bigdict.txt


Where 'bigdict.txt' is taken from
http://www.voxforge.org/uploads/-A/h1/-Ah18p_AY2DzEs-9h-K-4g/voxforge_lexicon

next
cat triphones1 fulllist > fulllist1

and
perl -w fixfulllist.pl fulllist1 fulllist

where fixfulllist.pl is taken from here

I continue to follow the steps in the voxforge tutorial,

but saved a copy of 'tree.hed'
cp tree.hed tree.hed.old


and also created 'tree.hed.suffix'

TR 1

AU "fulllist"
CO "tiedlist"

ST "trees"


After creating the required folders, I ran:
perl -w ~/samples/RMHTK/perl_scripts/mkclscript.prl TB 350 ../../def/monophones0 >> tree.hed

and
HHEd -A -D -T 1 -H hmm12/macros -H hmm12/hmmdefs -M hmm13 tree.hed triphones1

which fails with:
AU fulllist
Creating HMMset using trees to add unseen triphones
ERROR [+2662] FindProtoModel: no proto for b in hSet
FATAL ERROR - Terminating program HHEd


Now, true, there's no 'b' sound in any of the digits, as well as many other sounds like m or d.
My plan is to remove any monophones I don't need from 'bigdict.txt'

8:55pm:
Finally the 'HHEd' passed after filtering out all of these phones:
"[bmljdkpqgy]\|aa\|zh\|ch\|ae\|aw\|ax\|en\|er\|hh\|sh\|uh".

The following shell script helped in the process, where I just changed the grep -v pattern until only required monophones were present)
grep -v "[bmljdkpqgy]\|aa\|zh\|ch\|ae\|aw\|ax\|en\|er\|hh\|sh\|uh" ../../def/bigdict.txt > ../../def/bigdict2.txt;

HDMan -A -D -T 1 -b sp -n fulllist -g ../../def/global.ded -l flog dict-tri ../../def/bigdict2.txt

cat triphones1 fulllist > fulllist1

perl -w fixfulllist.pl fulllist1 fulllist

rm tree.hed; cp tree.hed.old tree.hed; cp tree.hed.old tree.hed

perl -w ~/samples/RMHTK/perl_scripts/mkclscript.prl TB 350 ../../def/monophones0 >> tree.hed

cat tree.hed.suffix >> tree.hed

HHEd -A -D -T 1 -H hmm12/macros -H hmm12/hmmdefs -M hmm13 tree.hed triphones1


There's probably a simpler way to work around this.

and my flog looks like this:
1. w : 65
2. ah : 71
3. n : 305
4. sp : 561
5. ow : 172
6. t : 375
7. uw : 69
8. s : 384
9. eh : 156
10. v : 46
11. ih : 280
12. f : 117
13. r : 204
14. ao : 49
15. z : 140
16. th : 43


which seems okay (all phones > 10).

now running

HERest -A -D -T 1 -C configtrain2 -I wintri.mlf -s stats -t 250.0 150.0 3000.0 -S trainmfc.scp -H hmm13/macros -H hmm13/hmmdefs -M hmm14 tiedlist

HERest -A -D -T 1 -C configtrain2 -I wintri.mlf -s stats -t 250.0 150.0 3000.0 -S trainmfc.scp -H hmm14/macros -H hmm14/hmmdefs -M hmm15 tiedlist


9:03pm. Done for now.

12:14am. Step 11 - Recognising the Test Data (finally!)

HVite -H ../train/hmm15/macros -H ../train/hmm15/hmmdefs -S testmfc.scp -l '*' -i recout.mlf -w ../../def/wdnet -p 0.0 -s 5.0 ../../def/dict ../train/tiedlist

HResults -I ../../def/testmlf ../train/tiedlist recout.mlf


Gives perfect results:
====================== HTK Results Analysis =======================
Date: Tue May 29 00:44:39 2012
Ref : ../../def/testmlf
Rec : recout.mlf
------------------------ Overall Results --------------------------
SENT: %Correct=100.00 [H=100, S=0, N=100]
WORD: %Corr=100.00, Acc=100.00 [H=641, D=0, S=0, I=0, N=641]
===================================================================

i.e. a %100 percent recognition success!
(this is expected due to the very low variance in the .wav files).
12:46am.

References
0. HTKBook here
1. voxforge tutorial: here
2. htk problems and how to fix'em: here
3. scripts and files I wrote/used: here

November 11, 2011

Bloody Debugging in Matlab and Perl

I'm no expert in neither Matlab nor Perl, but recently I've found out these useful commands, which I'm placing here for future reference:

In Matlab,
Instead of debugging using printing (bahh) or "keyboard()"-ing at the problematic line, simply execute 'dbstop if error' right after the matlab environment loads.
This will have a similar effect as keyboard(), but just after the line that crashed and before the program state is flushed - meaning, you will be able to inspect the code and the current state of variables, without having to run the code again.
see dbstop for more advance options

In Perl,
The Carp module  is handy when you want to debug your perl code.
I have no idea why die() and warn() don't have options that allow you to output the full stacktrace, but using say, Carp's confess() fuction you will get the full stacktrace.

Any other tips?
-- Tomer







December 30, 2006

Using Subversion with IntelliJ

Although IntelliJ comes with built-in support for Subversion (and CVS..), it's not really clear how to start working on a new Version Controlled project.
Searching the web, I couldn't find a tutorial that covers this topic, and the JetBrains site only has this not uninformative article http://www.jetbrains.com/idea/features/version_control.html

If you're unfamiliar with SVN or want to know more about it, there's a great online book available at http://svnbook.red-bean.com/

Prerequisites
1. Have an SVN service installed on your server (possibly via Apache) you can get SVN at http://subversion.tigris.com/
2. Have a repository filled with code.
3. Have IntelliJ 5.5 or 6 installed (http://www.jetbrains.com/idea/

Recommendation
Install the TortoiseSVN application (http://tortoisesvn.tigris.org/).
This application integrates with the windows explorer and enables communication with an SVN service (local or remote), essentially, it contains all the functionality that IntelliJ has, and more.

Now that we got that out of the way, let's start deploying the code and configuring the project.

Step 1: Checkout
Checkout means that we will be copying the latest (HEAD) version of the version controlled project to a local folder (also called a working copy).

  1. Close all the open projects in your IntelliJ Environment.
  2. Choose the checkout a new VCS (Version Controlled Source) – the bottom left link, and then choose the SVN.
    A new window should appear, which should contain a list of links to your SVN repositories. Choose the correct link or rather, If you have none, you can add a link by clicking the golden plus sign.
  3. Create a new local directory for the project and checkout the source files to that local directory.

This step can also be done without IntelliJ, if you've installed TortoiseSVN.
Moreover, if you browse to that directory, you will see it (and each sub-folder) contains a hidden .svn directory. Do not delete these directories!

Step 2: New Project
Using IntelliJ, create a new project and select the directory you've created in the previous step. Follow the New project wizard.
Notice that IntelliJ should detect the source files you've checked out (I tried this with Java files, so I don't know if it detects other types) .

Step 3: Link to the SVN
1. Go to module settings (File / Settings) or press Ctrl+Alt+S
2. Choose Version Control
3. Set the Default Version Control to Subversion (last in the list)

Outcome
There are a few things to notice after performing this step,
  1. Notice that the file names are now colored in black and that if you change the content of a file and save it, the file name will turn blue, indicating that the local version does not match the controlled version in the remote server.
  2. The Version Control Menu Item in the main menu contains more options
  3. If you right-click a file or directory, there's a subversion sub-menu you can expand that contains options such as commit (or check-in on IntelliJ5), update, compare, etc'.

Final Notes
  1. If you're developing a web-app, (possibly under Tomcat), you might want to checkout under the DocumentRoot, or map a location to you code.
  2. Don't commit your .iml, .ipr, .iws (which are Marron Colored)
  3. you might need to link libraries, this can be done by right-clicking a module / Module Settings
  4. I've been using Subversion with 5 other developers, one of which is using NetBeans and all the others are using IntelliJ.
  5. I've also written a post on how to install SVN on Eclipse available at http://levinboim.blogspot.com/2006/09/setting-up-subversion-with-eclipse-on.html

-- Tomer

September 03, 2006

Configuring Subversion on Eclipse

Trying to install SVN (Subversion) on Eclipse for the first time was a bit tricky for me. There seems to be a lack of resources on the subject, or a latent assumption that it's too trivial, so,
here's how I did it:

Prerequisites
1. Apache installed (on your server). If you're using WinXP OS on your server, you must have Apache2.0 installed, as the svn modules are not compatible with Apache2.2.
2. Eclipse installed (on your client)

What to do:
1. Download and install SVN on your server
http://subversion.tigris.org/
This, along with the Apache service will be the Version Control server.

2. Download and install TortoiseSVN on your server (and possibly on other machines)
http://tortoisesvn.tigris.org/
TortoiseSVN integrates with the windows explorer itself (not to be confused with IE..), so, after installation, you will have a few more options when right-clicking a folder or file (namely, you can choose to import them or checkout an existing repository).

3. Open a new Repository
We will now instruct the SVN server to open and import a new repository (a managed storage place for you code\documents).
Right click on a new folder, and have the TortoiseSVN import your data there

4. Download and install Subclipse using the Eclipse IDE
Use the Help->Software Updates->Find and Install menu
Configure a new Update Server for the Subclipse plug-in at:
http://subclipse.tigris.org/update_1.0.x
This tells the Eclipse to download a plug-in, with which it is able to communicate with the Subversion service.

5. Checkout the Repository
Create a new directory on your computer. You can checkout a project from the repository to that directory either by using the Eclipse IDE or via the TortoiseSVN itself (right-click on the directory and select checkout). If Indeed TortoiseSVN is installed on your local computer, the Files and Folders under that directory are now marked with Green Checks, indicating that they are up to date. Notice each folder now contains a hidden directory called .svn. Do not delete these directories.

6. Configure the post-commit hook
If you're working on a web-application like me, you will want a read-only copy of your code (sometimes called a mirror) on a directory accessibly by your HTTP service.
This copy should be updated to reflect the changes made by you or your team members while using the Eclipse IDE.
Subversion provides a hooking mechanism (in the hooks directory, under the repository directory). I use a modification of the post-commit file, taken from
http://www.svnforum.org/2017/viewtopic.php?t=1694.
Essentially, this batch file is called after each commit, and causes the Subversion to update a working copy at D:\WorkingCopyPath.

@ECHO ON
REM POST-COMMIT HOOK
set repo=%1
set rev=%2
set log="D:\SVN\Repository\logs\post-commit_log.txt"
set err="D:\SVN\Repository\logs\post-commit_err-log.txt"
set svn="C:\Progra~1\Subversion\bin\svn.exe"
set svnpath="C:\Progra~1\Subversion\bin"
( echo ========================================================================
echo Start commit %repo% r%rev%
date /t
time /t ) >> %log%
set cmd=%svn% update D:\WorkingCopyPath
(start "start-title" /D%svnpath% /BELOWNORMAL /B %cmd% >> %log%)

That's about it. Hope you find this helpful.

February 11, 2006

Downgrading from PHP5 to PHP4

One of the projects I'm currently involved in is a web based Prediction Market. For those of you who never heard of the field, run a quick search on in Google or in a Wiki and I'm sure you'll get all the information you need.
It's a very intelligant way to aggregate information and obtain insight on the future.
Alas, since we're not here to talk about business or predicting the future (interesting as that might be.... ) let me get to the point.

During an integration with a client, I discovered that they do not use php5, but rather, an earlier version - PHP4 (v4.3.2 I believe). Obviously I requested that they would upgrade, or at least run their HTTP server (Apache) with support to both versions (it is possible...).
They declined.

As they were a very important client (our first..) I had to undergo the rigorous task of making the code PHP4 compatible. following that I decided to publish a short recipe for the process.

Recipe for Converting PHP5 to PHP4 compatible code:
1. Functions - remove the following keywords: 'public', 'private' and 'static'. There are no visibility modifiers, and all functions can be accessed statically or from an instance.
2. Instance variables - replace 'public' and 'private' with 'var'.
3. Static variables - replace with a getter and setter functions. You can use the following pattern for each variables. (Credit to peter joel, a comment at http://il.php.net/keyword.paamayim-nekudotayim):


class A
{
function getVar($val=NULL)
{
static $class_variable = 0;
if ($val != NULL)
$class_variable = $val;
return $class_variable;
}

function setVar($val=0)
{
return A::getVar($val);
}
}

4. object usage - references in PHP4 is a bit different than it is in PHP5
4.1 - prefix all functions that return an object with an amp '&'
4.2 - when invoking a functi0n that returns an object use $obj = &function() (mind the &)
4.3 - when passing an object, we need to pass it by reference, so prefix the parameter with an &, for example: function func_name(&$param_name)

After applying this recipe, your code should be PHP4 compatible.