Kaldi Tutorial for Korean Model Part 1

enter image description here
Image source
칼디로 한국어 음성인식 구현하기 파트 1

  • 본 튜토리얼은 칼디를 막 시작하는 초보자들을 대상으로 하고 있으므로 칼디를 어느정도 공부하신 분들에게는 적합하지 않을 수 있습니다. 모든 설명은 다음 깃헙에 올려진 run.sh 스크립트를 기준으로 진행되면 추가적으로 궁금한 사항은 칼디 공식 홈페이지나 칼디 구글 헬프를 이용하길 바랍니다.
  • 본 튜토리얼에서 사용하는 스크립트는 맥과 리눅스(우분투) 환경에서 준비해왔기 때문에 그 외에 환경 (예: 윈도우)에서는 제대로 진행되지 않을수도 있습니다. 어차피 칼디를 진행하기 위해서는 리눅스 환경이 갖춰져야 하기 때문에 이 부분은 불편하시더라도 최대한 맞춰주시고 튜토리얼을 진행하여 주시기 바랍니다.
  • 튜토리얼에 사용되는 튜토리얼용 서울말 낭독체 코퍼스는 아래 링크를 통해 받으실 수 있으며, 튜토리얼 진행 도중 훈련에 필수적인 파일들이 제대로 생성되지 않을 상황에 대비해서 몇개의 파일을 미리 생성하여 준비하였으니 필요한 데이터는 그때마다 다운 받으시고 계속해서 진행해 나가시면 되겠습니다.
  • 궁금한 사항이 있으실 경우 개인적인 메일을 보내시기 보다는 아래에 댓글을 다셔서 대부분의 질문이 이 튜토리얼을 보는 모든 분들과 공유되게 해주시기 바랍니다.

데이터 준비


서울말 낭독체 데이터 구하기

  • 훈련을 하기 위해 먼저 데이터를 준비해야 한다. 우리는 국립국어원에서 제공하는 서울말 낭독체를 이용해서 실험을 진행할 것이다. 따라서 다음 링크에서 “small_krs” 폴더를 먼저 받기를 바란다. 혹시 전체 데이터를 다운 받아 훈련을 진행하고자 한다면 다음 링크를 통해 국립국어원으로 접속하여 공지사항을 확인한 후 데이터를 받으면 되겠다.
  • 본 훈련의 빠른 진행을 위해 정제된 데이터를 제공해 주었지만 데이터를 훈련하는 것 만큼이나 중요한 것이 바로 잘 정제된 데이터를 준비하는 것이다. 정제 이전의 서울말 낭독체는 꽤나 많은 수 작업을 필요로 하기에 미리 데이터를 잘 정리하는 작업을 꼼꼼하게 진행해야 할 것이다.
  • 그렇다면 혹시라도 다른 코퍼스 데이터를 이용해 훈련할 경우를 생각해서 데이터 정제작업에 대해 간략히 이야기 하겠다.
    • 먼저 데이터는 음성파일과 그 음성파일이 전사된 텍스트 파일로 이루어져야 한다. 예를들어 “학교 다녀 왔습니다.” 라고 녹음된 음성파일이 있다면 그것에 대한 전사파일이 있어야 한다. 그리고 두 파일의 이름은 확장자명만 제외하고 같아야 한다.
      • test01.wav > “학교 다녀 왔습니다” 라고 녹음된 음성 파일.
      • test01.txt > “학교 다녀 왔습니다” 가 적힌 텍스트 파일.
    • 음성 데이터 자체의 길이는 상관없다. 예를들어 5분정도의 말하기가 담긴 파일이라도 훈련에 사용할 수 있다. 하지만 훈련할 때는 한 문장 단위로 넣어줘야 좋기 때문에, 이왕이면 긴 파일을 문장 단위로 끊어서 한 파일에 한개의 문장만 있도록 하는 것이 가장 이상적인 데이터가 될 것이다. 하지만 그렇다고 꼭 물리적으로 끊을 필요는 없다. 추후에 알게 되겠지만 칼디는 “segments”라는 파일을 통해 이러한 문제를 해결해 주기 때문이다. (아 물론, 이미 한 문장 단위로 데이터가 준비되어 있다면 굳이 이 segments라는 파일을 신경 안써도 된다.)
      • 긴 문장
        • test01.wav: “오늘 학교에 갔어요. 너무 공부를 했더니 피곤하네요.”
      • 개인적으로 좋다고 생각하는 나눈 문장
        • test01.wav: “오늘 학교에 갔어요.”
        • test02.wav: “너무 공부를 했더니 피곤하네요”
    • 위의 데이터를 화자별로 담아서 폴더에 준비해 두도록 하자. 예를들어 여자 a, b와 남자 c, d의 녹음된 파일을 얻었다면 하나의 data라는 폴더를 만들고 거기에 a, b, c, d라는 폴더를 만들어 각 화자별로 녹음된 파일을 담아 준비하도록 하자. 훈련 과정중에 화자별 특징을 제거해주는 과정을 거쳐야 하기 때문이다. (명심해야 할 것은, 우리는 특정 여성의 “안녕”이라는 발화가 다른 특정 남성의 “안녕”과 다르다는걸 훈련시켜서는 안 된다. 둘의 목소리톤과 발화 길이가 다르더라도 무조건 그것은 “안녕”이라고 인식하도록 훈련시키는 것이 우리의 원하는 음성인식 결과물이기 때문이다.)
    • 추가적으로 확인할 사항으로는 음성파일이 제대로 실행 되는지, 텍스트 파일이 음성파일의 발화를 제대로 표기하고 있는지를 확인해 보는 것이다. 가끔 대량의 데이터를 다른 곳에서 받다보면 재생이 안되는 데이터로 인해 훈련 중 에러가 발생하거나(읽지를 못하므로), 전사가 음성파일과 달라서 성능이 낮아지는 경우가 있을 수 있다. 이 외에도 데이터를 정제할 때 고려해야 할 사항들이 많지만 데이터의 특성과 훈련하고자 하는 목적에 따라 정제방식은 달라지기 때문에 본 글에서는 여기까지만 다루도록 하겠다.

