Sphinx: Config skráin

Markmið: Að skilja hvernig config skráin er notuð og til hvers hún er.
Forkröfur eru: grunnþekking á XML, grunnþekking á Java og hlutbundinni forritun
Tól sem þarf: Java SDK 1.4.2, Sphinx-4 og einhvert þróunarumhverfi t.d. Eclipse

Sphinx-4 er talgreinir (e. speech recognizer) sem að vísindamenn við Carnegie Mellon University hafa þróað. Talgreinir er forrit sem notað er til að láta tölvu greina hvaða orð og setningar felast í þeim hljóðum sem koma inn í gegnum miðil t.d. míkrófón. Hér á eftir verður farið í það hvernig skrifa á svonefnda stilliskrá fyrir Sphinx-4. Hvernig hún er uppbyggð og hvað er hægt að gera með henni. Til að geta keyrt Spinx-4 þarf þessi skrá að vera til staðar því margir af þeim hlutum sem notaðir virka ekki rétt nema þeir séu stilltir áður en Sphinx-4 er ræstur. Í stuttu máli má segja að stilliskráin sé aðferð til að "handstilla" (e. custom configure) Sphinx-4.

Til að láta Sphinx-4 skilja það sem við erum að segja þarf, eins og áður sagði, að stilla alla þá hluta sem nota á við talgreininguna. Það skal þó tekið fram að ef ætlunin er að nota Sphinx-4 í annað en talgreiningu á afmörkuðum hóp setninga á ensku þá er ekki nauðsynlegt að skrifa eigin config skrá. Sú config skrá sem fylgir með verkefninu Sphinx-4 fyrstu skrefin er hægt að nýta ekki er ætlunin að breyta grunnstillingum forritsins (e. default settings).
Eins og áður sagði er hægt að handstilla nánast allt með config skránni og sem dæmi má nefna tungumál, málfræði, míkrófón o.s.frv. Þessi skrá er á XML formi og er því tiltölulega auðlesanleg. Það sem hægt er að skilgreina í config skrá er eftirfarandi:

  • Nöfn og tegundir allra hluta (e. component) kerfisins
  • Tengigetu (e. connectivity) þessara hluta - þ.e. hvaða hlutar tala við hverja
  • Nákvæm stilling (e. configuration) á hverjum þessara hluta

Til hvers þurfum við að fikta með allar þessar stillingar? Jú, til að Sphinx-4 virki og geti greint tal þá þarf t.d. að stilla þau tæki sem notuð eru til að taka upp hljóðið sem á að greina þ.e. í hvaða gæðum á að taka upp. Þessar stillingar skipta gríðarlega miklu máli því að sem dæmi um það má nefna að ef við tökum upp í miklum gæðum þá þarf mun meira afl til að greina upptökuna þar sem hún verður mun stærri. Það er þó einn galli við stilliskrár fyrir Sphinx-4 og það er stærðin, þær eiga það til að verða mjög stórar og umfangsmiklar. Við stökkvum þó ekki út í djúpu laugina strax. Við byrjum því á mjög einfaldri skrá til að útskýra grunnvirkni.

<config>
    <component name="mySampleComponent"
    type="edu.cmu.sphinx.sample.MyComponent"></component>
</config>

Hér höfum við skilgreint einn hluta sem heitir mySampleComponent og er af gerðinni edu.cmu.sphinx.sample.MyComponent. Þessi hluti gerir þó ekkert að svo stöddu. Þeir hlutar sem skilgreindir eru fylgja í þessu tilfelli nafnareglum frá Sun. Það er ekki nauðsynlegt að nota þessar nafnareglur en nauðsynlegt er þó að nota pakkaritháttinn. Athuga skal að þeir hlutar sem skilgreindir eru í skránni verða allir að hafa einkvæmt heiti þ.e. enginn annar hluti má hafa sama nafn.

Nú skulum við flækja málið aðeins til að skráin okkar nálgist það að vera nothæf til gagnlegra hluta. Við skilgreinum næst eiginleika (e. property) hvers hluta fyrir sig.

<config>
    <component name="concatDataSource"
    type="edu.cmu.sphinx.frontend.util.ConcatFileDataSource">
        <property name="sampleRate" value="16000"/>
        <property name="transcriptFile" value="reference.txt"/>
        <property name="silenceFile"
        value="/lab/speech/sphinx4/data/tidigits/test/raw16k/silence1sec.raw"/>
        <property name="bytesPerRead" value="320"/>
        <property name="batchFile" value="tidigits.batch"/>
        <property name="addRandomSilence" value="true"/>
    </component>
</config>

