让kaldi在Linux开发板上运行起来~ (测试运行篇)
【kaldi各文件解釋】
-
/egs:不同語料例子的執行腳本文件
-
/tools:存放asr過程中用到的庫
-
/src:存放實際執行的c++算法
-
解碼工具(src/onlinebin中):
online-gmm-decode-faster:識別從麥克風輸入的語音
online-wav-gmm-decode-faster:識別指定的wav文件
【分析chain模型的目錄結構】
run.sh根據wavpath生成的數據關系保存在/data里,文件解釋如下:
- spk2utt 包含說話人編號和說話人的語音編號的信息
- utt2spk 語音編號和說話人編號之間的關系
- wav.scp 包含了原始語音的路徑信息(格式:文件名 路徑)
{local, steps, utils}里面包含了run.sh所要用到各種的腳本文件
【運行數據堂chain模型】
將數據堂訓練好的模型移動到kaldi/egs的后續準備工作:
①Go to kaldi/egs/aidatatang_asr, create symlinks to /steps/ and /utils/ like this:
ln -s ../wsj/s5/steps/ steps ln -s ../wsj/s5/utils/ utils②設置你自己的WAVPATH
③運行模型:./run.sh WAVpath
但事情往往沒那么簡單。。。
【run.sh運行過程】
報錯1:
需要移植python,perl。
用buildroot配置,target packages->Interpreter languages and scripting->選中python和perl
sudo make時報錯
將文件復制到設備:__populate_fs: 無法為ext2文件系統分配塊 寫入文件“modules.symbols.bin”時 mkfs.ext4: 無法為ext2文件系統分配塊 于填充文件系統時 *** Maybe you need to increase the filesystem size (BR2_TARGET_ROOTFS_EXT2_SIZE)解決:sudo vim .config,調整BR2_TARGET_ROOTFS_EXT2_SIZE為100M
報錯2:
解決:去掉.decode('utf8')
報錯3:
local/decode.sh exp/chain/tdnn_1a_sp exp/chain/tdnn_1a_sp/decode_offline_test_19700101 8 utils/copy_data_dir.sh: copied data from data/offline_test to data/offline_test_hires mktemp: Invalid argument sort: invalid option -- 'C' BusyBox v1.29.3 (2020-12-01 11:02:45 CST) multi-call binary.Usage: sort [-nrugMcszbdfiokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR] [FILE]...Sort lines of text-o FILE Output to FILE-c Check whether input is sorted-b Ignore leading blanks-f Ignore case-i Ignore unprintable characters-d Dictionary order (blank or alphanumeric only)-n Sort numbers-g General numerical sort-M Sort month-t CHAR Field separator-k N[,M] Sort by Nth field-r Reverse sort order-s Stable (don't sort ties alphabetically)-u Suppress duplicate lines-z Lines are terminated by NUL, not newline utils/validate_data_dir.sh: file data/offline_test_hires/utt2spk is not sorted or has duplicates查找包含mktemp的文件:grep -rn "mktemp" *
根據上面的結果追蹤:decode.sh → utils/copy_data_dir.sh → utils/validate_data_dir.sh
tmpdir=$(mktemp -d /tmp/kaldi.XXXX);
根源:腳本是gnu版本的mktemp,而它與busybox版本的mktemp用法不同。
gnu linux核心命令和工具的源碼路徑
mktemp源碼:ftp://ftp.mktemp.org/pub/mktemp
結果:交叉編譯后在板子上正常運行!
還需要解決sort錯誤:
【更換coreutils】
? 大部分人的工作環境基本都是GNU/Linux,而我們的開發板中的工作組件(busybox-coreutils),與gnu的核心工具組件有一部分是不太兼容的,如mktemp
#mktemp --help in busybox Create a temporary file with name based on TEMPLATE and print its name. TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX). Without TEMPLATE, -t tmp.XXXXXX is assumed.#mktemp --help in gnu Create a temporary file or directory, safely, and print its name. TEMPLATE must contain at least 3 consecutive `X's in last component. If TEMPLATE is not specified, use tmp.XXXXXXXXXX, and --tmpdir is implied.諸如mv,sort等命令在gnu和busybox的實現多少是有些差別的。
而因為我們要想在開發板上(移植)運行一些開源軟件,就需要重新交叉編譯一下移植gnu的coreutils。
手動編譯:gnu-coreutils源碼下載地址:https://ftp.gnu.org/gnu/coreutils/
buildroot配置coreutils:target packages → systemtool → coreutils
報錯4:
執行decode.sh時莫名其妙就aborted了。。。
卡在解碼!!!
手動運行解碼命令:
export TRAINDIR=exp/chain/tdnn_1a_sp export GRAPHDIR=exp/chain/tdnn_1a_sp/graph./steps/online/nnet3/prepare_online_decoding.sh $GRAPHDIR $TRAINDIR ./chain_conf #生成一些配置文件 /root/kaldi/src/online2bin/online2-wav-nnet3-latgen-faster --do-endpointing=false --frames-per-chunk=20 --extra-left-context-initial=0 --online=true --config=chain_conf/conf/online.conf --min-active=200 --max-active=7000 --beam=15.0 --lattice-beam=6.0 --acoustic-scale=1.0 --word-symbol-table=$GRAPHDIR/words.txt $TRAINDIR/final.mdl $GRAPHDIR/HCLG.fst --utt2spk=ark:data/offline_test_hires/split4/1/utt2spk 'ark,s,cs:wav-copy scp,p:data/offline_test_hires/split4/1/wav.scp ark:- |' 'ark:|lattice-scale --acoustic-scale=10.0 ark:- ark:- | gzip -c >exp/chain/tdnn_1a_sp/decode_offline_test_19700101/lat.1.gz'報錯:
what(): std::bad_alloc經查找資源,好像是內存不夠了,(別好像,就是內存不夠)。
還嘗試過修改源碼(意義不大):
結合提示信息與nnet-compile-looped.cc上下文中的提示輸出,可以定位到
for (num_requests = num_requests1; num_requests <= max_requests;num_requests *= factor) {if (CompileLoopedInternal(nnet, optimize_opts,request1, request2, request3,num_requests, computation)) {KALDI_LOG << "Spent " << timer.Elapsed()<< " seconds in looped compilation.";return;} }}應該是for循環中內存耗盡。再看CompileLoopedInternal函數
std::vector extra_requests
修改:在CompileLoopedInternal函數結尾添加vector().swap(extra_requests); 手動清除vector空間。
意義不大。。。
#### 編譯valgrind,查看內存使用情況,是否有泄漏:
buildroot → target packages → debugging… 中有valgrind選項,但下載很慢。不過手動下載也不快,然后編譯也有不少問題,建議用buildroot直接配置。
下載地址:http://valgrind.org
手動編譯:
#!/bin/bashCXX=arm-linux-gnueabihf-g++ CC=arm-linux-gnueabihf-gcc ./configure --prefix= --host=arm-linux-gnueabihf make -j4 make install DESTDIR=`pwd`/build開發板中測試,valgrind --tool=memcheck --leak-check=full ./onlinewav.sh
==554== HEAP SUMMARY: ==554== in use at exit: 26,382 bytes in 540 blocks ==554== total heap usage: 999 allocs, 459 frees, 51,831 bytes allocated ==554== ==554== 594 bytes in 33 blocks are still reachable in loss record 1 of 4 ==554== at 0x483D858: malloc (vg_replace_malloc.c:307) ==554== by 0x6DC4B: initialize_signames (in /bin/bash) ==554== ==554== 1,614 bytes in 4 blocks are still reachable in loss record 2 of 4 ==554== at 0x483D858: malloc (vg_replace_malloc.c:307) ==554== by 0x6DAD7: xrealloc (in /bin/bash) ==554== ==554== 1,657 bytes in 4 blocks are still reachable in loss record 3 of 4 ==554== at 0x4840550: realloc (vg_replace_malloc.c:834) ==554== by 0x6DACB: xrealloc (in /bin/bash) ==554== ==554== 22,517 bytes in 499 blocks are still reachable in loss record 4 of 4 ==554== at 0x483D858: malloc (vg_replace_malloc.c:307) ==554== by 0x6DA8F: xmalloc (in /bin/bash) ==554== ==554== LEAK SUMMARY: ==554== definitely lost: 0 bytes in 0 blocks ==554== indirectly lost: 0 bytes in 0 blocks ==554== possibly lost: 0 bytes in 0 blocks ==554== still reachable: 26,382 bytes in 540 blocks ==554== suppressed: 0 bytes in 0 blocks ==554== ==554== For lists of detected and suppressed errors, rerun with: -s ==554== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)沒有什么發現。。。(kaldi有那么多大神在維護,源碼上應該沒問題的,更何況是內存泄露這種嚴重的問題。)
將整個文件系統燒到128G SD卡中:
? 本以為這會兒應該能解決了,但,,,,磁盤==內存?
我的天,plan-lastest(基本是最后的測試方案了),行不通。。。。。。。
上網查std::bad_alloc是怎么回事,在github中看到一個dan神的回復:https://github.com/kaldi-asr/kaldi/issues/3977,建議用gdb調試。
嘗試用gdb調試,定位錯誤:
https://jason–liu.github.io/2018/01/23/gdbdebug/
【gdb調試時函數都是“?”】
猜測:交叉編譯環境下和開發板運行環境中調用的lib.so.6不一樣。實際用diff命令檢查時,發現還真不一樣。
修改kaldi.mk
刪除src/nnet3和src/nnet3bin下的目標文件(*.o)
重新編譯鏈接:make
現實是殘酷的:還是存在問號。
【實際原因】:注意info sharedlibrary時報的錯誤(*): Shared library is missing debugging information.
動態庫缺少debug 信息,但這影響的僅僅是gdb調試過程,而對kaldi實際運行過程沒有影響。先跳過。
【嘗試添加虛擬內存】:
嘗試了很多種方法,但好像都有點問題,如
①直接NFS時創建swap文件,報swapfile has holes;
②在進入sd卡文件系統后,fdisk /dev/mmcblk0p2,對分區2(根文件系統的掛載分區)再分區,但doesn’t contain a valid partition table,fdisk命令后無法w,不起作用。也試過在虛擬機下對/dev/sdd2分區,行不通。
③sd卡下創建swap文件,運行時報mmcblk0: retrying using single block read,error:-84…
? 最后,在某一天晚上,在解決gdb問句和swap分區不起作用問題,都沒有建樹后,打算睡覺來著。但想了想再看一下,整理一下虛擬機環境(解決問號問題時嘗試移植glibc庫,版本不對,根文件系統直接崩潰了,還把lib目錄搞的有點亂)
正文!!!:
? 然后又試了下運行kaldi解碼,就那一刻突然開竅了,注意到了一個細節,③中:在解碼時,報錯會晚一點點,猜測是在嘗試使用虛擬內存時報的錯。說明什么?說明使用虛擬內存使得程序的崩潰點推遲了,根本原因就是運行內存不足!
? 重新分析添加虛擬內存時出現的問題,在嘗試③中有了突破,mmcblk0: retrying using single block read,error:-84…的問題在于SD卡的讀寫速度太快,應該要修改一下sd卡的時鐘頻率。SD卡中swap文件雖然可以作為虛擬內存,但與實際內存的讀寫速度是不一樣的。
? 于是我想到好像可以去dts中修改usdhc的時鐘配置。而在這時突然靈光一閃,sd卡速度太快?emmc作為開發板上的默認儲存器,與CPU的讀寫應該適配吧。然后就嘗試用emmc作為虛擬內存。
mkswap /dev/mmcblk1p2 swapon /dev/mmcblk1p2 cat /proc/swap //查看交換區是否被成功啟用。重新運行kaldi,終于沒報aborted或bad_alloc()了。
import zlib問題:
ModuleNotFoundError,沒有找到zlib庫,import zlib失敗
先到steps/nnet3/decode.sh中,將stage修改為2。因為steps/nnet3/decode.sh: feature type is raw這一步花費時間實在太長了,而且在第一次測試時通過了,所以直接可以跳過。方便后面的調試。(所有步驟測試都完成后記得改回去。)
Buildroot配置python:
? Target packages --》 Interpreter languages and scripting --》python
(之前配置為python3.7時,使能zlib module無效;現在換成python2.7,能成功通過import zlib)
創建一個test.py:
import zlib print "import zlib ok."python test.py,能正常打印說明配置成功。
結果還是要python3.7的zlib的模塊,不能直接將python2中的zlib.so拷貝。
File "usr/lib/python3.7/gzip.py", line 9, in <module> ImportError: dynamic module does not define module export function (PyInit_zlib)怎么將python3.7編譯出zlib.so鏈接庫???
在output/build/python3.7中的Makefile和configure修改了半天,但每次重新編譯buildroot時卻沒有反應?
buildroot重新編譯問題:
解決:修改Makefile或configure后,還要將.stamp_configured或.stamp_built等刪除,再重新編譯buildroot。
成功解決import zlib問題。
再次運行run.sh
測試成功,不過運行要3分鐘左右,也為難開發板了,只有512MB DDR3,792MHz 主頻。其中的數字和字母的組合好像沒識別出來,可以嘗試使用其它模型(推薦CVTE的模型,正確率高達92%)或自己訓練模型。
因為IMX6ULL的性能遠不如樹莓派4,且在其它嵌入式平臺上配置不如在raspbian上方便,故而在運行時會出很多其它問題。
總結:Imx6ull的性能導致其解碼識別的速度很慢,所以要實際應用到項目用,需要換更高配一些的芯片。
總結
以上是生活随笔為你收集整理的让kaldi在Linux开发板上运行起来~ (测试运行篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JIRA 从低版本升级到高版本(3.6
- 下一篇: 关于使用Vivado在仿真时报错的问题