Introduction to Digital Speech Processing Homework 3 FAQ

Go to e-mail announced problems!

SRILM Compilation

  1. 安裝說明
  2. i686:
    • 解壓縮 srilm-1.5.10.tar.gz
    • 修改 Makefile, 在檔案上端加入 SRILM 變數到你的 srilm 目錄(絕對路徑)
      • ex: # SRILM = /home/speech/stolcke/project/srilm/devel
        => SRILM = /root/srilm-1.5.10

        更多請詳見 Q3
        以下 SRILM 路徑都以此路徑舉例說明
    • 修改檔案 common/Makefile.machine.i686
      • 17 行的 CC 改成 CC = /usr/bin/gcc $(GCC_FLAGS)
      • 18 行的 CXX 改成 CXX = /usr/bin/g++ $(GCC_FLAGS) -DINSTANTIATE_TEMPLATES
      • 52, 53 行的 tcl 設定改成下面三行
          NO_TCL = X
          TCL_INCLUDE =
          TCL_LIBRARY =
    • 請確定 sbin/ 資料夾底下的程式為可執行檔。若不是或不確定,移至 sbin/底下,在命令列輸入 chmod 755 *
    • 完成以上步驟後, 在命令列輸入 make MACHINE_TYPE=i686 World
    • 清除編譯過程中的暫存檔:make cleanest
    • 安裝好後, 可在 bin/i686 中找到 SRILM 的執行檔
    i686-m64:
    • 64 bit machine (e.g., 資工系工作站),請修改 common/Makefile.machine.i686-m64
      修改後執行 make MACHINE_TYPE=i686-m64 World
      安裝好後, 可在 bin/i686-m64 中找到 SRILM 的執行檔
    Mac OS X: 如果系統是 Mac OS X,一開始的編譯方式會和上面不太一樣。
    • 解壓縮 srilm-1.5.10.tar.gz
    • 修改 Makefile,將 SRILM 路徑改成你要的路徑
    • 修改 common/Makefile.machine.macosx
        line 13: 改為 CC = /usr/bin/gcc $(GCC_FLAGS) -Wimplicit-int
        line 14: 改為 CXX = /usr/bin/g++ $(GCC_FLAGS) -DINSTANTIATE_TEMPLATES
        line 49, 50: 註解掉
    • 確定 srilm 安裝資料夾下的 sbin 為可執行檔
    • 在 srilm 安裝資料夾下輸入 make MACHINE_TYPE=macosx World
    • 清除暫存檔: make cleanest
    • 之後會在 srilm 安裝資料夾 /bin/macosx 裡看到執行檔
    • 要撰寫你自己 ngram_test 的 Makefile 時:
      MACHINE_TYPE = macosx
      CXX = /usr/bin/g++
  3. SRILM compile error!
  4. 出現下述語句:
    make: /home/master/98/r98922053/srilm-1.5.10/sbin/machine-type: Command not found
    
    • 很有可能是因為你的系統中沒有安裝 csh
    • 一般工作站應該都有安裝,若同學是使用自己的 linux 系統,可到套件管理程式那邊搜尋 csh 並安裝,
      或是在終端機輸入 sudo apt-get install csh
    裝了 csh 還是出現以下 error:
    make: /sbin/machine-type: Command not found
    
    • 可能你的 SRILM 路徑含有中文,請確認是否為全英文路徑
    matherr.c:18:16: warning: 'struct exception' declared inside parameter list will not be visible outside of this definition or declaration
    matherr(struct exception *x)
        ^~~~~~~~~
    matherr.c: In function 'matherr':
    matherr.c:21:10: error: dereferencing pointer to incomplete type 'struct exception'
    if (x->type == SING && strcmp(x->name, "log10") == 0) {
    ^~
    matherr.c:21:20: error: 'SING' undeclared (first use in this function)
    if (x->type == SING && strcmp(x->name, "log10") == 0) {
            ^~~~
    matherr.c:21:20: note: each undeclared identifier is reported only once for each function it appears in
    matherr.c:29:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
    make[2]: *** [/home/master/98/r98922053/srilm-1.5.10/common/Makefile.common.targets:85: ../obj/i686-m64/matherr.o] Error 1
    make[2]: Leaving directory '/home/master/98/r98922053/srilm-1.5.10/lm/src'
    make[1]: *** [Makefile:77: release-libraries] Error 1
    make[1]: Leaving directory '/home/master/98/r98922053/srilm-1.5.10'
    make: *** [Makefile:51: World] Error 2
    
    • 這是因為最新版的 glibc 2.27 已經把 struct exception 拿掉
    • 將 srilm-1.5.10/lm/src/matherr.c 第 14 ~ 29 行註解掉即可
    我使用 ubuntu 編譯 srilm,結果他回報 __off64_t 和 long int 的錯誤
    • 這是 Ubuntu gcc library 自己的問題......
    • 可以修改 /usr/include/stdio.h
      把所有 __off64_t 取代成 long int 後儲存離開即可
    Mac 執行 make MACHINE_TYPE=macosx World 後會出現以下 error message:
    11 warnings and 1 error genertated.
    
    make[2]: *** [../obj/macosx/LatticeIndex.o] Error 1
    make[1]: *** [release-libraries] Error 1 
    make: *** [World] Error 2 
    
    • 請參考網頁 https://apurvtwr.wordpress.com/2012/11/08/installing-srilm-on-mac-10-8-2/
    • 感謝 2014Autumn 修課的熊育萱同學
    /usr/include/features.h:367:25 fatal error: sys/cdefs.h no such file or directory
    
    • 可能因為電腦是 64bit 但卻用 32bit 去 compile
  5. SRILM Makefile 前面的 # 是什麼?
  6. 代表註解掉 # 之後一行的意思,跟 C++ 中的 // 相同。因此在 srilm-1.5.10/Makefile 中應該要去掉 # 並設定 path:
    • # SRILM = /home/speech/stolcke/project/srilm/devel
      改成 SRILM = 你的srilm資料夾 即可,例如 SRILM = /home/dsp/srilm-1.5.10
    • PS: 若想查詢完整路徑可在 srilm 的資料夾底下輸入 pwd 即可
    • PS2: 因為檔案預設都是唯讀檔,你可以 chmod 644 Makefile 改變權限,或是在存檔時輸入 wq! 即可

Docker

  1. 要怎麼把檔案抓到 docker 環境裡面?寫完作業之後要怎麼拿出來?
    • 方法一:使用 GitHub
      可以用 wget 將檔案下載到環境中;上傳檔案則建議用 github,但請記得將 repository 設定為 private。
    • 方法二:在 run docker image 的時候將資料夾掛載進 image (類似共用資料夾的原理)
      如同投影片中敘述的傳入 -v 參數,完整用法為
      docker run -it -v /home/r12345678/dsp_hw3:/root/dsp_hw3 ntudsp2020autumn/srilm
      
      
      如此一來便會將 /home/r12345678/dsp_hw3 資料夾掛載進 docker container 的 /root/dsp_hw3
      (請依照需求自行調整路徑)
      另外 docker 本身在 image clone 下來之後會自行隨機命名, 使用 docker ps 指令可以看到如下圖的情形
      CONTAINER ID        IMAGE                    COMMAND             CREATED        
           STATUS                     PORTS               NAMES
      6b0238b241f4        ntudsp2020autumn/srilm   "/bin/bash"         8 seconds ago 
           Exited (0) 4 seconds ago                       practical_fermat
          
      此時使用
      # Option 1:
      docker COMMAND practical_fermat
      # Option 2:
      docker COMMAND 6b0238b241f4
      兩種之一皆可對此 container 進行 COMMAND(如 startattach 等)的操作。
      若要對 container 事先自行命名則加入 --name 參數,例如
      docker run -it -v /home/r12345678/dsp_hw3:/root/dsp_hw3 --name my_new_name \
          ntudsp2020autumn/srilm
      
      即可命名為 my_new_name
    • 方法三:將檔案複製進 docker 或從 docker 複製出來。例如:
      # 將 container 內 /path/to/file_to_be_copied 的複製出來到 /path/to/host_file
      docker cp CONTAINER_ID:/path/to/file_to_be_copied /path/to/host_file
      # 將 container 外 /path/to/out_file 的複製進 docker 的 /path/to/docker_file
      docker cp /path/to/out_file CONTAINER_ID:/path/to/docker_file
      
      
  2. 為什麼每次跑投影片的指令之後,環境裡面的東西都不見了?
    • 投影片上的指令是開啟一個新的 container,如果一直跑這個指令就會一直開新的 container。
    • 正確的作法應該是使用 docker ps -a 確認 container 的 name 之後,用 docker start <name> 跟 docker attach <name> 回到原來的 container。

Map Big5-ZhuYin.map to ZhuYin-Big5.map

  1. mapping table 格式說明
    • Character based 注音對應中文的 mapping 大概是長這樣:
      ㄅ  八 匕 卜 不 卞 巴 比 丙 包 ...
      八  八
      匕  匕
      不  不
      ...
      ...
      ㄆ  仆 匹 片 丕 叵 平 扒 扑 疋 ...
      仆  仆
      匹  匹
      片  片
      ...
      ...
      ㄦ  二 而 耳 兒 洱 貳 爾 餌 邇 ...
      二  二
      而  而
      兒  兒
      ...
      ...
      
      注意:實作上,列的順序不一定要按照字典排序(不用ㄅㄆㄇ……,可以ㄧㄅㄍㄒ……)。
    • 注音文要轉換成字的時候,只取第一個注音轉換一個字(例如:ㄅ→罷),
      不是該字的所有注音都要能轉換(例如:不會有ㄚ→罷), 也不會有多個注音轉到一個字(例如:ㄅㄨ→布)。
      注意:破音字可能會出現在多個不同注音作為開頭的行內。
    • 不是所有注音都會出現在 map 中,例如沒有以ㄝ和ㄟ作為開頭的字,那麼ㄝ和ㄟ就不會出現在 map 中
    • 第一行和其對應的字中間必須是 tab 字元('\t'),而每個對應的字必須用一個空格隔開
  2. mapping 產生 ZhuYin-Big5.map 可以用 Python 寫嗎?
  3. 可以,但 mydisambig 必須要用 C++ 寫。關於使用 Makefile 執行 Python 程式可以參考 Makefile template 中 map 的部份。
    使用 Python 讀檔與寫檔時,請用 'big5-hkscs' 作為 encoding。
    • 由於 Python 官方已不再維護 Python 2,因此如需使用 Python 請使用 Python 3
      如果是使用 docker 的話裡面的 Python 預設安裝的版本是 3.6.8,命令列下 python 預設出來的也會是 Python 3。
  4. Big5-ZhuYin.map 和 corpus.txt 開起來都是亂碼或問號?
    • 因為這些檔案都是 Big5 編碼,若環境預設用 utf-8 或其他編碼去開,自然會出現亂碼。
    • 若需要檢視檔案內容,可以使用 iconv -f big5 $filename 觀看,
      但需注意程式讀檔與寫檔均需使用 Big5 格式,請勿以其他編碼覆寫掉原本的檔案。

Using SRILM

  1. 請問為何安裝之後無論我怎麼跑指令都不會產生任何結果也不會產生錯誤?
  2. 請注意全形半形的問題,不要直接把投影片上的指令 copy and paste 到 terminal 去執行
  3. 在建立 lm 的時候, -unk 是處理什麼的 OOV?
  4. 在 testdata 中一定會有 corpus.txt 沒出現過的字,因此在 disambig 的時候就會變成 OOV。 在建立 lm 的時候加 -unk,打開 lm 就會發現有 <unk> 的機率,之後在 disambig 的時候就可以使用 <unk> 的機率代替 OOV 的機率。
  5. 請問為何執行 disambig -text testdata/xx.txt -map ZhuYin-Big5.map -lm bigram.lm -order 2 > $output, 所有 注音轉成了中文字 ,但是所有 中文字都變 <unk> 了?
    • ZhuYin-Big5.map 的格式是為了表示出 Viterbi 所需要的 obervation 與 state 之間的對應關係,
      也就是空白的左邊是 observation,右邊是所有可能的 state。
    • 因此 ZhuYin-Big5.map 有兩種對應:注音(observation)對應到可能的字(state),以及字(observation)對應到自己(state)。
    • 所以 當 ZhuYin-Big5.map 只有注音對應到字,沒有字對應到字
      則雖然 disambig 讀入注音(observation)時,可以很順利的找出可能的字(state),
      但讀入中文字(observation)時,由於 map 沒有對應的 state,因此會被視為 <unk>。
      或者 testdata 出現 corpus.txt 中沒有的字 ,也會因為 map 沒有對應的 state 而被視為 <unk>。
      因此請在執行時加添加 "-keep-unk",也就是
      disambig -text testdata/xx.txt -map ZhuYin-Big5.map -lm bigram.lm -order 2 -keep-unk > $output
      這會使得 disambig 在遇到沒看過的字時,直接把輸入當成輸出。
  6. 請問為何執行 disambig -text testdata/xx.txt -map ZhuYin-Big5.map -lm bigram.lm -order 2 > $output 所有字都變 <unk> 了?
  7. ZhuYin-Big5.map 的檔案格式應為 Big5,若為 utf-8 則可能使 disambig 將不同 encoding 的相同字當作是不同的,因此就會全部都是 <unk>。

    檢查方法:在 terminal 打 file ZhuYin-Big5.map,只要是 ISO 開頭的應該就沒問題。

MyDisambig

  1. How to include class Ngram and Vocab
    • 如果同學要讀 SRILM 所訓練出來的 model,最簡單的方法就是 link SRILM 的 library。
      Compile 完之後,lib 的位置在 $(SRIPATH)/lib/$(MACHINE_TYPE)/ 之下,
      e.g. /root/srilm-1.5.10/bin/i686-m64。
    • 如 source code 為 ngram_test.cpp,可撰寫 Makefile:
      SRIPATH ?= /root/srilm-1.5.10
      MACHINE_TYPE ?= i686-m64
      
      CXX = g++
      CXXFLAGS = -O3 -I$(SRIPATH)/include -w --std=c++11
      vpath lib%.a $(SRIPATH)/lib/$(MACHINE_TYPE)
      
      TARGET = ngram_test
      SRC = ngram_test.cpp
      OBJ = $(SRC:.cpp=.o)
      
      .PHONY: all clean
      
      all: $(TARGET)
      
      $(TARGET): $(OBJ) -loolm -ldstruct -lmisc
      	$(CXX) $(LDFLAGS) -o $@ $^
      
      %.o: %.cpp
      	$(CXX) $(CXXFLAGS) -c $<
      
      clean:
      	$(RM) $(OBJ) $(TARGET)
      
      source code ngram_test.cpp 為:
      #include <stdio.h>
      #include "Ngram.h"
      int main(int argc, char *argv[]) {
          int ngram_order = 3;     Vocab voc;     Ngram lm( voc, ngram_order );     {         const char lm_filename[] = "./corpus.lm";         File lmFile( lm_filename, "r" );         lm.read(lmFile);         lmFile.close();     }     VocabIndex wid = voc.getIndex("囧");     if(wid == Vocab_None) {         printf("No word with wid = %d\n", wid);         printf("where Vocab_None is %d\n", Vocab_None);     }     wid = voc.getIndex("患者");     VocabIndex context[] = {voc.getIndex("癮") , voc.getIndex("毒"), Vocab_None};     printf("log Prob(患者|毒-癮) = %f\n", lm.wordProb(wid, context)); }
      如此就可以利用 lm.wordProb 來得到 language model 的機率。
    • 示範檔下載: ngram_test.zip (corpus.lm 非 char-based LM!!)
  2. 什麼 function 可以測試字有沒有在字典裡面?
  3. 可以寫成下面這個樣子來測試
    VocabIndex wid = voc.getIndex("囧");
    if(wid == Vocab_None) {
        // replace OOV with <unk>
        wid = voc.getIndex(Vocab_Unknown);
    }
    
    // do something
    ...
    
    
  4. 不太清楚 mydisambig 怎麼寫?
  5. 我在 SRILM 的 libraires 中找到 disambig 跟 Viterbi algorithm 的 source code,可以直接使用嗎?
    • 不可以,助教會檢查同學們有沒有使用,抓到視同抄襲。
  6. 讀取OOV的Bigram時出現錯誤
    • 因為OOV的getIndex得到的wid是-1,無法直接套用在算機率上, 故必須先判斷他是否為OOV後再套入lm.wordProb求機率
    • 附上兩個簡單的Method讓同學方便讀取ngram Prob: GetProb.txt

E-mail Announced Problems

  1. 出現警告訊息是我做錯了嗎?
  2. 在執行 ngram-count 時出現
    warning: discount coeff 1 is out of range: -0
    
    或者在執行 disambig 時出現
    corpus_LM.txt: line 10: warning: non-zero probability for <unk> in closed-vocabulary LM
    
    (這條是因為我們用了 <unk> 而我們確實希望出現 OOV 時輸出 <unk>) 這兩條警告訊息忽略即可。
  3. 為什麼我跑出來幾乎全部都是 <unk>?
  4. 各位同學可以檢查一下,在 disambig 之前,有沒有記得 test_data 也和 training corpus 一樣經過 separator_big5.pl 斷成字。
  5. example_ans.txt 和投影片說好的輸出格式怎麼不一樣?
  6. 關於 example_ans.txt 檔案的意義,只是提供同學們比較 decode 出來的結果跟 ground truth 的差距,而這個檔案的格式並非 SRILM 格式,因此理論上同學輸出的格式應該要是如
    <s> 讓 他 十 分 害 怕 </s>
    <s> 只 希 望 自 己 明 年 度 別 再 這 麼 苦 命 了 </s>
    <s> 演 藝 娛 樂 產 業 加 入 積 極 轉 型 提 升 競 爭 力 </s>
    <s> 明 天 就 是 年 </s>
    <s> 台 灣 將 正 式 加 入 世 界 貿 易 組 織 </s>
    <s> 因 應 全 球 化 市 場 國 際 競 爭 </s>
    ...
    
    的格式才是正確的。為了方便同學比較,一個格式正確的 sample 提供在這邊。不過同學 disambig example.txt 出來的結果並不一定會完全和 example_sample.txt 相同(因為 LM 的訓練語料等因素會造成模型的差異)請各位留意。
  7. 如果我要寫 trigram bonus,請問有沒有要求應該要符合什麼格式或者寫在哪個檔案裡?
  8. 各位如果要寫 bonus 的 trigram decoding,因為我們在一開始並沒有明確給定 trigram 版本的 mydisambig 指令要怎麼下,因此只要在
    • 不影響原本 bigram
    • 格式上可以讀取和 bigram 一樣的四個參數,亦即
          $1 segemented file to be decoded
          $2 ZhuYin-Big5 mapping
          $3 language model
          $4 output file
      
    • 輸出格式和 bigram 一樣符合 SRILM 格式
    的條件下,在報告中描述清楚 trigram 的作法與怎麼編譯與執行的指令,都是可以接受的。
    另外關於執行時間的部份,雖然 trigram 的 decoding 會比 bigram 更複雜,但是演算法的效率在實際應用上時也非常重要,因此希望同學將程式碼優化到能夠一樣在 1 分鐘內完成,才會給 bonus 分數。
    具體作法上這邊助教提供幾個選項:
    • 另外寫一個 mydisambig_trigram.cpp,在 make 時從 Makefile 中另外 compile 出 mydisambig_trigram 執行檔,隨後用
          ./mydisambig_trigram $1 $2 $3 $4
      
      也就是跟 bigram 一樣的格式。
    • 將 bigram 跟 trigram 的 decoding 寫在同一個 cpp,因此只會 make 出一個 mydisambig,在 decode trigram 時使用
          ./mydisambig $1 $2 $3 $4 --tri
      
      指令 decode。
    同時,請別忘了在報告中盡可能詳細敘述 trigram 你是怎麼做的,因為這個也會是 bonus trigram 批改的因素之一(當然前提是要跑出東西,單純敘述是拿不到分數的)。但仍請注意報告請符合兩頁的篇幅限制(不論有沒有做 trigram),超出兩頁的報告一概不接受。
  9. 我的 setup.sh 不會 work?
  10. 如果執行出現 error [: -v: unary operator expected 錯誤,原因可能是 bash 版本不同所致,可以更改 setup.sh 如下:
    原本是

    if [ ! -v SRILM_BIN_PATH ]; then
        export SRILM_BIN_PATH="$SRILM_REP_PATH/bin/$MACHINE_TYPE"
        export PATH="$SRILM_BIN_PATH:$PATH"
        export PS1="(srilm) $PS1"
    fi
    

    更改為

    set_var() {
            export SRILM_BIN_PATH="$SRILM_REP_PATH/bin/$MACHINE_TYPE"
            export PATH="$SRILM_BIN_PATH:$PATH"
            export PS1="(srilm) $PS1"
    }
    
    not_set_var () { :;}
    
    [[ $SRILM_BIN_PATH && ${SRILM_BIN_PATH-x} ]] && not_set_var || set_var
    

    這是因為 -v 的語法不為某些舊版的 bash 接受。不過如果是用 docker 的同學應該不會遇到這樣的問題。

  11. 出現 SRILM Assertion error
  12. 有些同學會遇到這種 error

    關於這個問題,可能的原因有

    • code 寫壞了
    • code 裡面有包含測試的 code 但是編碼用成 UTF-8 (因為 LM 是用 Big5-HKSCS)
  13. C++ library 可以使用嗎?
  14. 可以的,STD library 包括 <map><vector><algorithm> 基本上 compile 不會 error 都可以。

  15. 我 cout 出來都是亂碼?
  16. 如果同學用 C++ 進行 cout、cerr 之類的卻因為亂碼而看不懂,可以用

        ./mydisambig ... | iconv -f big5
    

    加上後面的 | iconv -f big5 來正確轉碼,或者檔案存下來後用以往 FAQ 的作法轉碼。要注意的是如果 source code 中有中文字切記要用 Big5-HKSCS 存。

  17. 關於 Big5 和 Big5-HKSCS 的差異問題
  18. 這部分原則上跟具體實作並沒有太大的關係,但是以防同學因為使用任何編輯器存檔時改到 encoding 造成結果壞掉還是提醒一下。原則上我們是以 Big5-HKSCS 為準。

  19. 我還是不會用 SRILM library
  20. 在這邊多開放一些前年提供的 libraries 給各位參考,尤其是 testError.cc 有一些使用 library 很方便的提示。真的還是不行的話,可以上網查 documentations。
  21. Makefile 中的 ?= 是什麼?
    • 代表預設值的意思,寫作業時可將 ?= 後面改為同學各自的參數
    • 批改作業時會需要從外面輸入助教的 SRIPATH, MACHINE_TYPE,因此請勿把問號拿掉
  22. make all 時出現 Makefile:21: *** missing separator (did you mean TAB instead of 8 spaces?). Stop. 怎麼辦?(前年 FAQ)
    • Makefile 的縮排有規定要是tab,不能是相同長度的空白。
    • 請勿自行將 Makefile 的 tab 以空白帶換!