Hér skilgreinum við hluta sem nefnist concatDataSource og er að tegundinni edu.cmu.sphinx.frontend.util.ConcatFileDataSource og hefur eiginleika sem hafa einkvæm nöfn og gildi (e. value). Þessi gildi geta verið af eftirfarandi gerð:

  • sanngildi (e. boolean) - þ.e. true eða false
  • heiltala (e. integer) - þ.e. tölur á borð við 1234
  • fleytitala (e. floating point) - þ.e. tölur á borð við 1.3456
  • doubletala (e. double) tölu - þ.e. tölur á forminu "1E-140"
  • textastrengur (e. string) - t.d. "einhver texti"
  • tilvísun í hluta (e. component) - t.d. "mySampleComponent"

Á sama hátt og hægt er að skilgreina staka eiginleika sem einhvern af ofangreindum tegundum þá er einnig hægt að skilgreina lista af eiginleikum (e. property list)

<component name="fileManager"
    type="edu.cmu.sphinx.sample.FileManager">
    <propertylist name="fileNames">
        <item>file1.txt</item>
        <item>file2.txt</item>
        <item>file3.txt</item>
    </propertylist>
</component>

Hér er skilgreindur hluti á sama hátt og áður en í stað þess að gefa upp fullt af stökum eiginleikum þá skilgreinum við lista af eiginleikum. Í þessu tilfelli erum við með skráarstjórnanda sem hefur eiginleikalista sem inniheldur nöfn á skrám þ.e. file1.txt, file2.txt og file3.txt.

Hægt er að skilgreina eiginleika án þess að þeir tilheyri ákveðnum hluta og kallast þeir eiginleikar víðværir (e. global) og hafa allir hlutar sem skilgreindir eru í config skránni aðgang að þeim með tilvísun ${nafnEiginleika}.

<config>
    <property name="sampleRate" value="16000"/>
    <component name="concatDataSource"
    type="edu.cmu.sphinx.frontend.util.ConcatFileDataSource">
        <property name="sampleRate" value="${sampleRate}/>
    </component>
    <component name="microphone"
    type="edu.cmu.sphinx.frontend.util.Microphone">
        <property name="sampleRate" value="${sampleRate}/>
    </component>
    <component name="streamDataSource"
    type="edu.cmu.sphinx.frontend.util.StreamDataSource">
        <property name="sampleRate" value="${sampleRate}/>
    </component>
</config>

Hér höfum við skilgreint einn víðværan eiginleika sem nefnist sampleRate sem þrír hlutar þ.e. concatDataSource, microphone og streamDataSource nota allir við að skilgreina sína eiginleika. Hugsunin á bak við það að hafa víðværa eiginleika er sú að með þeim er hægt minnka vinnuna við breytingu á stillingum til muna. Hægt er að nota tilvísanir í víðværa eiginleika til að skilgreina allar tegundir eiginleika.

<config>
    <property name="cmn" value="liveCMN"/>
        <component name="mfcFrontEnd" type="edu.cmu.sphinx.frontend.FrontEnd">
        <propertylist name="pipeline">
            <item>streamDataSource</item>
            <item>premphasizer</item>
            <item>windower</item>
            <item>fft</item>
            <item>melFilterBank</item>
            <item>dct</item>
            <item>${cmn}/item>
            <item>featureExtraction</item>
        </propertylist>
    </component>
</config>

Hér höfum við skilgreint víðværan eiginleika líkt og í fyrri dæmum en nú notum við hann í eiginleikalista. Ekki má nota víðværa eiginleika sem heiti eða tegund hluta.

<config>
    <property name="cmn" value="liveCMN"/>
    <!-- illegal! -->
    <component name="${liveCMN}" type="edu.cmu.sphinx.frontend.CepstralMeanNormalizer"/>
</config>

Í þessu dæmi er sýnt hvernig má ekki nota víðværa eiginleika þ.e.a.s. notkun sem skilar villu þegar skráin er þýdd af Sphinx-4 forriti. Nú höfum við farið í það helsta sem þarf að þekkja til að skilja uppbyggingu á config skrám fyrir Sphinx-4. Hér að neðan er svo sýnd heil config skrá.

<?xml version="1.0" encoding="UTF-8"?>

<!--
    Sphinx-4 Configuration file
-->

<!-- ******************************************************** -->
<!--  tidigits configuration file                             -->
<!-- ******************************************************** -->