필수자료 생성하기

  • wav.scp, utt2spk, text, 그리고 segments는 칼디 훈련에 들어가기전 데이터셋으로부터 추출하는 필수 자료다. 우리는 다운로드 받은 서울말 낭독체로부터 이 필수자료들을 생성하기 위해 krs_prep_data.sh 코드를 이용할 것이다. krs_prep_data.sh을 실행시켜 생성되는 필수 자료들을 열어보고 어떤식으로 구성되어있는지 확인해 보자.
    • wav.scp
      • wav.scp는 오디오 데이터 이름과 그 데이터의 절대경로로 이루어진 파일이다. 여기서 중요한 사실은 오디오 데이터의 이름을 적을때는 확장자명인 “.wav”를 생략해야 하고 데이터의 절대경로를 적을때는 확장자명까지 다 적어줘야 한다는 것이다.
        • [오디오 데이터 이름] [오디오 데이터 절대 경로]
        • fv01_t01_s01 /home/data/train/fv01/fv01_t01_s01.wav
    • utt2spk
      • utt2spk는 발화(utterance)와 발화자(speaker)를 연결해주는 파일이다. 위에서 한 화자가 발화한 모든 오디오 파일을 한 폴더에 담아서 준비하자고 했었는데, 이 과정을 제대로 지켰다면 한 폴더의 이름은 한 화자의 고유 식별이름이 되는것이고 그 폴더에 담긴 각 파일들은 그 화자와 연결될 것이다. 기본적으로 한 폴더에는 여러개의 녹음된 데이터가 있기때문에 첫번 째 줄의 이름은 다양하게 나오는 반면 두번째 줄의 이름은 중복되게 나온다.
        • [오디오 파일 이름] [화자 폴더 이름]
        • fv01_t01_s01 fv01
          fv01_t01_s02 fv01
    • text
      • text는 오디오 데이터 이름과 그 데이터의 발화 문장을 기록한 파일이다. 이 파일에서도 오디오 데이터 이름은 확장자명인 “.wav”를 제거한 상태로 적어야 한다.
        • [오디오 파일 이름] [발화 문장]
        • fv01_t01_s01 기차도 전기도 없었다
    • segments
      • segments는 오디오 파일의 시작과 끝 지점을 알려주는 파일이다. 먼저 오디오 데이터의 시작과 끝을 지정해줄 데이터 이름을 적고 이후에 시작과 끝 시간을 적으면 된다. 각각의 오디오 데이터가 한 문장만 담고 있다면 segments의 한 줄당 한 오디오 데이터 이름과 그 오디오 데이터의 시작과 끝 시간을 적어주면 되지만 이런 경우에는 segments가 굳이 없어도 칼디 내부적으로 한 오디오 데이터가 한 문장을 담는것으로 인식하고 처리한다. 따라서 segments가 필요한 경우는 여러문장을 한 오디오 데이터가 담고 있을 경우 그 문장을 끊어서 인식하고 훈련하기를 원할 때 사용한다.
        • 오디오가 한 문장만 담고 있을 경우: fv01_t01_s01이라는 문장은 “기차도 전기도 없었다” 라는 한 문장만을 담고 있으며 이 문장은 0초에 시작하여 4.93초에 끝난다. 시각적으로 잘 보이도록 일부러 1, 3번째 컬럼에 볼드체를 주었다.
          • [오디오 파일 이름 시작] [오디오 파일 이름 끝] [시작 시간] [끝 시간]
          • fv01_t01_s01 fv01_t01_s01 0 4.93
        • 오디오가 여러 문장을 담고 있을 경우: st01_f01_v01이라는 문장은 “어제부터 하루종일 비만 내리더라구요 그래서 너무 우울했어요” 라는 두 가지 문장을 담고 있고, 첫 번째 “어제부터 하루종일 비만 내리더라구요” 문장은 0초에 시작해서 6.23에 끝나고, 두 번째 “그래서 너무 우울했어요” 문장은 7.01초에 시작해서 11.36초에 끝난다. segments에 아래처럼 표시함으로써 칼디는 한 오디오 파일에서 두 가지 문장을 추출해서 훈련한다. 시각적으로 잘 보이도록 일부러 1, 3번째 컬럼에 볼드체를 주었다.
          • [오디오 파일 이름 시작] [오디오 파일 이름 끝] [시작 시간] [끝 시간]
          • st01_f01_v01 st01_f01_v01 0 6.23
          • st01_f01_v01 st01_f01_v01 7.01 11.36
  • 위 필수자료들이 만들어졌다면 이젠 그 파일들을 통해 2가지 파일을 더 생성해야 한다. 바로 textraw와 spk2utt인데 이 두 파일들은 각각 text와 utt2spk을 통해 쉽게 만들어 낼 수 있다. 자세한 생성법은 krs_prep_data.sh 코드를 참고하면 된다.
    • textraw
      • textraw는 text에서 추출하는 정보로 첫번째 줄에 입력된 오디오 데이터 이름만 제거하여 발화문장만 남긴 파일로서 위에서 언급한 text 파일에서 textraw를 생성한다면 다음과 같은 모습을 갖게 된다.
        • [발화 문장]
        • 기차도 전기도 없었다
      • text를 가지고 아래와 같이 bash command line에 입력하면 textraw가 생성된다.
        $ cat text | awk '{$1="";print $0}' | sed 's/^ //g' > textraw
        
    • spk2utt
      • spk2utt은 utt2spk의 반대 맵핑인 파일로 발화자에 발화문장들을 연결해주는 파일로 다음과 같은 모습을 갖고 있다.
        • [화자 폴더 이름] [오디오 파일 이름들]
        • fv01 fv01_t01_s01 fv01_t01_s02
      • utt2spk을 가지고 아래와 같이 bash command line에 입력하면 spk2utt가 생성된다.
        $ utils/utt2spk_to_spk2utt.pl utt2spk > spk2utt    
        
  • 여기까지 잘 따라왔다면 (파일들을 잘 생성했다면) 훈련을 위한 준비가 1차적으로 끝났다. 만약 위에서 생성된 각각의 필수 자료들이 어떤식으로 구성되었는지 제대로 이해했다면 다른 코퍼스를 이용한 훈련도 가능해진다. 다음으로 dictionary와 관련된 파일들을 생성하는 과정에 대해 알아보도록 하자.

