/** * @file m_chkparam.c * * * @brief パラメータ設定の後処理. * * jconf ファイルおよびコマンドオプションによって与えられた * パラメータについて後処理を行い,最終的に認識処理で使用する値を確定する. * * * * @brief Post processing of parameters for recognition. * * These functions will finalize the parameter values for recognition. * They check for parameters given from jconf file or command line, * set default values if needed, and prepare for recognition. * * * * @author Akinobu LEE * @date Fri Mar 18 16:31:45 2005 * * $Revision: 1.7 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ #include /** * * ファイルが存在して読み込み可能かチェックする. * * @param filename [in] ファイルパス名 * * * Check if a file actually exist and is readable. * * @param filename [in] file path name * * */ boolean checkpath(char *filename) { if (access(filename, R_OK) == -1) { jlog("ERROR: m_chkparam: cannot access %s\n", filename); return FALSE; } return TRUE; } /** * * @brief jconf設定パラメータを最終的に決定する * * この関数は,jconf ファイルやコマンドオプションによって与えられた * jconf 内のパラメータについて精査を行う. 具体的には,値の範囲のチェッ * クや,競合のチェック,設定から算出される各種パラメータの計算,使用 * するモデルに対する指定の有効性などをチェックする. * * この関数は,アプリケーションによって jconf の各値の指定が終了した直後, * エンジンインスタンスの作成やモデルのロードが行われる前に呼び出される * べきである. * * * * @brief Check and finalize jconf parameters. * * This functions parse through the global jconf configuration parameters. * This function checks for value range of variables, file existence, * competing specifications among variables or between variables and models, * calculate some parameters from the given values, etc. * * This function should be called just after all values are set by * jconf, command argument or by user application, and before creating * engine instance and loading models. * * * * @param jconf [i/o] global jconf configuration structure * * @return TRUE when all check has been passed, or FALSE if not passed. * * @callgraph * @callergraph * @ingroup jconf */ boolean j_jconf_finalize(Jconf *jconf) { boolean ok_p; JCONF_LM *lm; JCONF_AM *am; JCONF_SEARCH *s, *hs; ok_p = TRUE; /* update and tailor configuration */ /* if a search config has progout_flag enabled, set it to all config */ hs = NULL; for(s=jconf->search_root;s;s=s->next) { if (s->output.progout_flag) { hs = s; break; } } if (hs != NULL) { for(s=jconf->search_root;s;s=s->next) { s->output.progout_flag = hs->output.progout_flag; s->output.progout_interval = hs->output.progout_interval; } } /* if an instance has short-pause segmentation enabled, set it to global opt for parameter handling (only a recognizer with this option will decide the segmentation, but the segmentation should be synchronized for all the recognizer) */ for(s=jconf->search_root;s;s=s->next) { if (s->successive.enabled) { jconf->decodeopt.segment = TRUE; break; } } #ifdef GMM_VAD /* if GMM VAD enabled, set it to global */ if (jconf->reject.gmm_filename) { jconf->decodeopt.segment = TRUE; } #endif for(lm = jconf->lm_root; lm; lm = lm->next) { if (lm->lmtype == LM_UNDEF) { /* determine LM type from the specified LM files */ if (lm->ngram_filename_lr_arpa || lm->ngram_filename_rl_arpa || lm->ngram_filename) { /* n-gram specified */ lm->lmtype = LM_PROB; lm->lmvar = LM_NGRAM; } if (lm->gramlist_root) { /* DFA grammar specified */ if (lm->lmtype != LM_UNDEF) { jlog("ERROR: m_chkparam: LM conflicts: several LM of different type specified?\n"); return FALSE; } lm->lmtype = LM_DFA; lm->lmvar = LM_DFA_GRAMMAR; } if (lm->dfa_filename) { /* DFA grammar specified by "-dfa" */ if (lm->lmtype != LM_UNDEF && lm->lmvar != LM_DFA_GRAMMAR) { jlog("ERROR: m_chkparam: LM conflicts: several LM of different type specified?\n"); return FALSE; } lm->lmtype = LM_DFA; lm->lmvar = LM_DFA_GRAMMAR; } if (lm->wordlist_root) { /* word list specified */ if (lm->lmtype != LM_UNDEF) { jlog("ERROR: m_chkparam: LM conflicts: several LM of different type specified?\n"); return FALSE; } lm->lmtype = LM_DFA; lm->lmvar = LM_DFA_WORD; } } if (lm->lmtype == LM_UNDEF) { /* an LM is not specified */ jlog("ERROR: m_chkparam: you should specify at least one LM to run Julius!\n"); return FALSE; } if (lm->lmtype == LM_PROB) { if (lm->dictfilename == NULL) { jlog("ERROR: m_chkparam: needs dictionary file (-v dict_file)\n"); ok_p = FALSE; } } /* file existence check */ if (lm->dictfilename != NULL) if (!checkpath(lm->dictfilename)) ok_p = FALSE; if (lm->ngram_filename != NULL) if (!checkpath(lm->ngram_filename)) ok_p = FALSE; if (lm->ngram_filename_lr_arpa != NULL) if (!checkpath(lm->ngram_filename_lr_arpa)) ok_p = FALSE; if (lm->ngram_filename_rl_arpa != NULL) if (!checkpath(lm->ngram_filename_rl_arpa)) ok_p = FALSE; if (lm->dfa_filename != NULL) if (!checkpath(lm->dfa_filename)) ok_p = FALSE; } for(am = jconf->am_root; am; am = am->next) { /* check if needed files are specified */ if (am->hmmfilename == NULL) { jlog("ERROR: m_chkparam: needs HMM definition file (-h hmmdef_file)\n"); ok_p = FALSE; } /* file existence check */ if (am->hmmfilename != NULL) if (!checkpath(am->hmmfilename)) ok_p = FALSE; if (am->mapfilename != NULL) if (!checkpath(am->mapfilename)) ok_p = FALSE; if (am->hmm_gs_filename != NULL) if (!checkpath(am->hmm_gs_filename)) ok_p = FALSE; /* cmn{save,load}_filename allows missing file (skipped if missing) */ if (am->frontend.ssload_filename != NULL) if (!checkpath(am->frontend.ssload_filename)) ok_p = FALSE; } if (jconf->reject.gmm_filename != NULL) if (!checkpath(jconf->reject.gmm_filename)) ok_p = FALSE; if (jconf->input.inputlist_filename != NULL) { if (jconf->input.speech_input != SP_RAWFILE && jconf->input.speech_input != SP_MFCFILE) { jlog("WARNING: m_chkparam: not file input, \"-filelist %s\" ignored\n", jconf->input.inputlist_filename); } else { if (!checkpath(jconf->input.inputlist_filename)) ok_p = FALSE; } } /* set default realtime flag according to input mode */ if (jconf->decodeopt.force_realtime_flag) { if (jconf->input.type == INPUT_VECTOR) { jlog("WARNING: m_chkparam: real-time concurrent processing is not needed on feature vector input\n"); jlog("WARNING: m_chkparam: real-time flag has turned off\n"); jconf->decodeopt.realtime_flag = FALSE; } else { jconf->decodeopt.realtime_flag = jconf->decodeopt.forced_realtime; } } /* check for cmn */ if (jconf->decodeopt.realtime_flag) { for(am = jconf->am_root; am; am = am->next) { if (am->analysis.cmn_update == FALSE && am->analysis.cmnload_filename == NULL) { jlog("ERROR: m_chkparam: when \"-cmnnoupdate\", initial cepstral normalisation data should be given by \"-cmnload\"\n"); ok_p = FALSE; } } } /* set values for search config */ for(s=jconf->search_root;s;s=s->next) { lm = s->lmconf; am = s->amconf; /* force context dependency handling flag for word-recognition mode */ if (lm->lmtype == LM_DFA && lm->lmvar == LM_DFA_WORD) { /* disable inter-word context dependent handling ("-no_ccd") */ s->ccd_handling = FALSE; s->force_ccd_handling = TRUE; /* force 1pass ("-1pass") */ s->compute_only_1pass = TRUE; } /* set default iwcd1 method from lm */ /* WARNING: THIS WILL BEHAVE WRONG IF MULTIPLE LM TYPE SPECIFIED */ /* RECOMMEND USING EXPLICIT OPTION */ if (am->iwcdmethod == IWCD_UNDEF) { switch(lm->lmtype) { case LM_PROB: am->iwcdmethod = IWCD_NBEST; break; case LM_DFA: am->iwcdmethod = IWCD_AVG; break; } } } /* check option validity with the current lm type */ /* just a warning message for user */ for(s=jconf->search_root;s;s=s->next) { lm = s->lmconf; am = s->amconf; if (lm->lmtype != LM_PROB) { /* in case not a probabilistic model */ if (s->lmp.lmp_specified) { jlog("WARNING: m_chkparam: \"-lmp\" only for N-gram, ignored\n"); } if (s->lmp.lmp2_specified) { jlog("WARNING: m_chkparam: \"-lmp2\" only for N-gram, ignored\n"); } if (s->lmp.lm_penalty_trans != 0.0) { jlog("WARNING: m_chkparam: \"-transp\" only for N-gram, ignored\n"); } if (lm->head_silname && !strmatch(lm->head_silname, BEGIN_WORD_DEFAULT)) { jlog("WARNING: m_chkparam: \"-silhead\" only for N-gram, ignored\n"); } if (lm->tail_silname && !strmatch(lm->tail_silname, END_WORD_DEFAULT)) { jlog("WARNING: m_chkparam: \"-siltail\" only for N-gram, ignored\n"); } if (lm->enable_iwspword) { jlog("WARNING: m_chkparam: \"-iwspword\" only for N-gram, ignored\n"); } if (lm->iwspentry && !strmatch(lm->iwspentry, IWSPENTRY_DEFAULT)) { jlog("WARNING: m_chkparam: \"-iwspentry\" only for N-gram, ignored\n"); } #ifdef HASH_CACHE_IW if (s->pass1.iw_cache_rate != 10) { jlog("WARNING: m_chkparam: \"-iwcache\" only for N-gram, ignored\n"); } #endif #ifdef SEPARATE_BY_UNIGRAM if (lm->separate_wnum != 150) { jlog("WARNING: m_chkparam: \"-sepnum\" only for N-gram, ignored\n"); } #endif } if (lm->lmtype != LM_DFA) { /* in case not a deterministic model */ if (s->pass2.looktrellis_flag) { jlog("WARNING: m_chkparam: \"-looktrellis\" only for grammar, ignored\n"); } if (s->output.multigramout_flag) { jlog("WARNING: m_chkparam: \"-multigramout\" only for grammar, ignored\n"); } if (s->lmp.penalty1 != 0.0) { jlog("WARNING: m_chkparam: \"-penalty1\" only for grammar, ignored\n"); } if (s->lmp.penalty2 != 0.0) { jlog("WARNING: m_chkparam: \"-penalty2\" only for grammar, ignored\n"); } } } if (!ok_p) { jlog("ERROR: m_chkparam: could not pass parameter check\n"); } else { jlog("STAT: jconf successfully finalized\n"); } if (debug2_flag) { print_jconf_overview(jconf); } return ok_p; } /** * * @brief あらかじめ定められた第1パスのデフォルトビーム幅を返す. * * デフォルトのビーム幅は,認識エンジンのコンパイル時設定や * 使用する音響モデルに従って選択される. これらの値は,20k の * IPA 評価セットで得られた最適値(精度を保ちつつ最大速度が得られる値) * である. * * @return 実行時の条件によって選択されたビーム幅 * * * @brief Returns the pre-defined default beam width on 1st pass of * beam search. * * The default beam width will be selected from the pre-defined values * according to the compilation-time engine setting and the type of * acoustic model. The pre-defined values were determined from the * development experiments on IPA evaluation testset of Japanese 20k-word * dictation task. * * @return the selected default beam width. * */ static int default_width(HTK_HMM_INFO *hmminfo) { if (strmatch(JULIUS_SETUP, "fast")) { /* for fast setup */ if (hmminfo->is_triphone) { if (hmminfo->is_tied_mixture) { /* tied-mixture triphones (PTM etc.) */ return(600); } else { /* shared-state triphone */ #ifdef PASS1_IWCD return(800); #else /* v2.1 compliant (no IWCD on 1st pass) */ return(1000); #endif } } else { /* monophone */ return(400); } } else { /* for standard / v2.1 setup */ if (hmminfo->is_triphone) { if (hmminfo->is_tied_mixture) { /* tied-mixture triphones (PTM etc.) */ return(800); } else { /* shared-state triphone */ #ifdef PASS1_IWCD return(1500); #else return(1500); /* v2.1 compliant (no IWCD on 1st pass) */ #endif } } else { /* monophone */ return(700); } } } /** * * @brief 第1パスのビーム幅を決定する. * * ユーザが "-b" オプションでビーム幅を指定しなかった場合は, * 下記のうち小さい方がビーム幅として採用される. * - default_width() の値 * - sqrt(語彙数) * 15 * * @param wchmm [in] 木構造化辞書 * @param specified [in] ユーザ指定ビーム幅(0: 全探索 -1: 未指定) * * @return 採用されたビーム幅. * * * @brief Determine beam width on the 1st pass. * * @param wchmm [in] tree lexicon data * @param specified [in] user-specified beam width (0: full search, * -1: not specified) * * @return the final beam width to be used. * * * @callgraph * @callergraph */ int set_beam_width(WCHMM_INFO *wchmm, int specified) { int width; int standard_width; if (specified == 0) { /* full search */ jlog("WARNING: doing full search (can be extremely slow)\n"); width = wchmm->n; } else if (specified == -1) { /* not specified */ standard_width = default_width(wchmm->hmminfo); /* system default */ width = (int)(sqrt(wchmm->winfo->num) * 15.0); /* heuristic value!! */ if (width > standard_width) width = standard_width; /* 2007/1/20 bgn */ if (width < MINIMAL_BEAM_WIDTH) { width = MINIMAL_BEAM_WIDTH; } /* 2007/1/20 end */ } else { /* actual value has been specified */ width = specified; } if (width > wchmm->n) width = wchmm->n; return(width); } /* end of file */