<config>

    <!-- ******************************************************** -->
    <!-- frequently tuned properties                              -->
    <!-- ******************************************************** -->

    <property name="absoluteBeamWidth" value="-1"/>
    <property name="relativeBeamWidth" value="1E-200"/>
    <property name="wordInsertionProbability" value="1E-36"/>
    <property name="languageWeight" value="8"/>
    <property name="silenceInsertionProbability" value="1"/>
    <property name="skip" value="0"/>

    <property name="linguist" value="flatLinguist"/>
    <property name="frontend" value="mfcFrontEnd"/>

    <!-- ******************************************************** -->
    <!-- batch tool configuration                                 -->
    <!-- ******************************************************** -->

    <component name="batch"
        type="edu.cmu.sphinx.tools.batch.BatchModeRecognizer">
        <property name="recognizer" value="connectedDigitsRecognizer"/>
        <property name="inputSource" value="streamDataSource"/>
        <propertylist name="monitors">
            <item>accuracyTracker </item>
        </propertylist>
    </component>

    <!-- ******************************************************** -->
    <!-- The connectedDigitsRecognizer configuration               -->
    <!-- ******************************************************** -->

    <component name="connectedDigitsRecognizer"
        type="edu.cmu.sphinx.recognizer.Recognizer">
        <property name="decoder" value="digitsDecoder"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The Decoder   configuration                              -->
    <!-- ******************************************************** -->

    <component name="digitsDecoder" type="edu.cmu.sphinx.decoder.Decoder">
        <property name="searchManager" value="searchManager"/>
    </component>

    <component name="searchManager"
        type="edu.cmu.sphinx.decoder.search.SimpleBreadthFirstSearchManager">
        <property name="logMath" value="logMath"/>
        <property name="linguist" value="${linguist}"/>
        <property name="pruner" value="trivialPruner"/>
        <property name="scorer" value="threadedScorer"/>
        <property name="activeListFactory" value="activeList"/>
    </component>

    <component name="activeList"
        type="edu.cmu.sphinx.decoder.search.SortingActiveListFactory">
        <property name="logMath" value="logMath"/>
        <property name="absoluteBeamWidth" value="${absoluteBeamWidth}"/>
        <property name="relativeBeamWidth" value="${relativeBeamWidth}"/>
    </component>

    <component name="trivialPruner"
    type="edu.cmu.sphinx.decoder.pruner.SimplePruner"/>

    <component name="threadedScorer"
        type="edu.cmu.sphinx.decoder.scorer.ThreadedAcousticScorer">
        <property name="frontend" value="${frontend}"/>
        <property name="isCpuRelative" value="true"/>
        <property name="numThreads" value="0"/>
        <property name="minScoreablesPerThread" value="10"/>
        <property name="scoreablesKeepFeature" value="true"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The linguist  configuration                              -->
    <!-- ******************************************************** -->

    <component name="flatLinguist" type="edu.cmu.sphinx.linguist.flat.FlatLinguist">
        <property name="logMath" value="logMath"/>
        <property name="grammar" value="wordListGrammar"/>
        <property name="acousticModel" value="acousticModel"/>
        <property name="wordInsertionProbability"
            value="${wordInsertionProbability}"/>
        <property name="silenceInsertionProbability"
            value="${silenceInsertionProbability}"/>
        <property name="languageWeight" value="${languageWeight}"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The Grammar  configuration                               -->
    <!-- ******************************************************** -->
    <component name="wordListGrammar"
        type="edu.cmu.sphinx.linguist.language.grammar.SimpleWordListGrammar">
        <property name="path" value="./tidigits.wordlist"/>
        <property name="isLooping" value="true"/>
        <property name="dictionary" value="dictionary"/>
        <property name="optimizeGrammar" value="true"/>
        <property name="logMath" value="logMath"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The Dictionary configuration                            -->
    <!-- ******************************************************** -->

    <component name="dictionary"
    type="edu.cmu.sphinx.linguist.dictionary.FullDictionary">
        <property name="location"
            value="file:/lab/speech/sphinx4/data/
tidigits_8gau_13dCep_16k_40mel_130Hz_6800Hz.bin.zip"/>
        <property name="dictionaryPath" value= "dictionary"/>
        <property name="fillerPath" value="fillerdict"/>
        <property name="addSilEndingPronunciation" value="false"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The acoustic model configuration                         -->
    <!-- ******************************************************** -->
    <component name="acousticModel"
    type="edu.cmu.sphinx.linguist.acoustic.tiedstate.TiedStateAcousticModel">
        <property name="loader" value="sphinx3Loader"/>
    </component>

    <component name="sphinx3Loader"
        type="edu.cmu.sphinx.linguist.acoustic.tiedstate.Sphinx3Loader">
        <property name="logMath" value="logMath"/>
        <property name="isBinary" value="true"/>
        <property name="location"
            value="file:/lab/speech/sphinx4/data/