dictionary 생성하기

  • dictionary는 데이터를 훈련할 때 어떠한 음소(phoneme)를 가지고 훈련할지에 대한 정보를 담고 있으며, 이 정보를 이용해서 단어들에 대한 발음 정보를 구성한다. dictionary에 정의되는 음소들은 실제 훈련과정속에서 사용되는 정보이므로 한 번 설정하여 훈련을 시작하면 추후에 바꿀 수 없는 정보가 된다. 따라서 추후에 음소들에 대한 구성을 바꾼다면 훈련 또한 새롭게 진행되어야 한다.
  • 음소는 무음과 유음이라는 큰 2가지의 파트로 나뉘어진다. (물론 연구자에 방향에 따라 이 파트도 세분화 할 수 있으며 필자는 4가지 분류까지 나눠서 실험을 진행해 본 적이 있다.) 그리고 그 2가지 파트에 존재하는 음소를 이용해서 textraw에 존재하는 모든 문장의 단어들을 음소로 구성된 발음열로 변환시킨다. 이 때 중요한 것은 문자 그대로의 발음을 기록하는 것이 아니라 인간이 실제로 내뱉는 발음을 기록해야 한다는 것이다. 왜냐하면 우리는 소리를 훈련하기 때문에 단어 그대로의 발음보다(예, 권력: 권력) 실제로 음운규칙이 적용된 발음으로 (예, 권력 : 궐력) 기록해야 제대로된 훈련을 진행할 수 있기 때문이다.
  • 보통 dict라는 폴더를 생성하여 dictionary 관련 파일들을 담는데 그 관련 파일들은 다음과 같다.
    • nonsilience_phones.txt
      • 훈련에 사용할 유음(nonsilence) 종류를 담은 파일로 한 줄에 한 음소를 적는다. 유음의 경우 30 ~ 50개 사이의 음소셋으로 구성된다.
        • [훈련에 사용할 유음 음소]
        • p0
    • silence_phones.txt
      • 훈련에 사용할 무음(silence) 종류를 담은 파일로 한 줄에 한 음소를 적는다. 무음의 경우 1-5개 사이의 음소라기 보다 특정 기호나 단어로 구성되며, 보통 sil, < SIL >, < UNK >를 사용하여 무음구간을 표현한다.
        • [훈련에 사용될 무음]
        • sil
      • 무음을 훈련하는 것은 유음과 다르다. 예를들어 웃음소리와 말 안하는 두 가지를 무음으로 훈련한다면 말 안하는 것과 웃음소리를 유음에서처럼 g2p로 변환할 수 없다. “꺄르르르”, “큭크큭”, “아하하하하” 등등 다양한 웃음을 어떻게 별개로 따질수 있겠는가? 그것들은 다르게 들릴지라도 웃음이라는것은 동일하고 어떤 의미를 갖는 것은 아니다. 따라서 다양한 웃음소리는 < LAUGH >로 통일시키고, 조용히 있는 부분을 “< SIL >”로 통일시켜서 훈련하는게 더 올바른 방향이라 할 수 있다.
    • optional_silence.txt
      • 이 무음 파일의 경우 단어와 단어 사이에 선택적으로 들어가는 휴지 구간에 대해 어떤 음소셋으로 표현할지를 정하는 파일이다. 한개의 음소셋을 넣어주면 되지만 이것도 무음을 표현하는 것이기에 음소라기 보다 위와 같은 특정 기호나 단어로 구성한다.
        • [훈련에 사용할 무음]
        • sil
    • lexicon.txt
      • 단어들과 그 단어들의 음소정보를 저장한 파일로, 칼디는 이 파일 정보를 통해 각 단어들을 음소셋으로 변환하여 AM(Acoustic Model) 훈련을 진행한다.
        • [단어] [단어 음소]
        • 끝까지 kk xx tf kk aa c0 ii
    • lexiconp.txt
      • lexicon.txt 파일에 확률값이 삽입 된 파일로 한 단어가 표기된 음소셋으로 읽힐 확률에 대해 기록하고 있다. 한국어의 경우 표기상의 단어가 다양한 형태로 읽히는 경우가 적어서 보통 1.0이라는 100퍼센트 확률을 부여하여 lexiconp.txt를 기록하지만 영어의 경우 한 단어가 다양한 발음으로 읽힐 수 있기 때문에 이 확률값을 적용하는게 의미를 갖는다. 예를들어 tomato의 경우 영어는 “도마도” 혹은 “토메이도”라는 2가지의 경우로 읽힌다. 이 때 “도마도”가 “토메이도”보다 더 자주 발음한다면 “도마도”의 경우 0.7의 확률값으로 “토메이도”의 경우 0.3의 확률값을 부여할 수 있을 것이다. 이러한 확률값은 존재하는 데이터를 통해 추출할 수 있지만 한국어의 경우 편의상 1.0으로 처리하는 경우가 대부분이다. 영어의 경우도 저러한 정보를 뽑기 힘들 경우 1.0으로 맞출수 있으며 이로 인해 훈련에 큰 지장은 일어나지 않는다.
        • [단어] [확률] [단어 음소]
        • 끝까지 1.0 kk xx tf kk aa c0 ii
      • 모든 단어에 대해 1.0으로 확률값을 부여할 예정이라면 lexicon.txt만 가지고 있어도 된다. 왜냐하면 prepare_lang.sh을 돌릴 때 자동적으로 lexiconp.txt를 생성해 주기 때문이다. 혹시라도 미리 생성하고자 한다면 아래의 커맨드 라인을 이용하면 쉽게 생성할 수 있다.
        $ perl -ape 's/(\S+\s+)(.+)/${1}1.0\t$2/;' < lexicon.txt > lexiconp.txt
        
    • extra_questions.txt
      • 이 파일은 추후 훈련을 통해 tree라는 파일을 생성할 때, 칼디 내부적으로 폰을 찾아가는 과정을 “물어보는 방식으로” 진행하는 데 그 때 필요로 하는 파일이다. 이 파일에 대해서는 추후에 설명하는 것이 맞는듯 하여 현재 단계에서는 설명을 생략하겠으며 그냥 아무것도 적지 않은 공백 상태로 파일을 생성해 두면 prepare_lang.sh 스크립트가 알아서 처리할 것이다.
