2017-03-14 3 views
1

디코딩 부분에 대한 자동 음성 인식에서 빔 - 검색 알고리즘에 사용 된 로직을 이해하려고 노력해 왔습니다. 내가 따라하려고 시도한 논문은 First-Pass Large Vocabulary Continuous Speech Recognition using Bi-Directional Recurrent DNNs, Lexicon-Free Conversational Speech Recognition with Neural NetworksTowards End-to-End Speech Recognition with Recurrent Neural Networks입니다. 문제는 알고리즘 뒤에있는 아이디어가 따르기 쉽지 않으며 논문에 제공된 의사 코드에 많은 오타가 있다는 것입니다. 또한 두 번째 논문의 this implementation은 뒤 따르기가 매우 어렵 기 때문에 언급 한 마지막 논문의 this one은 언어 모델을 포함하지 않습니다. 어떤 도움이 정말 이해할 수있을 것이다RNN 출력을 디코딩하는 빔 - 검색 알고리즘

class BeamSearch(object): 
""" 
Decoder for audio to text. 

From: https://arxiv.org/pdf/1408.2873.pdf (hardcoded) 
""" 
def __init__(self, alphabet='" abcdefghijklmnopqrstuvwxyz'): 
    # blank symbol plus alphabet 
    self.alphabet = '-' + alphabet 
    # index of each char 
    self.char_to_index = {c: i for i, c in enumerate(self.alphabet)} 

def decode(self, probs, k=100): 
    """ 
    Decoder. 

    :param probs: matrix of size Windows X AlphaLength 
    :param k: beam size 
    :returns: most probable prefix in A_prev 
    """ 
    # List of prefixs, initialized with empty char 
    A_prev = [''] 
    # Probability of a prefix at windows time t to ending in blank 
    p_b = {('', 0): 1.0} 
    # Probability of a prefix at windows time t to not ending in blank 
    p_nb = {('', 0): 0.0} 

    # for each time window t 
    for t in range(1, probs.shape[0] + 1): 
     A_new = [] 
     # for each prefix 
     for s in Z: 
      for c in self.alphabet: 
       if c == '-': 
        p_b[(s, t)] = probs[t-1][self.char_to_index[self.blank]] *\ 
            (p_b[(s, t-1)] +\ 
             p_nb[(s, t-1)]) 
        A_new.append(s) 
       else: 
        s_new = s + c 
        # repeated chars 
        if len(s) > 0 and c == s[-1]: 
         p_nb[(s_new, t)] = probs[t-1][self.char_to_index[c]] *\ 
              p_b[(s, t-1)] 
         p_nb[(s, t)] = probs[t-1][self.char_to_index[c]] *\ 
              p_b[(s, t-1)] 
        # spaces 
        elif c == ' ': 
         p_nb[(s_new, t)] = probs[t-1][self.char_to_index[c]] *\ 
              (p_b[(s, t-1)] +\ 
              p_nb[(s, t-1)]) 
        else: 
         p_nb[(s_new, t)] = probs[t-1][self.char_to_index[c]] *\ 
              (p_b[(s, t-1)] +\ 
               p_nb[(s, t-1)]) 
         p_nb[(s, t)] = probs[t-1][self.char_to_index[c]] *\ 
              (p_b[(s, t-1)] +\ 
               p_nb[(s, t-1)]) 
        if s_new not in A_prev: 
         p_b[(s_new, t)] = probs[t-1][self.char_to_index[self.blank]] *\ 
              (p_b[(s, t-1)] +\ 
               p_nb[(s, t-1)]) 
         p_nb[(s_new, t)] = probs[t-1][self.char_to_index[c]] *\ 
               p_nb[(s, t-1)] 
        A_new.append(s_new) 
     A = A_new 
     s_probs = map(lambda x: (x, (p_b[(x, t)] + p_nb[(x, t)])*len(x)), A_new) 
     xs = sorted(s_probs, key=lambda x: x[1], reverse=True)[:k] 
     Z, best_probs = zip(*xs) 
    return Z[0], best_probs[0] 

:

이 때문에 일부 누락 된 확률 실패 파이썬 내 구현입니다.

+0

레이블 지정 경로 확률을 지정합니다. 하지만 같은 라벨을 만드는 모든 경로를 합산해야합니다. 의사 코드는 이에 대해 명확하지 않습니다. 나는 빔 검색을 LM으로 구현했다. 아마 이것이 도움이 될 것이다 : https://github.com/githubharald/CTCDecoder – Harry

답변

-1

문제는 A_prev에없는 s_new가있는 블록이 생성 된 새 문자열에 대해 존재하지 않을 확률을 말하는 것입니다. 새로운 문자열의 이전 타임 스텝, 즉 s_new, t-1에 대해 -float ("inf")로 초기화하십시오. try catch 블록을 넣을 수 있습니다. 여기서 p [(s_new, t-1)]가 없으면 -infinity를 사용합니다.

0


-inf 초기화를 사용하여 빔 검색을 구현하고 http://proceedings.mlr.press/v32/graves14.pdf 종이의 ctc_beam_search 알고리즘을 따르십시오 ... 이것은 문자에 대한 p_b의 업데이트를 제외하고는 거의 비슷합니다 ... 알고리즘이 제대로 실행됩니다 ... 초기화가있는 경우에도이 알고리즘이 작동합니다.

A_prev = [''] 
p_b[('',0)] = 1 
p_nb[('',0)] = 0 
for alphabet in alphabets: 
    p_b[(alphabet,0)] = -float("inf") 
    p_nb[(alphabet,0)] = -float("inf") 
for t in range(1,probs.shape[0] +1): 
    A_new = [] 
    for s in A_prev: 
     if s!='': 
      try:     
       p_nb[(s,t)] = p_nb[(s,t-1)]*probs[t-1][char_map[s[-1:]]] 
      except: 
       p_nb[(s,t)] = p_nb[(s,t-1)]*probs[t-1][char_map['<SPACE>']]*pW(s) 
      if s[:-1] in A_prev: 
       p_nb[(s,t)] = p_nb[(s,t)]+pr(probs[t-1],s[-1:],s[:-1],t) 
     p_b[(s,t)] = (p_nb[(s,t-1)]+p_b[(s,t-1)])*probs[t-1][0] 
     if s=='': 
      p_nb[(s,t)] = 0 
     if s not in A_new: 
      A_new.append(s) 
     for c in alphabets: 
      s_new = s+c 
      p_b[(s_new,t)] = 0 
      p_nb[(s_new,t)] = pr(probs[t-1],c,s,t) 
      #print s_new,' ',p_nb[(s_new,t)] 
      if s_new not in A_new: 
       A_new.append(s_new) 
    s_probs = map(lambda x: (x,(p_b[(x, t)]+ p_nb[(x, t)])), A_new) 
+0

(그레이브스에 따른 이름) "ab"와 "a"가 B_hat에 포함되어 있다고 상상해 보라. 그런 다음 y = "a"및 k = "b"이면 y + k = "ab"입니다. 하지만 "ab"에 대한 항목이 이미 있으므로 이전 확률 Pr +가 덮어 쓰기됩니다. 이것에 대해 어떻게 생각하십니까? 또한 여기에 설명 : https://stats.stackexchange.com/questions/273548/multiple-paths-leading-to-same-label-during-ctc-beam-search/ – Harry