tidigits_8gau_13dCep_16k_40mel_130Hz_6800Hz.bin.zip"/>
        <property name="definition_file" value="wd_dependent_phone.500.mdef"/>
        <property name="data_location" value="wd_dependent_phone.cd_continuous_8gau"/>
        <property name="properties_file" value="am.props"/>
        <property name="FeatureVectorLength" value="39"/>
    </component>

    <!-- ******************************************************** -->
    <!-- The frontend configuration                               -->
    <!-- ******************************************************** -->

    <component name="mfcFrontEnd" type="edu.cmu.sphinx.frontend.FrontEnd">
        <propertylist name="pipeline">
            <item>streamDataSource</item>
            <item>premphasizer</item>
            <item>windower</item>
            <item>fft</item>
            <item>melFilterBank</item>
            <item>dct</item>
            <item>batchCMN</item>
            <item>featureExtraction</item>
        </propertylist>
    </component>

    <component name="premphasizer"
        type="edu.cmu.sphinx.frontend.filter.Preemphasizer"/>
    <component name="windower"
        type="edu.cmu.sphinx.frontend.window.RaisedCosineWindower" />
    <component name="fft"
        type="edu.cmu.sphinx.frontend.transform.DiscreteFourierTransform"/>
    <component name="melFilterBank"
        type="edu.cmu.sphinx.frontend.frequencywarp.MelFrequencyFilterBank"/>
    <component name="dct"
        type="edu.cmu.sphinx.frontend.transform.DiscreteCosineTransform"/>
    <component name="batchCMN"
        type="edu.cmu.sphinx.frontend.feature.BatchCMN"/>
    <component name="featureExtraction"
        type="edu.cmu.sphinx.frontend.feature.DeltasFeatureExtractor"/>

    <component name="streamDataSource"
        type="edu.cmu.sphinx.frontend.util.StreamDataSource">
        <property name="sampleRate" value="16000"/>
    </component>

    <component name="cepstrumSource"
        type="edu.cmu.sphinx.frontend.StreamCepstrumSource">
        <property name="sampleRate" value="16000"/>
    </component>

    <!-- ******************************************************* -->
    <!--  monitors                                               -->
    <!-- ******************************************************* -->

    <component name="accuracyTracker"
        type="edu.cmu.sphinx.instrumentation.BestPathAccuracyTracker">
        <property name="recognizer" value="connectedDigitsRecognizer"/>
        <property name="showAlignedResults" value="false"/>
        <property name="showRawResults" value="false"/>
    </component>

    <!-- ******************************************************* -->
    <!--  Miscellaneous components                               -->
    <!-- ******************************************************* -->

    <component name="logMath" type="edu.cmu.sphinx.util.LogMath">
        <property name="logBase" value="1.0001"/>
        <property name="useAddTable" value="true"/>
    </component>

</config>

Eins og sést hér á kóðanum að ofan þá geta þessar skrár orðið frekar stórar og flóknar (sú skrá sem hér er sýnd er frekar einföld) og því er nauðsynlegt að vita hvernig hægt er að aflúsa þær með auðveldum hætti. Það er gert með því að skilgreina eiginleika ofarlega í skránni sem ber nafnið showCreations og gefa honum gildið true. Ef það er gert þá fæst eftirfarandi útprentun þegar Sphinx-4 forrit er ræst og látið lesa inn skránna.

Creating: batch
Creating: connectedDigitsRecognizer
Creating: digitsDecoderCreating: searchManager
Creating: logMath
Creating: flatLinguist
Creating: wordListGrammar
Creating: dictionary
Creating: acousticModel
Creating: sphinx3Loader
Creating: trivialPruner
Creating: threadedScorer
Creating: mfcFrontEnd
Creating: streamDataSource
Creating: premphasizer
Creating: windower
Creating: fft
Creating: melFilterBank
Creating: dct
Creating: batchCMN
Creating: featureExtraction
Creating: activeList
Creating: accuracyTracker
Creating: speedTracker
Creating: memoryTracker
Creating: recognizerMonitor
Creating: linguistStats

Með þessari útprentun er hægt að sjá hvar eitthvað klikkar því að útprentunin er í sömu röð og hlutar eru keyrðir upp úr skránni og stoppar þar sem eitthvað er að og skilar út á skjáinn villumeldingu.

Nú höfum við farið í það hvernig á að byggja upp stillingaskrá fyrir Sphinx-4 og séð hvað er í boði til að auðvelda breytingar á skránni og annað í þeim dúr. Stillingaskráin er geysilega öflug og er nauðsynleg til að hægt sé að keyra Sphinx-4 forrit. Það fæst því mikið út úr því að læra hvernig á að búa þær til og skilja hvernig þær virka.

 

CADIA
cadia@ru.is  |  Ofanleiti 2, IS -103 Reykjavík
Tel: +354 510 6427  |  Fax: +354 510 6201