Hyungwon Yang

댓글

  1. krs_prep_data.sh 실행시킬 때 argument를 어떻게 줘야 되나요?
    Three arguments should be assigned.
    1. Source data.
    2. The folder generated files saved.
    라고 뜹니다!

    답글삭제
    답글
    1. 제가 마이너한 디테일을 항상 깜빡하고 수정을 못하네요 ^^;; 2가지 arguments만 넣어주면 되는데(three는 오타입니다) 하나는 코퍼스 데이터로 k1 스크립트에서 보면 $source/$set을 첫번째 인자로 받는데, 링크에서 small_krs를 다운받으셨다면 그 내부의 train과 test를 for loop을 돌면서 받는걸 확인하실수 있습니다. 두번째는 스크립트를 통해 생성된 파일들을 저장할 폴더를 말하는데 k1에서 보다시피 data/$set으로 되어있는데 이게 각각 for loop을 돌면서 data/train과 data/test를 만들고 여기에 각각 생성된 파일들을 저장합니다.

      삭제
    2. 제가 이해를 잘 못해서 그런데
      ./krs_prep_data.sh [small_krs위치] [저장할 폴더] 이렇게 실행시켜주면 되나요?

      삭제
    3. krs_prep_data.sh 스크립트를 실행할 때 current path가 ./k1 이라면 local/krs_prep_data.sh 하고 2가지 인풋 적어주셔야 되요. 실행 스크립트들이 ./local에 저장되어 있거든요.

      삭제
  2. k1 스크립트 run.sh 실행시키면 data폴더 안에 lang , local, tran, test 폴더는 생성되는데
    중간에
    IOError: [Errno 2] No such file or directory: './local/rulebook.txt'
    에러가 뜨는데 어디가 문제인가요??

    답글삭제
    답글
    1. run.sh 스크립트는 ./k1 디렉토리를 current path로 잡은 상태에서 돌려줘야 합니다. 혹시라도 k1 내부에서 스크립트들을 개별적으로 실행시킬 때, ./k1이 아닌 ./k1/data나 ./k1/local에서 바로 돌리고 계신다면 아마 스크립트의 위치를 못찾고 위와같은 에러를 발생시킵니다. 혹시라도 ./k1에서 run.sh을 실행시켰는데도 불구하고 에러가 발생한건가요? 그리고 만약에 ./local/rulebook.txt가 존재하지 않는다면 알려주세요

      삭제
  3. ./k1 에서 run.sh 실행 시켰는데 위와같은 에러가 발생했습니다.
    그리고 k1/data/train 과 k1/data/test 폴더 안에 text를 실행시켜보면 fv04_t02_s87 없다 이거 1줄 밖에 없는데 맞는건가요?

    아 그리고 제가 바꾼 부분은
    krs_prep_data.sh 에서
    # Make a spk2utt file.
    /home/kjs/kaldi_recipes/k1/utils/utt2spk_to_spk2utt.pl $save/utt2spk > $save/spk2utt
    경로설정 부분에서 /home~~ 처럼 절대경로로 바꿨고

    run.sh 에서

    kaldi=/home/kjs/kaldi
    # Source data: Where is your source (wavefile) data directory?
    source=/home/kjs/kaldi_recipes/k1/small_krs

    경로 설정 수정하고 위에서 1로 바꾸라고 하신 부분만 수정했습니다.

    답글삭제
    답글
    1. 저도 돌려보고 1줄밖에 생성이 안되는걸 보고서 코드를 다시 뜯어봤습니다. segment 만드는 부분에 버그가 있었더군요. 지금 다시 해보고 잘 되는걸 확인했습니다. 리포트 감사해요! 지금 깃헙 다시 pull하고 실행해 주시기 바랍니다.

      삭제
    2. 좀전에 해봤는데 잘 됩니다!! 감사합니다!
      혹시 이 이후의 훈련과정과 디코딩 부분은 언제쯤 포스팅 하시나요??

      삭제
    3. 최대한 빨리 올리도록 노력중입니다. 하지만 진행하는 연구가 많아서 언제라고 딱 말씀드리기는 힘들겠네요.

      삭제
    4. 감사합니다!! 닦달하는거 같아서 죄송합니다.ㅠ
      항상 고생많으십니다!!

      삭제
  4. 안녕하세요! 저번에 큰 도움 받았습니다.

    위의 글을 읽고 krs_prep_data를 실행 시켜보았는데요,

    segment의 오디오 이름이 동일하게 나타났었습니다.

    그래서 wav_snt부분을 segment를 생성하는 코드 사이에 넣고 get_snt에서 txt를 sed 명령어를 통해 제거 해주었습니다.

    확인 부탁드립니다.

    답글삭제
    답글
    1. 이전 코드를 가지고 있어서 그랬던거 같습니다. git hub을 확인 해보니 정상적으로 적혀 있네요!

      추가적으로 Train Monophone 부분에서 split_scp.pl에서 input output 문제가 발생하는 것 같습니다. 해결 방법이 있을까요?

      Refusing to split data because number of speakers 2 is less than the number of output .scp files 3 at utils/split_scp.pl line 114, <I line 137.

      위는 에러 코드 입니다.

      삭제
    2. Data split 하는 부분에서 nj라는 부분이 있어서 저의 경우에는 3개로 나뉘었던거 같습니다.

      nj를 3으로 하고 할 수 있는 방법을 찾아봐야 겠습니다.

      삭제
    3. train하는 폴더 내에 화자별 폴더가 2개 있다면 number of jobs는 1혹은 2로 해주셔야 됩니다. 2개의 화자를 3으로는 분할할 수 없으니까요. train하고자 하는 폴더 내에 3명의 화자폴더를 가지고 있으시다면 number of jobs를 1혹은 3으로 해주시길 바랍니다.

      삭제
    4. 작성 하신 코드를 기반으로 kaldi에 대한 이해를 하는데 도움이 많이 되었습니다. 정말로 감사합니다.

      삭제
    5. 도움이 되었다니 다행입니다

      삭제
  5. 후반에 그림이 있었던 걸로 기억하는데 수정 하신건가요!??

    답글삭제
    답글
    1. 네 올린 글은 필요에 의해 간혹 수정을 하게됩니다.

      삭제

  6. lexicon을 만드는 과정에서 '개울로'라는 단어의 발음에 대한 부분이 empty하게 나오네요. rulebook.txt파일을 살펴 봐야 될까요?

    답글삭제
    답글

    1. 다시 돌려 보았을 때 랜덤하게 몇몇의 단어들이 empty 하게 나오는 군요 조금 더 보고 다시 덧글을 달도록 하겠습니다.

      삭제
    2. 직접 스크립트를 작성하던 중 숫자 3 하나를 수정을 안하여 생긴 문제였습니다.

      삭제
    3. 네 문제를 찾으셨다니 다행입니다.

      삭제
  7. 작성자가 댓글을 삭제했습니다.

    답글삭제
  8. run.sh 실행시에
    run.sh: 119: .: path.sh: not found
    오류를 내뿜습니다.
    run.sh 에서 kaldi 하고 source 경로는 지정했구요

    그리고 파트2는 언제쯤 볼수있을까요??

    답글삭제
    답글
    1. run.sh 파일 경로를 자체적으로 설정하면 해결이네요..
      다른문제는 다 해결했는데 prepare_lang.sh 해당 파일은 어떻게 실행시켜야하나요? 옵션을 어떤거를 줘야하는지요 ㅜㅜ

      삭제
    2. 현재 존재하는 스크립트를 그대로 따라하신다면 문제없이 돌아가도록 설정되어있는 상태입니다. prepare_lang.sh을 열어서 어떤 인풋을 받는지 직접 확인해 보시길 바라며 본 스크립트를 실행하고자 할 때 특별한 옵션을 줄 필요는 없습니다.

      삭제
    3. 혹 run.sh에서 데이터 경로를 어떻게 지정하셨는지요
      KALDI_ROOT 는 K1 디렉토리로 지정하였고
      DATA_ROOT 는 dict폴더를 지정해야하는지 아님 필수자료를 지정해야하는지 잘 모르겠네요 ㅜㅜ

      삭제
    4. KALDI_ROOT와 DATA_ROOT를 언급하시는것 보니 각각 kaldi와 source변수명을 말씀하시는것 같습니다. echo하는 라인의 변수는 따로 건들면 안되시구요 kaldi는 칼디 설치하신 칼디 경로를, source에는 위 튜토리얼에서 제공하는 폴더를 다운받으시고 저장해놓으신 경로를 적으시면 됩니다.

      삭제
    5. 말씀하신 kaldi에 칼디 설치하신 경로란 kaldi 공식사이트에서 제공하는 kaldi 를 말하시는건가요? 아님 해당 듀토리얼에서 제공하는 k1 인가요

      삭제
    6. 칼디 공식사이트에서 제공하는 칼디를 말하는 것입니다.

      삭제
    7. run.sh 실행시에

      KALDI_ROOT: /home/pi01/Kaldi-master
      DATA_ROOT: /home/pi01/record/small_krs
      run.sh: 18: [: no: unexpected operator
      Please check your input arguments. Only kaldi directory path is needed.

      18번 라인은 source data 가 표기된 라인인데..
      제가 지정을 잘못한건가요?

      삭제
    8. KALDI_ROOT와 DATA_ROOT 변수는 직접 지정하는 변수가 아닙니다. 18번 라인은 source 변수를 지정하는 곳인데 어떻게 지정하였기에 저런 에러가 뜨는지는 모르겠습니다. source에는 path만 들어가야합니다. '['과 같은 오타가 들어가 있는지 확인해 주세요. 코드를 실행하기 전 블로그의 내용들과 코드에 적힌 코멘트들을 다시 한번 읽어보시고 실행해 주시기 바랍니다.

      삭제
    9. run.sh 에서
      KALDI_ROOT: /home/pi01/Kaldi-master
      DATA_ROOT: /home/pi01/record/small_krs
      위와같이 입력해둔 상태인데.. 잘못된것인지...

      삭제
    10. run.sh에서 몇번째 라인의 변수를 변경하신건가요?

      삭제
  9. 안녕하세요. 머신러닝을 이용한 음성인식 기술에 관심을 가지고 있는데요. 기본적인 내용을 이해하는데 공유해주신 글이 큰 도움이 되었습니다. 좋은 글 감사합니다. ^^

    갑자기 문의를 드려도 괜찮을지 좀 조심스러운데요. 머신러닝에 필요한 음성 raw 데이타의 경우 녹음실에서 녹음을 한 완전한 clean 버전이 아니라 집이나 사무실 정도 생활 노이즈 환경에서 핸드폰/PC를 이용해 녹음한 데이타도 음성 데이타로 사용이 가능할까요?






    답글삭제
    답글
    1. 물론 가능합니다. 하지만 훈련결과는 깨끗한 데이터로 훈련 했을 때보다 안 좋을수 있습니다. 따라서 녹음하실때 최대한 외부와의 소리가 차단된 곳에서 마이크를 이용한 녹음을 추천드립니다. 마이크 구매 및 사용이 부담스럽다면 애플의 이어팟을 추천드립니다.

      삭제
    2. 갑작스런 질문에도 친절히 답변해 주셔서 감사합니다. ^^

      삭제
    3. 사실 저는 ASR을 위한 음성 데이타 수집 방법에 대해 관심이 더 많은데요.
      한 문장을 훈련하기 위해 해당 문장 음성데이타가 얼마나 필요할까요?
      예를 들어 위에 제시하신 "오늘 학교에 갔어요" 라는 문장을 훈련하기 위해 몇명의 사람이 몇번 반복한 음성 데이타가 필요한지 궁금합니다.
      또 녹음된 데이타 후처리를 할 때 프레임단위로 세밀한 편집이 필요한지 아니면 사람이 들어서 해당 문장의 시작과 끝이 명확한 정도로 사용이 가능할까요?
      관련 분야에 지식이 적다보니 초보적인 질문을 드리게 되었네요. ^^


      삭제
    4. 좋은 성능의 ASR 결과를 원하신다면 다양한 화자의 다양한 발화패턴이 담긴 장시간의 음성데이터가 필요합니다. 단순히 말해서 데이터 상태가 좋다는 것을 가정할 경우 무조건 많은수록 좋습니다. 하지만 단지 훈련을 위한 연습이 목적이시라면 단 하나의 발화자료로도 훈련은 가능합니다. 질문자께서 생각하시는 "이정도면 원하던 훈련결과다"의 기준을 알수가 없지만 초반에 연습을 목적으로 하고자 하시는 경우라면 10명의 발화자를 모집해서 한명당 20초내외 길이의 20문장을 녹음하여 훈련을 해보고 성능을 직접 체험해보면 어떨까요? 그리고 음성 데이터의 후처리는 초반에 생각하실 문제는 아니고 추후에 음성인식의 성능을 올리기위해 고려해보실 사항입니다. 따라서 세밀한 편집작업 혹은 시작과 끝이 명확한지 하는 세부적 사항은 크게 고려치 않으셔도 됩니다.

      삭제
  10. 다음은 이상현님이 메일을 통해 질문하신 내용입니다.
    안녕하세요 음성인식에 관심있는 학생 이상현입니다.
    양형원님의 블로그에서 guit에 올라와 있는 k1을 공부하고자 kaldi를 돌리고 있습니다
    제가 지금 kaldi에 대해서 처음이라 run하면서 문제가 많이 발생하고 몇일 고민 끝에 궁금해서 이렇게 메일을 쓰게 되었습니다.
    먼저 run.sh에서 kaldi path와 small_krs path를 지정하였습니다.
    그리고 data 부분을 전체 1로 두고
    training 부분도 전체 1, Decoding 부분도 1로 두고 run.sh를 실행하였습니다.
    잘 가다가 DNN 부분에서
    run.pl: job failed, log is in exp/tri4/egs/log/create_train_subset.log
    Error detected while creating train/valid egs 에서 에러가 발생했는데 혹시 해결할수 있는 조언을 해주실 수 나요?

    감사합니다.

    답글삭제
    답글
    1. 다음은 이상현님께서 보내주신 에러 관련 로그파일을 확인한 뒤 저의 답변입니다.
      로그파일 잘 확인해 보았습니다.
      로그파일에 보면 “Applied transform to 0 utterances”, “Applied cepstral mean normalization to 0 utterances” 와 같은 기록이 보일겁니다.
      dnn을 진행하기에 앞서 egs 파일들을 만드는 과정중에 train 쪽에서 egs 파일을 못만들었고 그게 0 utterances 라는 로그에 나타났습니다.
      dnn 훈련의 경우 보통 적어도 10시간 분량의 데이터를 가지고 훈련을 하는데 그래야만 dnn으로 훈련한 의미가 생기기 때문이죠. 그 이하의 데이터는 훈련이 무의미합니다.
      현재 칼디 dnn의 경우 데이터가 적으면 train용과 valid용 데이터셋을 분리하는 과정중에서 충분한 데이터를 뽑지못해 에러가 발생합니다.
      즉 제가 제공해드린 small_krs로는 칼디에서 구현한 dnn훈련을 못한다는 의미죠.
      발생한 에러는 자연스러운 것이니 크게 걱정 안하셔도 될 것 같습니다.
      나중에 데이터를 많이 모으게 되시면 dnn을 돌려보시길 바라며 현재는 tri3모델을 가지고 디코딩 하는 것으로 마무리 지으시면 됩니다.

      삭제
  11. 위 글에서 언급된 내용은 아니지만 음성인식에 관한 질문을 드리고 싶습니다. 질문이 좀 길 수 있는데, 혹시 메일을 통해서 질문드려도 되는지요? 가능하다면 메일주소를 알고싶습니다. 좋은 글 감사합니다.

    답글삭제
    답글
    1. 네 가능합니다. hyung8758@gmail.com 입니다.

      삭제

  12. 오랜만에 글을 남기네요, 주어진 rule book이 정말 귀중한 자료라는 것을 다시 한번 깨닫게 되어 글을 남깁니다. 감사합니다.

    답글삭제
    답글
    1. 네 g2p 과정은 중요한 문제입니다. 현재 rulebook은 테스트 버전이라서 연구자분께서 추후에 더 추가하셔야 할 부분이 많을 겁니다. 그리고 현재 rulebook은 테스트 버전이긴 하지만 저희 연구소의 중요한 자산이기도 해서 다른 분들과의 공유는 자제 부탁드립니다^^

      삭제
  13. 안녕하세요. 올려주신 튜토리얼 덕분에 칼디를 이해하는데 많은 도움을 받았습니다. 감사합니다. 그리고 지금 github에 올라간 버전은 rulebook.txt를 없애고 lexicon.txt를 남겨두신 것 같은데 맞는지요? 나중에 제가 직접 다른 corpus를 이용하여 학습을 시킬 때 사용하셨던 rulebook을 참고하고 싶은데 혹시 가능할까요? 일부분만 보내주셔도 많은 도움이 될 것 같습니다. 제 이메일 주소는 hjbae.astro@gmail.com 입니다. 감사합니다.

    답글삭제
    답글
    1. 안녕하세요. 현재 저희 랩에서 개발한 rulebook의 경우 배포 제한을 결정한 상태입니다. 따라서 더이상 제공하지 않고 있습니다. 그리고 본 튜토리얼의 목적은 어디까지나 많은 분들이 kaldi를 쉽게 배울수 있도록 돕고자 하는 것입니다. 따라서 본 튜토리얼을 통해 어느정도 칼디를 이해하셨다면 그 다음 스텝은 스스로 연구를 해보시길 바랍니다.

      삭제
    2. 답변 감사드립니다! 그럼 연습하다가 궁금한게 생기면 또 찾아오겠습니다~ :)

      삭제
    3. rule은 국립국어원에 정의된 발음규칙을 참고하시거나, google scholar에 관련 논문 검색을 하시면 많은 정보를 얻으실 겁니다. 질문은 늘 환영합니다.

      삭제
  14. 작성자가 댓글을 삭제했습니다.

    답글삭제
  15. 안녕하세요. 공개해주신 kaldi_tutorial 을 통해 kaldi 기반 음성인식에 대한 이해에 많은 도움을 받고 있습니다.
    sh run.sh 를 통해 train 을 성공적으로 완료하였습니다. 그런데, run.sh 를 보면 training 뿐아니라, decoding 과정도 처리하는 것으로 보이는데, small_krs 에 있는 test 데이타들에 대해서 kaldi_tutorial 을 통해 훈련된 model 로 디코딩하여 음성인식된 text 들은 어디서 확인할 수 있는지요?
    고맙습니다.

    답글삭제
    답글
    1. 예를들어 tri3에 대한 디코드를 보고싶다면 exp/tri3/decode/scoring_kaldi/wer_details/per_utt를 확인하시면 됩니다. 거기서 ref는 정답지고 hyp는 asr결과입니다.

      삭제
    2. 친절한 답변 감사드립니다. 고맙습니다.

      삭제
  16. 박영수씨로부터 질문댓글이 달렸다는 알림이 왔는데 막상 와보니 없어서 제가 대신 글을 등록합니다.
    안녕하세요! 현재 음성인식에 공부를 막 시작해보려고 하는 한 대학생입니다. 너무 좋은 튜토리얼에 감명받았습니다. 제가 궁금한게 있는데 질문좀 해도 될까요???!
    음성 인식에는 음향 모델과 언어 모델이 있다고 들었습니다. 만약 이렇게 kaldi로 구현을 한다면 어떤 모델이 완성되는 건가요???? 두가지 모델이 전부 완성되는 형태인가요??ㅠ 죄송합니다 기초가 모자라서.....

    답글삭제
    답글
    1. 맞습니다. 칼디 음성 인식은 음향 모델과 언어 모델의 조합으로 이루어집니다. 칼디를 통해 데이터를 훈련하게 되면 각각 음향 모델과 언어모델이 만들어 지게 됩니다. 자세한 사항은 튜토리얼상의 코드를 돌려보신다면 언어 모델과 음향 모델의 결과물을 확인하실 수 있으실 겁니다.

      삭제
  17. 안녕하세요. 본 블로그를 통해 많은 도움을 받고 있는 대학생입니다. 튜토리얼 대로 진행하는데에는 성공한 것 같습니다만, 기초가 부족한지라 생성되는 파일들이 각각 어떤 역할을 하는지 잘 모르겠네요.. 음향모델은 어떤 파일이고 언어모델은 어떤 파일인건가요?
    그리고 학습시킨 모델을 응용해보고 싶은데 어떻게해야할지 모르겠습니다.
    예를 들어 학습시킨 모델에 제가 원하는 한국어 음성mp3파일을 던져서 읽을 수 있는지를
    시험해 보고싶은데 어떻게 해야할까요?
    조언 부탁드립니다 ㅠㅜ

    답글삭제
    답글
    1. run.sh 상에서 Language Modeling 영역을 실행해서 생성되는 파일들이 언어모델과 관련된 파일들이라 볼 수 있고 여기엔 lm.arpa, G.fst 등이 있습니다. 그리고 Train & Decode 영역을 실행하여 생성되는 파일들이 음향모델과 관련된 파일들이라 볼 수 있으며 여기엔 final.mdl, tree 등이 있습니다. 사실 칼디는 엄청나게 크고 작은 학문분야를 합친 거대한 프로그램입니다. 따라서 각 생성된 파일들이 무엇이며 어떤 역할을 갖는지 알고자 한다면 그 파일의 목적을 이론을 통해 학습하셔야 합니다. 예를들어 언어모델의 경우 ngram 모델, information theory 등과 같은 개념을 학습하셔야 이해할수 있습니다. 급하게 생각하지 마시고 차근차근 하나씩 공부해 보시면 어떨까요? 생각보다 많고 유익한 정보가 인터넷상에 존재합니다. 그리고 mp3 파일을 통해 시험을 해보고 싶으시다면 decoding 영역쪽 코드를 열어보시고 이해하셔야 사용가능할 것입니다. (답글로 적기에는 힘들듯하네요) 그리고 실시간 음성인식을 테스트 해보고 싶으시다면 제 깃헙의 Korean_ASR을 다운받으셔서 테스트 해보시면 됩니다.

      삭제
    2. 조언 감사드립니다 ㅜㅜ Korean_ASR을 이용하여 원하는 wav파일을 읽는데에 성공했습니다. test 음성파일은 완벽하게 알아듣는데, words.txt 에 있는 단어들을 조합하여 TTS프로그램으로 임의로 만든 wav 파일을 넣어보니 알아듣지를 못하네요. 그럼 인식률을 높이기 위해서는 한국어 데이터셋을 더 구하고 run.sh을 응용, 트레이닝을 여러번 돌려서 거기서 나온 final.mdl 등등을 data/diy 안에 배치하고 run_asr.sh을 실행시키면 될까요...?
      허접한 질문을 드려 죄송하네요 ㅜㅜ
      그리고 GStreamer 와 yaml 파일을 이용한 kaldi 예제도 해본적이 있는데
      그쪽은 yaml 파일안에 final.mdl, HCLG.fst 등의 경로를 기재해 놓고
      사용하던데, 여기에 제가 트레이닝 시킨 파일을 넣어서 실행해도 무방한 것인지 궁금하네요

      삭제
    3. Korean_ASR 내부 diy 폴더에 언급하신 파일들을 넣으면 되지만 현재는 dnn 모델 훈련이 끝난 뒤에 나온 파일들을 넣어야만 작동되도록 셋팅되어있습니다. 이 부분도 꼭 dnn이 아닌 다른 모델로 훈련하여 나온 결과물에 대해서도 디코딩이 되도록 수정해야되는데요. 이 부분 고친다면서 계속 못고치고 있었네요^^;; 조만간 업데이트 하면 사용가능하지만 현재는 불가능 합니다.

      삭제
    4. 친절한 답변 너무 감사드립니다 ㅠㅜ dnn으로 훈련시키기 위해 run.sh에서 dnn관련 주석처리된 부분의 주석을 제거했는데 dnn 훈련할때 에러가 발생하네요. nnet-get-egs 에서 에러가 발생하며 프로세스가 중지되는데 현재 dnn 훈련에 제약이 있는 상태인건가요?

      삭제
    5. 본 칼디 튜토리얼에서 제공하는 데이터가 너무 작다보니 dnn에서는 훈련중 에러가 발생할 겁니다. 더 많은 데이터를 준비하셔야만 dnn이 작동할 겁니다.

      삭제
    6. 국립국어원에서 제공하는 서울말 낭독체를 다운로드 하여, 데이터를 550개 정도로 늘려서 dnn 훈련을 시도해봤는데 실패했습니다. dnn 훈련을 위해서는 대략 얼마나 더 데이터를 준비해야 하는걸까요?

      삭제
    7. 저의 경우 서울말 낭독체 데이터를 전체 사용하였을 때 dnn 훈련이 진행되었습니다. 하지만 데이터상의 정제방식이나 그 이외에 여러가지 방식 차이로 데이터 시간상의 차이가 발생할수 있습니다. 먼저 데이터 시간을 뻥튀기 해보세요. 다양한 노이즈를 섞어서 데이터를 부풀리는거죠. 만약 이 방법이 번거롭다면 dnn 옵션을 수정해야할 것 같습니다. dnn 훈련을 진행할 때 get_egs.sh에서 데이터를 나누는데 여기서 num_utts_subset이 300으로 되어있을 겁니다. 이 수치를 줄여서 해보세요.

      삭제
  18. 안녕하세요 궁금한점이 있어서 댓글을 남깁니다.
    lexicon을 만들어 보려고하는데 '삶'과 '삼' 같은 경우의 발음이 같은 코드 부여는 어떻게 하시나요?
    장음 단음을 나눠 부여해보려 생각했다가도 그걸 적용했다가는 전체를 바꿔야할거 같아서...

    답글삭제
    답글
    1. 삶과 삼의 경우는 같은 발음이기때문에 발음사전인 lexicon에도 동일하게 들어갑니다. 실제로 사람들이 둘을 구분하기 위해 장음 단음을 사용하는 경우가 거의 없기 때문에 그렇게 안하셔도 됩니다. 대신 문맥을 통해 그 둘을 구분하겠죠? "계란을 삶다" 라는 문장과 "그 사람을 며느리로 삼다"와 같은 문장이 언어모델에 잘 훈련되어 있다면 디코딩시 문제가 없을 겁니다. 이렇게 잘 훈련되었다면 누군가가 "며느리를 삼다" 라는 말을 했을 때 내 모델이 "며느리를 삶다" 라는 식으로 위험하게(?) 디코딩 하지 않을 겁니다.

      삭제
  19. 작성자가 댓글을 삭제했습니다.

    답글삭제
  20. 작성자가 댓글을 삭제했습니다.

    답글삭제
    답글
    1. 칼디의 전사규칙이라면 어떤것을 이야기 하는 것인가요? text 파일의 전사를 말하는거라면, 칼디 내에서 규정한 전사규칙은 없고 데이터를 어떻게 준비해야한다는 포멧은 본 글에 언급한 wav.scp, text, utt2spk 등이 있습니다.

      삭제

댓글 쓰기

이 블로그의 인기 게시물

Korean Forced Aligner: 한국어 자동강제정렬

Kaldi Tutorial for Korean Model Part 4