CTCDecode é uma implementação do CTC (Classificação Temporal do Connectionista) Decodificação de Pytorch. O código C ++ emprestou liberalmente do DeepSpeech do Paddle Paddles. Inclui suporte de goleador swappable que permite a pesquisa padrão do feixe e a decodificação baseada em Kenlm. Se você é novo nos conceitos de pesquisa de CTC e feixe, visite a seção de recursos onde vinculamos alguns tutoriais explicando por que eles são necessários.
A biblioteca é amplamente independente e requer apenas Pytorch. Construir a biblioteca C ++ requer GCC ou CLANG. O suporte a modelagem de idiomas Kenlm também está opcionalmente incluído e ativado por padrão.
A instalação abaixo também funciona para o Google Colab.
# get the code
git clone --recursive https://github.com/parlance/ctcdecode.git
cd ctcdecode && pip install . from ctcdecode import CTCBeamDecoder
decoder = CTCBeamDecoder (
labels ,
model_path = None ,
alpha = 0 ,
beta = 0 ,
cutoff_top_n = 40 ,
cutoff_prob = 1.0 ,
beam_width = 100 ,
num_processes = 4 ,
blank_id = 0 ,
log_probs_input = False
)
beam_results , beam_scores , timesteps , out_lens = decoder . decode ( output )CTCBeamDecoderlabels são os tokens que você usou para treinar seu modelo. Eles devem estar na mesma ordem que suas saídas. Por exemplo, se seus tokens forem as letras em inglês e você usou 0 como seu token em branco, então você passaria na lista ("_ abcdefghijklmopqrststwxyz") como seu argumento para os rótulosmodel_path é o caminho para o seu modelo de linguagem Kenlm externo (LM). Padrão não é.alpha associada às probabilidades do LMS. Um peso de 0 significa que o LM não tem efeito.beta associado ao número de palavras dentro do nosso feixe.cutoff_top_n Número de corte na poda. Somente os caracteres top cutoff_top_n com a maior probabilidade no vocabulário serão usados na pesquisa de feixes.cutoff_prob Probabilidade de corte na poda. 1.0 significa nenhuma poda.beam_width Isso controla o quão ampla é a pesquisa de feixe. Valores mais altos têm maior probabilidade de encontrar vigas superiores, mas também tornarão sua pesquisa de feixe exponencialmente mais lenta. Além disso, quanto mais longas suas saídas, mais feixes grandes levarão. Este é um parâmetro importante que representa uma troca que você precisa fazer com base no seu conjunto de dados e necessidades.num_processes paralelize o lote usando trabalhadores num_processos. Você provavelmente deseja passar o número de CPUs que seu computador possui. Você pode encontrar isso em python com import multiprocessing e então n_cpus = multiprocessing.cpu_count() . Padrão 4.blank_id Este deve ser o índice do token em branco do CTC (provavelmente 0).log_probs_input Se suas saídas tiveram passado por um softmax e representarem probabilidades, isso deve ser falso, se elas passaram por um logSoftMax e representarem uma probabilidade de log negativa, você precisa passar true. Se você não entende isso, execute print(output[0][0].sum()) , se for um número negativo que você provavelmente tem NLL e precisará passar verdadeiro, se resumir para ~ 1,0, você deve passar false. Padrão false.decodeoutput deve ser as ativações de saída do seu modelo. Se a sua saída passou por uma camada SoftMax, você não precisará alterá -la (exceto talvez transpor), mas se sua output representar probabilidades negativas de log (logits brutas), você precisará passar por uma torch.nn.functional.softmax adicional.nn.functional.softmax ou você pode passar log_probs_input=False para o decodificador. Sua saída deve ser em lote x n_timesteps x n_labels, para que você precise transpor -o antes de passá -lo para o decodificador. Observe que, se você passar as coisas na ordem errada, a pesquisa de feixe provavelmente ainda será executada, você apenas receberá resultados absurdos.decode 4 coisas são devolvidas de decode
beam_results - SHAPE: BatchSize x n_beams x n_timesteps Um lote contendo a série de caracteres (esses são INTs, você ainda precisa decodificá -los de volta ao seu texto) representando os resultados de uma determinada pesquisa de feixe. Observe que os feixes são quase sempre mais curtos que o número total de textuais, e os dados adicionais não são sensíveis; portanto, para ver o feixe superior (como rótulos INT) do primeiro item do lote, você precisa executar beam_results[0][0][:out_len[0][0]] .beam_scores - SHAPE: BatchSize x n_beams Um lote com a pontuação aproximada do CTC de cada feixe (consulte o código aqui para obter mais informações). Se isso for verdade, você pode obter a confiança do modelo de que o feixe está correto com p=1/np.exp(beam_score) .timesteps - Shape: BatchSize x n_beams O timestep no qual o enésimo caractere de saída tem probabilidade de pico. Pode ser usado como alinhamento entre o áudio e a transcrição.out_lens - Shape: BatchSize x n_beams. out_lens[i][j] é o comprimento do jth beam_result, do item I do seu lote. from ctcdecode import OnlineCTCBeamDecoder
decoder = OnlineCTCBeamDecoder (
labels ,
model_path = None ,
alpha = 0 ,
beta = 0 ,
cutoff_top_n = 40 ,
cutoff_prob = 1.0 ,
beam_width = 100 ,
num_processes = 4 ,
blank_id = 0 ,
log_probs_input = False
)
state1 = ctcdecode . DecoderState ( decoder )
probs_seq = torch . FloatTensor ([ probs_seq ])
beam_results , beam_scores , timesteps , out_seq_len = decoder . decode ( probs_seq [:, : 2 ], [ state1 ], [ False ])
beam_results , beam_scores , timesteps , out_seq_len = decoder . decode ( probs_seq [:, 2 :], [ state1 ], [ True ])O decodificador on -line está copiando a interface CTCBeamDecoder, mas requer seqüências estados e is_eos_s.
Os estados são usados para acumular sequências de pedaços, cada uma correspondente a uma fonte de dados. IS_EOS_S diz ao decodificador se os pedaços pararam de ser empurrados para o estado correspondente.
Obtenha o feixe superior para o primeiro item em seu lote beam_results[0][0][:out_len[0][0]]
Obtenha os 50 principais feixes para o primeiro item do seu lote
for i in range ( 50 ):
print ( beam_results [ 0 ][ i ][: out_len [ 0 ][ i ]]) Observe que estes serão uma lista de INTs que precisam de decodificar. Você provavelmente já tem uma função para decodificar de int para o texto, mas se não pode fazer algo como. "".join[labels[n] for n in beam_results[0][0][:out_len[0][0]]] usando os rótulos que você passou para CTCBeamDecoder