├── .gitignore ├── Makefile ├── README.md ├── context-to-pdf.cc ├── convert.sh ├── convert.sh.readme ├── gmm-copy.cc ├── kaldi2AP.py ├── kaldi2HTK.py ├── make-pdf-to-tid-transducer.cc └── print-transitions.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .* 3 | /saveBinary.py 4 | /gmm-copy 5 | /kaldi2NNEris.py 6 | /path.sh 7 | /convert.sh.readme 8 | /convert.sh 9 | /print-transitions 10 | /context-to-pdf 11 | /make-pdf-to-tid-transducer 12 | /formats.py 13 | /loadBinary.py 14 | .idea -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | KALDI = /home/dan/kky/kaldi/kaldi.git/src/ 2 | 3 | 4 | all: 5 | 6 | EXTRA_CXXFLAGS = -Wno-sign-compare -I${KALDI} 7 | 8 | include ${KALDI}/kaldi.mk 9 | 10 | BINFILES = context-to-pdf print-transitions gmm-copy make-pdf-to-tid-transducer 11 | # gmm-copy : is in $kaldipath/src/gmmbin 12 | # make-pdf-to-tid-transducer : is in bin/make-pdf-to-tid-transducer.cc 13 | 14 | OBJFILES = 15 | 16 | ADDLIBS = ${KALDI}/lm/kaldi-lm.a ${KALDI}/decoder/kaldi-decoder.a ${KALDI}/lat/kaldi-lat.a \ 17 | ${KALDI}/hmm/kaldi-hmm.a ${KALDI}/transform/kaldi-transform.a ${KALDI}/gmm/kaldi-gmm.a \ 18 | ${KALDI}/tree/kaldi-tree.a ${KALDI}/matrix/kaldi-matrix.a ${KALDI}/util/kaldi-util.a \ 19 | ${KALDI}/base/kaldi-base.a ${KALDI}/hmm/kaldi-hmm.a \ 20 | ${KALDI}/fstext/kaldi-fstext.a 21 | 22 | TESTFILES = 23 | 24 | include ${KALDI}/makefiles/default_rules.mk 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Kaldi to HTK GMM/HMM model converting script 2 | 3 | ## Requirements 4 | 5 | 1. Compiled Kaldi (kaldi-asr.org) 6 | 2. python 7 | 8 | ## Compilation 9 | 10 | 1. Check your KALDI path in Makefile 11 | 2. make binaries with ```make``` 12 | 13 | ## Usage 14 | 15 | ``` 16 | python kaldi2HTKmodel.py 17 | ``` 18 | 19 | Note: script kaldi2AP.py is modification of kaldi2HTK.py suited for our decoder 20 | 21 | ## Licence 22 | 23 | Implemented by Daniel Soutner, NTIS - New Technologie for the Information Society, 24 | University of West Bohemia, Plzen, Czech rep. dsoutner@kky.zcu.cz, 2016. 25 | 26 | Licensed under the 3-clause BSD. 27 | -------------------------------------------------------------------------------- /context-to-pdf.cc: -------------------------------------------------------------------------------- 1 | // allTriphonesToPdf.cc 2 | 3 | // Copyright 2016 Daniel Soutner 4 | 5 | // See ../../COPYING for clarification regarding multiple authors 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 15 | // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 16 | // MERCHANTABLITY OR NON-INFRINGEMENT. 17 | // See the Apache 2 License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | 21 | #include "tree/tree-renderer.h" 22 | #include "tree/context-dep.h" 23 | 24 | int main(int argc, char **argv) { 25 | using namespace kaldi; 26 | try { 27 | std::string qry; 28 | 29 | const char *usage = 30 | "Outputs Pdf for all possible triphones\n" 31 | "Usage: context-to-pdf \n" 32 | "e.g.: context-to-pdf phones.txt tree \n"; 33 | 34 | std::string silphones = "1,2,3"; 35 | int32 silpdfclasses = 5; 36 | int32 nonsilpdfclasses = 3; 37 | 38 | ParseOptions po(usage); 39 | 40 | po.Register("sil-phones", &silphones, 41 | "Comma separated list of silence phones"); 42 | po.Register("sil-pdf-classes", &silpdfclasses, 43 | "Number of pdf-classes for silence phones"); 44 | po.Register("non-sil-pdf-classes", &nonsilpdfclasses, 45 | "Number of pdf-classes for non-silence phones"); 46 | po.Read(argc, argv); 47 | 48 | if (po.NumArgs() != 2) { 49 | po.PrintUsage(); 50 | return -1; 51 | } 52 | std::string phnfile = po.GetArg(1); 53 | std::string treefile = po.GetArg(2); 54 | 55 | //read phones 56 | fst::SymbolTable *phones_symtab = NULL; 57 | { 58 | std::ifstream is(phnfile.c_str()); 59 | phones_symtab = ::fst::SymbolTable::ReadText(is, phnfile); 60 | if (!phones_symtab) 61 | KALDI_ERR << "Could not read phones symbol table file "<< phnfile; 62 | } 63 | 64 | /* 65 | if (phones_symtab != NULL) { 66 | size_t ns = phones_symtab->NumSymbols(); 67 | if (maxs != (int32) (ns-1)) { 68 | KALDI_WARN << "specified highest symbol (" << maxs 69 | << ") not equal to size of symtab (" << (ns-1) << "), adjusting "; 70 | maxs = (ns-1); 71 | } 72 | } 73 | */ 74 | 75 | //read tree object 76 | ContextDependency ctx_dep; 77 | ReadKaldiObject(po.GetArg(2), &ctx_dep); 78 | 79 | 80 | // parse silphones 81 | std::set silset; 82 | 83 | std::string::size_type i1 = 0, i2; 84 | do { 85 | i2 = silphones.find(',', i1); 86 | silset.insert(atoi(silphones.substr(i1, i2 - i1).c_str())); 87 | KALDI_LOG << "silphone: " << silphones.substr(i1, i2 - i1); 88 | if (i2 == std::string::npos) 89 | break; 90 | i1 = i2 + 1; 91 | } while (true); 92 | 93 | KALDI_LOG << "Context width:" << ctx_dep.ContextWidth(); 94 | KALDI_LOG << "Central position:" << ctx_dep.CentralPosition(); 95 | 96 | // triphones 97 | if((ctx_dep.ContextWidth() == 3) && (ctx_dep.CentralPosition() == 1)){ 98 | // iter over all possible triphones 99 | size_t nphones = phones_symtab->NumSymbols(); 100 | for (int32 l_ctx = 0; l_ctx < nphones; ++l_ctx) { 101 | for (int32 ph = 1; ph < nphones; ++ph) { // not 102 | for (int32 p_ctx = 0; p_ctx < nphones; ++p_ctx) { 103 | 104 | int32 pdf_id; 105 | 106 | //KALDI_LOG << "OK"; 107 | 108 | // triphone context vector 109 | std::vector triphone; 110 | triphone.push_back(l_ctx); 111 | triphone.push_back(ph); 112 | triphone.push_back(p_ctx); 113 | 114 | //KALDI_LOG << "OK"; 115 | 116 | //In the normal case the pdf-class is the same as the HMM state index (e.g. 0, 1 or 2), but pdf classes provide a way for the user to enforce sharing. 117 | // pdf-classes http://kaldi.sourceforge.net/hmm.html 118 | int32 mpdf = (silset.find(ph) == silset.end() ? 119 | nonsilpdfclasses : 120 | silpdfclasses); 121 | 122 | //KALDI_LOG << mpdf; 123 | for (int32 pdf_class=0; pdf_class < mpdf; ++pdf_class) { 124 | //bool ContextDependency::Compute(const std::vector &phoneseq, int32 pdf_class, int32 *pdf_id) 125 | ctx_dep.Compute(triphone, pdf_class, &pdf_id); 126 | std::cout << phones_symtab->Find(l_ctx) << " " << phones_symtab->Find(ph) << " " << phones_symtab->Find(p_ctx) << " " << pdf_class << " " << pdf_id << "\n"; 127 | } 128 | } 129 | } 130 | } 131 | } 132 | // mono 133 | if((ctx_dep.ContextWidth() == 1) && (ctx_dep.CentralPosition() == 0)){ 134 | // iter over all possible monophones 135 | size_t nphones = phones_symtab->NumSymbols(); 136 | for (int32 ph = 1; ph < nphones; ++ph) { // not 137 | int32 pdf_id; 138 | 139 | // mono context vector 140 | std::vector triphone; 141 | triphone.push_back(ph); 142 | 143 | //In the normal case the pdf-class is the same as the HMM state index (e.g. 0, 1 or 2), but pdf classes provide a way for the user to enforce sharing. 144 | // pdf-classes http://kaldi.sourceforge.net/hmm.html 145 | int32 mpdf = (silset.find(ph) == silset.end() ? 146 | nonsilpdfclasses : 147 | silpdfclasses); 148 | 149 | for (int32 pdf_class=0; pdf_class < mpdf; ++pdf_class) { 150 | //bool ContextDependency::Compute(const std::vector &phoneseq, int32 pdf_class, int32 *pdf_id) 151 | ctx_dep.Compute(triphone, pdf_class, &pdf_id); 152 | std::cout << phones_symtab->Find(ph) << " " << pdf_class << " " << pdf_id << "\n"; 153 | } 154 | } 155 | } 156 | 157 | 158 | } catch (const std::exception &e) { 159 | std::cerr << e.what(); 160 | return -1; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /convert.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR=$1 4 | 5 | gmm-copy --binary=false $DIR/final.mdl $DIR/final.mdl.txt 6 | python kaldi2AP.py $DIR/final.mdl.txt $DIR/phones.txt $DIR/tree $DIR/HTKmodels $DIR/tiedlist 7 | 8 | for nnet in $1/*.nnet 9 | do 10 | nnet-copy --binary=false $nnet $nnet.txt 11 | python kaldi2NNEris.py $DIR/HTKmodels $nnet.txt $DIR/final.feature_transform $DIR/ali_train_pdf.counts $nnet.NNimage $nnet.stateOrder 12 | done 13 | -------------------------------------------------------------------------------- /convert.sh.readme: -------------------------------------------------------------------------------- 1 | # get GMM + HMM model 2 | # ! look inside script to set up NSE phones 3 | # ! use full triphone model with GMMs (from tri4? dir), fake GMM conversion is not tested 4 | # ! if trained with SAT, use final.alimdl model (is converted back to orig.features) 5 | python kaldi2AP.py 6 | 7 | # convert nnet to txt format 8 | nnet-copy --binary=false 9 | 10 | # make ERIS image 11 | python kaldi2NNEris.py 12 | -------------------------------------------------------------------------------- /gmm-copy.cc: -------------------------------------------------------------------------------- 1 | // gmmbin/gmm-copy.cc 2 | 3 | // Copyright 2009-2011 Microsoft Corporation 4 | 5 | // See ../../COPYING for clarification regarding multiple authors 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 15 | // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 16 | // MERCHANTABLITY OR NON-INFRINGEMENT. 17 | // See the Apache 2 License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | #include "base/kaldi-common.h" 21 | #include "util/common-utils.h" 22 | #include "gmm/am-diag-gmm.h" 23 | #include "hmm/transition-model.h" 24 | 25 | int main(int argc, char *argv[]) { 26 | try { 27 | using namespace kaldi; 28 | typedef kaldi::int32 int32; 29 | 30 | const char *usage = 31 | "Copy GMM based model (and possibly change binary/text format)\n" 32 | "Usage: gmm-copy [options] \n" 33 | "e.g.:\n" 34 | " gmm-copy --binary=false 1.mdl 1_txt.mdl\n"; 35 | 36 | 37 | bool binary_write = true, 38 | copy_am = true, 39 | copy_tm = true; 40 | 41 | ParseOptions po(usage); 42 | po.Register("binary", &binary_write, "Write output in binary mode"); 43 | po.Register("copy-am", ©_am, "Copy the acoustic model (AmDiagGmm object)"); 44 | po.Register("copy-tm", ©_tm, "Copy the transition model"); 45 | 46 | po.Read(argc, argv); 47 | 48 | if (po.NumArgs() != 2) { 49 | po.PrintUsage(); 50 | exit(1); 51 | } 52 | 53 | std::string model_in_filename = po.GetArg(1), 54 | model_out_filename = po.GetArg(2); 55 | 56 | AmDiagGmm am_gmm; 57 | TransitionModel trans_model; 58 | { 59 | bool binary_read; 60 | Input ki(model_in_filename, &binary_read); 61 | if (copy_tm) 62 | trans_model.Read(ki.Stream(), binary_read); 63 | if (copy_am) 64 | am_gmm.Read(ki.Stream(), binary_read); 65 | } 66 | 67 | { 68 | Output ko(model_out_filename, binary_write); 69 | if (copy_tm) 70 | trans_model.Write(ko.Stream(), binary_write); 71 | if (copy_am) 72 | am_gmm.Write(ko.Stream(), binary_write); 73 | } 74 | 75 | KALDI_LOG << "Written model to " << model_out_filename; 76 | } catch(const std::exception &e) { 77 | std::cerr << e.what() << '\n'; 78 | return -1; 79 | } 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /kaldi2AP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016, Daniel Soutner, University of West Bohemia, Czechia 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without modification, are permitted 8 | # provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, this list of conditions 11 | # and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 14 | # and the following disclaimer in the documentation and/or other materials provided with the distribution. 15 | # 16 | # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote 17 | # products derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | # OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import re 29 | import numpy as np 30 | import subprocess 31 | import sys 32 | import os 33 | sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 34 | 35 | # Path to bin 36 | print_transitions_bin = "print-transitions" 37 | context_to_pdf_bin = "context-to-pdf" 38 | gmm_copy_bin = "gmm-copy" 39 | 40 | 41 | def mat2str(mat): 42 | """Convert numpy matrix to string""" 43 | s = "" 44 | for i in range(mat.shape[0]): 45 | for j in range(mat.shape[1]): 46 | s += "%.6e" % mat[i,j] 47 | if j < mat.shape[1] - 1: 48 | s += " " 49 | if i < mat.shape[0] - 1: 50 | s += "\n" 51 | return s 52 | 53 | 54 | def list2str(l): 55 | """Convert list to matrix-string""" 56 | s = "" 57 | for i in range(len(l)): 58 | s += "%.6e" % l[i] 59 | if i < len(l) -1: 60 | s += " " 61 | return s 62 | 63 | 64 | def shell(cmd): 65 | subprocess.call(cmd, shell=True) 66 | 67 | 68 | def load_kaldi_gmms(fmdl): 69 | """Load Kaldi GMM model, from text .mdl file""" 70 | mdl = { 71 | "vecSize" : None, 72 | "states" : None, 73 | } 74 | inTag = "" 75 | pTag = {} 76 | states = {} 77 | st_no = -1 78 | 79 | # Load model tags 80 | for raw_line in open(fmdl): 81 | line = raw_line.strip() 82 | 83 | if line.startswith("", line) 87 | 88 | if len(all_tags_in_line) == 1: 89 | inTag = all_tags_in_line[0] 90 | pTag[all_tags_in_line[0]] = True 91 | else: 92 | for i in all_tags_in_line: 93 | inTag = i 94 | pTag[i] = True 95 | 96 | # Get DIMs 97 | if line.startswith(""): 98 | mdl["vecSize"] = int(line.split()[1]) 99 | 100 | if inTag == "GCONSTS": 101 | data = [float(i) for i in line.split()[2:-1]] 102 | states[st_no]["GConsts"] = np.array(data) 103 | 104 | elif inTag == "WEIGHTS": 105 | data = [float(i) for i in line.split()[2:-1]] 106 | states[st_no]["Weights"] = np.array(data) 107 | 108 | elif inTag == "MEANS_INVVARS" and not line.startswith(""): 109 | data = [float(i) for i in line.replace("]", "").split()] 110 | try: 111 | states[st_no]["MeansInvVars"].append(data) 112 | except KeyError: 113 | states[st_no]["MeansInvVars"] = [data] 114 | 115 | elif inTag == "INV_VARS" and not line.startswith(""): 116 | data = [float(i) for i in line.replace("]", "").split()] 117 | try: 118 | states[st_no]["InvVars"].append(data) 119 | except KeyError: 120 | states[st_no]["InvVars"] = [data] 121 | 122 | elif inTag == "DiagGMM": 123 | st_no += 1 124 | states[st_no] = {} 125 | 126 | mdl["states"] = states 127 | return mdl 128 | 129 | 130 | def load_kaldi_transitions(ftrans): 131 | """Load Kaldi transition model""" 132 | 133 | probs = {} 134 | 135 | for line in open(ftrans): 136 | lx = line.strip().split() 137 | pdf = int(lx[1]) 138 | # phone = int(lx[2]) 139 | a = int(lx[3]) 140 | b = int(lx[4]) 141 | prob = float(lx[6]) 142 | # probs[(pdf, phone, a, b)] = prob 143 | # if (pdf, a, b) in probs1: 144 | # print "ERROR: Bad transitions read at", (pdf, a, b) 145 | probs[(pdf, a, b)] = prob 146 | 147 | return probs 148 | 149 | 150 | def load_kaldi_hmms(fctx): 151 | """Load HMMs from text output of context to pdf binary""" 152 | hmms ={} 153 | 154 | hmm = [] 155 | for line in open(fctx): 156 | lx = line.strip().split() 157 | ctx = (lx[0], lx[1], lx[2]) 158 | n = int(lx[3]) 159 | pdf = int(lx[4]) 160 | 161 | # we do not need disambig phones 162 | if "#" in ctx[0] or "#" in ctx[1] or "#" in ctx[2]: 163 | continue 164 | 165 | # we do not need 166 | if "" in ctx[0] or "" in ctx[1] or "" in ctx[2]: 167 | continue 168 | 169 | if n == 0: # first state, start new HMM 170 | if len(hmm) > 0: 171 | if not tuple(hmm) in hmms: 172 | hmms[tuple(hmm)] = [ctx_last] 173 | else: 174 | hmms[tuple(hmm)] += [ctx_last] 175 | hmm = [pdf] 176 | else: 177 | hmm.append(pdf) 178 | ctx_last = ctx 179 | 180 | # and the last one :) 181 | if not tuple(hmm) in hmms: 182 | hmms[tuple(hmm)] = [ctx_last] 183 | else: 184 | hmms[tuple(hmm)] += [ctx_last] 185 | 186 | return hmms 187 | 188 | 189 | def load_kaldi_phones(fphones): 190 | """Load Kaldi phones table""" 191 | phones2int = {} 192 | int2phones = {} 193 | 194 | for line in open(fphones): 195 | lx = line.strip().split() 196 | ph = lx[0] 197 | i = int(lx[1]) 198 | phones2int[ph] = i 199 | int2phones[i] = ph 200 | 201 | return phones2int, int2phones 202 | 203 | 204 | def phone_to_AP(ph, nse="CG ER GR HM LA LB LS NS SIL".split()): 205 | if ph in nse: 206 | return "_"+ph.lower()+"_" 207 | else: 208 | return ph 209 | 210 | 211 | def to_htk_name(lst, nse="CG ER GR HM LA LB LS NS SIL".split()): 212 | # original names 213 | # return lst[0]+"-"+lst[1]+"+"+lst[2] 214 | 215 | # AP conversion 216 | if lst[1] in nse: # NSE as mono 217 | return phone_to_AP(lst[1], nse=nse) 218 | else: 219 | return phone_to_AP(lst[0], nse=nse) + "-" + phone_to_AP(lst[1], nse=nse) + "+" + phone_to_AP(lst[2], nse=nse) 220 | 221 | 222 | def convert(fmdl, fphones, ftree, foutname, ftiedname, vecSize=39, silphones="", silphones_str=["SIL"], GMM=False): 223 | 224 | # print all transitions 225 | shell("./%s %s > %s" % (print_transitions_bin, fmdl, ".transitions")) 226 | trans = load_kaldi_transitions(".transitions") 227 | 228 | # print all triphones 229 | shell("./%s --sil-pdf-classes=3 --sil-phones='%s' %s %s > %s" % (context_to_pdf_bin, silphones, fphones, ftree, ".ctx")) 230 | hmms = load_kaldi_hmms(".ctx") 231 | 232 | # phones 233 | phones2int, int2phones = load_kaldi_phones(fphones) 234 | 235 | if GMM: 236 | shell("%s --binary=false --verbose=1 %s %s" % (gmm_copy_bin, fmdl, ".gmm")) 237 | gmms = load_kaldi_gmms(".gmm") 238 | vecSize = gmms["vecSize"] 239 | 240 | # Write HTK models 241 | with open(foutname, "w") as fw: 242 | print >> fw, "~o" 243 | print >> fw, " 1 %d" % vecSize 244 | print >> fw, " %d" % vecSize 245 | 246 | # Write transitions 247 | states = [] 248 | for hmm in hmms.keys(): 249 | trans_name = "_".join([str(x) for x in hmm]) 250 | 251 | trans_mat = np.zeros((len(hmm)+2, len(hmm)+2)) 252 | trans_mat[0, 1] = 1. 253 | for i, state in enumerate(hmm): 254 | states.append(state) 255 | for b in range(0, 2): 256 | ph = phones2int[hmms[hmm][0][1]] 257 | try: 258 | p = trans[state, i, b] 259 | except KeyError: 260 | print "ERROR: Not found transition for pdf %d with phone %d at %d %d" % (state, ph, i, b) 261 | trans_mat[i+1, b+i+1] = p 262 | 263 | # Print out transitions for this HMM 264 | print >> fw, '~t "T_%s"' % trans_name 265 | print >> fw, " %d" % (len(hmm) + 2) 266 | print >> fw, mat2str(trans_mat) 267 | 268 | if GMM: 269 | # Write GMMs 270 | for s in gmms["states"].keys(): 271 | print >> fw, '~s "state_%04d"' % s 272 | num_mixes = len(gmms["states"][s]["GConsts"]) 273 | print >> fw, " %d" % num_mixes 274 | for gmm in range(num_mixes): 275 | print >> fw, " %d %e" % (gmm + 1, gmms["states"][s]["Weights"][gmm]) 276 | print >> fw, " %d" % len(gmms["states"][s]["MeansInvVars"][gmm]) 277 | print >> fw, list2str([i / j for i, j in zip(gmms["states"][s]["MeansInvVars"][gmm], gmms["states"][s]["InvVars"][gmm])]) 278 | print >> fw, " %d" % len(gmms["states"][s]["InvVars"][gmm]) 279 | print >> fw, list2str([1.0 / i for i in gmms["states"][s]["InvVars"][gmm]]) 280 | gconst = np.log(2 * np.pi) * vecSize + np.sum(np.log(np.array([1.0 / i for i in gmms["states"][s]["InvVars"][gmm]]))) 281 | print >> fw, " %e" % gconst 282 | 283 | else: 284 | # Write fake GMMs 285 | for s in set(states): 286 | print >> fw, '~s "state_%04d"' % s 287 | num_mixes = 1 288 | print >> fw, " %d" % num_mixes 289 | for gmm in range(num_mixes): 290 | print >> fw, " %d %e" % (gmm + 1, 1.0) 291 | print >> fw, " %d" % vecSize 292 | print >> fw, mat2str(np.zeros((1, vecSize))) 293 | print >> fw, " %d" % vecSize 294 | print >> fw, mat2str(np.ones((1, vecSize))) 295 | print >> fw, " %e" % 1.0 296 | 297 | # Write HMMs 298 | for hmm in hmms.keys(): 299 | trans_name = "_".join([str(x) for x in hmm]) 300 | hmm_name = to_htk_name(hmms[hmm][0], nse=silphones_str) 301 | 302 | print >> fw, '~h "%s"' % hmm_name 303 | print >> fw, "" 304 | print >> fw, " %d" % (len(hmm) + 2) 305 | for idx, s in enumerate(hmm): 306 | print >> fw, " %d" % (idx + 2) 307 | print >> fw, '~s "state_%04d"' % s 308 | print >> fw, '~t "T_%s"' % trans_name 309 | print >> fw, "" 310 | 311 | os.fsync(fw) 312 | fw.flush() 313 | 314 | # Write HTK tiedlist 315 | written = set() # just in case, we are writing something second time 316 | with open(ftiedname, "w") as fw: 317 | for hmm in hmms.keys(): 318 | if len(hmms[hmm]) > 1: 319 | print >> fw, to_htk_name(hmms[hmm][0], nse=silphones_str) 320 | for i in range(1, len(hmms[hmm])): 321 | if (to_htk_name(hmms[hmm][i], nse=silphones_str), to_htk_name(hmms[hmm][0], nse=silphones_str)) not in written \ 322 | and to_htk_name(hmms[hmm][i], nse=silphones_str) != to_htk_name(hmms[hmm][0], nse=silphones_str): 323 | 324 | print >> fw, to_htk_name(hmms[hmm][i], nse=silphones_str), to_htk_name(hmms[hmm][0], nse=silphones_str) 325 | written.add((to_htk_name(hmms[hmm][i], nse=silphones_str), to_htk_name(hmms[hmm][0], nse=silphones_str))) 326 | else: 327 | print >> fw, to_htk_name(hmms[hmm][0], nse=silphones_str) 328 | 329 | 330 | def detect_NSE(phones_file, min_len=3): 331 | """ 332 | All phones in upper case, longer then MIN_LEN and without # in name 333 | """ 334 | phones = [x.strip().split()[0] for x in open(phones_file).readlines()] 335 | nse = [x for x in phones if (len(x) >= min_len) and (x.upper() == x) and ("#" not in x)] 336 | idx = [phones.index(x) for x in nse] 337 | return nse, idx 338 | 339 | if __name__ == "__main__": 340 | 341 | # now detected automatically 342 | #silphones_str = "CG ER GR HM LA LB LS NS SIL".split() 343 | #silphones = "1,2,3,4,5,6,7,8,9" 344 | #silphones_str = "DISTORTION DTMF EHM EHMNO EHMYES LAUGH NOISE SIL SLURP SPEAKER UNINTELLIGIBLE".split() 345 | #silphones_str = "INHALE NOISE EEE HMM SIL MOUTH LAUGH".split() 346 | #silphones = "1,2,3,4,5,6,7" 347 | 348 | if len(sys.argv) != 6: 349 | print "Usage: Kaldi2HTKmodel.py " 350 | sys.exit() 351 | 352 | MODEL_FILE = sys.argv[1] 353 | PHONES_FILE = sys.argv[2] 354 | TREE_FILE = sys.argv[3] 355 | OUTPUT_MODEL_FILE = sys.argv[4] 356 | OUTPUT_TIEDLIST_FILE = sys.argv[5] 357 | 358 | silphones_str, silphones = detect_NSE(PHONES_FILE, min_len=2) 359 | print >> sys.stderr, "NSE phones:", " ".join(silphones_str) 360 | print >> sys.stderr, "NSE phones:", " ".join([str(x) for x in silphones]) 361 | convert(MODEL_FILE, PHONES_FILE, TREE_FILE, OUTPUT_MODEL_FILE, 362 | OUTPUT_TIEDLIST_FILE, vecSize=36, 363 | silphones=",".join([str(x) for x in silphones]), 364 | silphones_str=silphones_str, GMM=True) 365 | -------------------------------------------------------------------------------- /kaldi2HTK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016, Daniel Soutner, University of West Bohemia, Czechia 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without modification, are permitted 8 | # provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, this list of conditions 11 | # and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 14 | # and the following disclaimer in the documentation and/or other materials provided with the distribution. 15 | # 16 | # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote 17 | # products derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | # OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import re 29 | import numpy as np 30 | import subprocess 31 | import sys 32 | import os 33 | import argparse 34 | 35 | sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 36 | 37 | # Path to bin 38 | print_transitions_bin = "print-transitions" 39 | context_to_pdf_bin = "context-to-pdf" 40 | gmm_copy_bin = "gmm-copy" 41 | 42 | 43 | def mat2str(mat): 44 | """Convert numpy matrix to string""" 45 | s = "" 46 | for i in range(mat.shape[0]): 47 | for j in range(mat.shape[1]): 48 | s += "%.6e" % mat[i,j] 49 | if j < mat.shape[1] - 1: 50 | s += " " 51 | if i < mat.shape[0] - 1: 52 | s += "\n" 53 | return s 54 | 55 | 56 | def list2str(l): 57 | """Convert list to matrix-string""" 58 | s = "" 59 | for i in range(len(l)): 60 | s += "%.6e" % l[i] 61 | if i < len(l) -1: 62 | s += " " 63 | return s 64 | 65 | 66 | def shell(cmd): 67 | subprocess.call(cmd, shell=True) 68 | 69 | 70 | def load_kaldi_gmms(fmdl): 71 | """Load Kaldi GMM model, from text .mdl file""" 72 | mdl = { 73 | "vecSize" : None, 74 | "states" : None, 75 | } 76 | inTag = "" 77 | pTag = {} 78 | states = {} 79 | st_no = -1 80 | 81 | # Load model tags 82 | for raw_line in open(fmdl): 83 | line = raw_line.strip() 84 | 85 | if line.startswith("", line) 89 | 90 | if len(all_tags_in_line) == 1: 91 | inTag = all_tags_in_line[0] 92 | pTag[all_tags_in_line[0]] = True 93 | else: 94 | for i in all_tags_in_line: 95 | inTag = i 96 | pTag[i] = True 97 | 98 | # Get DIMs 99 | if line.startswith(""): 100 | mdl["vecSize"] = int(line.split()[1]) 101 | 102 | if inTag == "GCONSTS": 103 | data = [float(i) for i in line.split()[2:-1]] 104 | states[st_no]["GConsts"] = np.array(data) 105 | 106 | elif inTag == "WEIGHTS": 107 | data = [float(i) for i in line.split()[2:-1]] 108 | states[st_no]["Weights"] = np.array(data) 109 | 110 | elif inTag == "MEANS_INVVARS" and not line.startswith(""): 111 | data = [float(i) for i in line.replace("]", "").split()] 112 | try: 113 | states[st_no]["MeansInvVars"].append(data) 114 | except KeyError: 115 | states[st_no]["MeansInvVars"] = [data] 116 | 117 | elif inTag == "INV_VARS" and not line.startswith(""): 118 | data = [float(i) for i in line.replace("]", "").split()] 119 | try: 120 | states[st_no]["InvVars"].append(data) 121 | except KeyError: 122 | states[st_no]["InvVars"] = [data] 123 | 124 | elif inTag == "DiagGMM": 125 | st_no += 1 126 | states[st_no] = {} 127 | 128 | mdl["states"] = states 129 | return mdl 130 | 131 | 132 | def load_kaldi_transitions(ftrans): 133 | """Load Kaldi transition model""" 134 | 135 | probs = {} 136 | 137 | for line in open(ftrans): 138 | lx = line.strip().split() 139 | pdf = int(lx[1]) 140 | # phone = int(lx[2]) 141 | a = int(lx[3]) 142 | b = int(lx[4]) 143 | prob = float(lx[6]) 144 | # probs[(pdf, phone, a, b)] = prob 145 | # if (pdf, a, b) in probs1: 146 | # print "ERROR: Bad transitions read at", (pdf, a, b) 147 | probs[(pdf, a, b)] = prob 148 | 149 | return probs 150 | 151 | 152 | def load_kaldi_hmms(fctx): 153 | """Load HMMs from text output of context to pdf binary""" 154 | hmms ={} 155 | 156 | hmm = [] 157 | for line in open(fctx): 158 | lx = line.strip().split() 159 | if len(lx) == 5: 160 | ctx = (lx[0], lx[1], lx[2]) 161 | n = int(lx[3]) 162 | pdf = int(lx[4]) 163 | elif len(lx) == 3: 164 | ctx = (lx[0],) 165 | n = int(lx[1]) 166 | pdf = int(lx[2]) 167 | else: 168 | raise ValueError("Data not understood.") 169 | 170 | # we do not need disambig phones 171 | if len(ctx) == 3 and ("#" in ctx[0] or "#" in ctx[1] or "#" in ctx[2]): 172 | continue 173 | 174 | # we do not need 175 | if len(ctx) == 3 and ("" in ctx[0] or "" in ctx[1] or "" in ctx[2]): 176 | continue 177 | 178 | if n == 0: # first state, start new HMM 179 | if len(hmm) > 0: 180 | if not tuple(hmm) in hmms: 181 | hmms[tuple(hmm)] = [ctx_last] 182 | else: 183 | hmms[tuple(hmm)] += [ctx_last] 184 | hmm = [pdf] 185 | else: 186 | hmm.append(pdf) 187 | ctx_last = ctx 188 | 189 | # and the last one :) 190 | if not tuple(hmm) in hmms: 191 | hmms[tuple(hmm)] = [ctx_last] 192 | else: 193 | hmms[tuple(hmm)] += [ctx_last] 194 | return hmms 195 | 196 | 197 | def load_kaldi_phones(fphones): 198 | """Load Kaldi phones table""" 199 | phones2int = {} 200 | int2phones = {} 201 | 202 | for line in open(fphones): 203 | lx = line.strip().split() 204 | ph = lx[0] 205 | i = int(lx[1]) 206 | phones2int[ph] = i 207 | int2phones[i] = ph 208 | 209 | return phones2int, int2phones 210 | 211 | 212 | def to_htk_name(lst): 213 | # original names 214 | if len(lst) == 3: 215 | return lst[0]+"-"+lst[1]+"+"+lst[2] 216 | elif len(lst) == 1: 217 | return lst[0] 218 | else: 219 | raise ValueError("Only monophone/triphone models allowed.") 220 | 221 | 222 | def convert(fmdl, fphones, ftree, foutname, ftiedname, vecSize=39, silphones="", GMM=False, sil_pdf_classes=3): 223 | 224 | # print all transitions 225 | shell("./%s %s > %s" % (print_transitions_bin, fmdl, ".transitions")) 226 | trans = load_kaldi_transitions(".transitions") 227 | 228 | # print all triphones 229 | shell("./%s --sil-pdf-classes=%d --sil-phones='%s' %s %s > %s" % (context_to_pdf_bin, sil_pdf_classes, silphones, fphones, ftree, ".ctx")) 230 | hmms = load_kaldi_hmms(".ctx") 231 | 232 | # phones 233 | phones2int, int2phones = load_kaldi_phones(fphones) 234 | 235 | if GMM: 236 | shell("%s --binary=false %s %s" % (gmm_copy_bin, fmdl, ".gmm")) 237 | gmms = load_kaldi_gmms(".gmm") 238 | vecSize = gmms["vecSize"] 239 | 240 | # Write HTK models 241 | with open(foutname, "w") as fw: 242 | print >> fw, "~o" 243 | print >> fw, " 1 %d" % vecSize 244 | print >> fw, " %d" % vecSize 245 | 246 | # Write transitions 247 | states = [] 248 | for hmm in hmms.keys(): 249 | trans_name = "_".join([str(x) for x in hmm]) 250 | 251 | trans_mat = np.zeros((len(hmm)+2, len(hmm)+2)) 252 | trans_mat[0, 1] = 1. 253 | for i, state in enumerate(hmm): 254 | states.append(state) 255 | for b in range(0, 2): 256 | if len(hmms[hmm][0]) == 3: 257 | ph = phones2int[hmms[hmm][0][1]] 258 | elif len(hmms[hmm][0]) == 1: 259 | ph = phones2int[hmms[hmm][0][0]] 260 | else: 261 | raise ValueError("Only mohophone/triphone models allowed.") 262 | try: 263 | # p = trans[state, ph, i, b] 264 | p = trans[state, i, b] 265 | except KeyError: 266 | if "#" in int2phones[ph]: 267 | print "INFO: Not found transition for pdf %d with phone %d at %d %d" % (state, ph, i, b) 268 | else: 269 | print "ERROR: Not found transition for pdf %d with phone %d at %d %d" % (state, ph, i, b) 270 | print "This could be bad error, probably some mistake in conversion?" 271 | trans_mat[i + 1, b + i + 1] = p 272 | 273 | # Print out transitions for this HMM 274 | print >> fw, '~t "T_%s"' % trans_name 275 | print >> fw, " %d" % (len(hmm) + 2) 276 | print >> fw, mat2str(trans_mat) 277 | 278 | if GMM: 279 | # Write GMMs 280 | for s in gmms["states"].keys(): 281 | print >> fw, '~s "state_%d"' % s 282 | num_mixes = len(gmms["states"][s]["GConsts"]) 283 | print >> fw, " %d" % num_mixes 284 | for gmm in range(num_mixes): 285 | print >> fw, " %d %e" % (gmm + 1, gmms["states"][s]["Weights"][gmm]) 286 | print >> fw, " %d" % len(gmms["states"][s]["MeansInvVars"][gmm]) 287 | print >> fw, list2str([i / j for i, j in zip(gmms["states"][s]["MeansInvVars"][gmm], gmms["states"][s]["InvVars"][gmm])]) 288 | print >> fw, " %d" % len(gmms["states"][s]["InvVars"][gmm]) 289 | print >> fw, list2str([1.0 / i for i in gmms["states"][s]["InvVars"][gmm]]) 290 | gconst = np.log(2 * np.pi) * vecSize + np.sum(np.log(np.array([1.0 / i for i in gmms["states"][s]["InvVars"][gmm]]))) 291 | print >> fw, " %e" % gconst 292 | 293 | else: 294 | # Write fake GMMs 295 | for s in set(states): 296 | print >> fw, '~s "state_%d"' % s 297 | num_mixes = 1 298 | print >> fw, " %d" % num_mixes 299 | for gmm in range(num_mixes): 300 | print >> fw, " %d %e" % (gmm + 1, 1.0) 301 | print >> fw, " %d" % vecSize 302 | print >> fw, mat2str(np.zeros((1, vecSize))) 303 | print >> fw, " %d" % vecSize 304 | print >> fw, mat2str(np.ones((1, vecSize))) 305 | print >> fw, " %e" % 1.0 306 | 307 | # Write HMMs 308 | for hmm in hmms.keys(): 309 | trans_name = "_".join([str(x) for x in hmm]) 310 | hmm_name = to_htk_name(hmms[hmm][0]) 311 | 312 | print >> fw, '~h "%s"' % hmm_name 313 | print >> fw, "" 314 | print >> fw, " %d" % (len(hmm) + 2) 315 | for idx, s in enumerate(hmm): 316 | print >> fw, " %d" % (idx + 2) 317 | print >> fw, '~s "state_%d"' % s 318 | print >> fw, '~t "T_%s"' % trans_name 319 | print >> fw, "" 320 | 321 | os.fsync(fw) 322 | fw.flush() 323 | 324 | # Write HTK tiedlist 325 | written = set() # just in case, we are writing something second time 326 | with open(ftiedname, "w") as fw: 327 | for hmm in hmms.keys(): 328 | if len(hmms[hmm]) > 1: 329 | print >> fw, to_htk_name(hmms[hmm][0]) 330 | for i in range(1, len(hmms[hmm])): 331 | if (to_htk_name(hmms[hmm][i]), to_htk_name(hmms[hmm][0])) not in written \ 332 | and to_htk_name(hmms[hmm][i]) != to_htk_name(hmms[hmm][0]): 333 | 334 | print >> fw, to_htk_name(hmms[hmm][i]), to_htk_name(hmms[hmm][0]) 335 | written.add((to_htk_name(hmms[hmm][i]), to_htk_name(hmms[hmm][0]))) 336 | else: 337 | print >> fw, to_htk_name(hmms[hmm][0]) 338 | 339 | 340 | if __name__ == "__main__": 341 | 342 | DESCRIPTION = "Script for converting Kaldi GMM to HTK model" 343 | 344 | parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.ArgumentDefaultsHelpFormatter) 345 | #parser.add_argument('--config', default=None, 346 | # help='Config file, other keys will be set to default') 347 | parser.add_argument('--silphones', default="1,2,3", type=str, 348 | help='Numbers of silence phones, split by comma') 349 | parser.add_argument('--vec-size', default=39, type=int, 350 | help='Size of input vectors if you fake GMM model') 351 | parser.add_argument('--sil-pdf-classes', default=3, type=int, 352 | help='Silphones pdf classes, HTK default is 3, Kaldi default is 5') 353 | parser.add_argument('--sil', type=str, default="SIL,SPN,NSN", 354 | help='Sil phones names, split by comma', ) 355 | parser.add_argument("kaldi_model") 356 | parser.add_argument("kaldi_phones") 357 | parser.add_argument("kaldi_tree") 358 | parser.add_argument("htk_output_model") 359 | parser.add_argument("htk_output_tiedlist") 360 | args = parser.parse_args() 361 | 362 | SIL = args.sil.split(",") 363 | 364 | convert(args.kaldi_model, args.kaldi_phones,args.kaldi_tree, 365 | args.htk_output_model, args.htk_output_tiedlist, 366 | vecSize=args.vec_size, silphones=args.silphones, 367 | GMM=True, sil_pdf_classes=args.sil_pdf_classes) 368 | -------------------------------------------------------------------------------- /make-pdf-to-tid-transducer.cc: -------------------------------------------------------------------------------- 1 | // bin/make-pdf-to-tid-transducer.cc 2 | // Copyright 2009-2011 Microsoft Corporation 3 | 4 | // See ../../COPYING for clarification regarding multiple authors 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 14 | // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 15 | // MERCHANTABLITY OR NON-INFRINGEMENT. 16 | // See the Apache 2 License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | #include "hmm/transition-model.h" 20 | #include "hmm/hmm-utils.h" 21 | #include "util/common-utils.h" 22 | #include "fst/fstlib.h" 23 | #include "matrix/kaldi-matrix.cc" 24 | 25 | int main(int argc, char *argv[]) { 26 | try { 27 | using namespace kaldi; 28 | typedef kaldi::int32 int32; 29 | using fst::SymbolTable; 30 | using fst::VectorFst; 31 | using fst::StdArc; 32 | 33 | const char *usage = 34 | "Make transducer from pdfs to transition-ids\n" 35 | "Usage: make-pdf-to-tid-transducer model-filename [fst-out]\n" 36 | "e.g.: \n" 37 | " make-pdf-to-tid-transducer 1.mdl > pdf2tid.fst\n"; 38 | ParseOptions po(usage); 39 | 40 | po.Read(argc, argv); 41 | 42 | if (po.NumArgs() <1 || po.NumArgs() > 2) { 43 | po.PrintUsage(); 44 | exit(1); 45 | } 46 | 47 | std::string trans_model_filename = po.GetArg(1); 48 | std::string fst_out_filename = po.GetOptArg(2); 49 | 50 | TransitionModel trans_model; 51 | ReadKaldiObject(trans_model_filename, &trans_model); 52 | 53 | fst::VectorFst *fst = GetPdfToTransitionIdTransducer(trans_model); 54 | 55 | #if _MSC_VER 56 | if (fst_out_filename == "") 57 | _setmode(_fileno(stdout), _O_BINARY); 58 | #endif 59 | 60 | if (!fst->Write(fst_out_filename)) 61 | KALDI_ERR << "Error writing fst to " 62 | << (fst_out_filename == "" ? "standard output" : fst_out_filename); 63 | delete fst; 64 | } catch(const std::exception &e) { 65 | std::cerr << e.what(); 66 | return -1; 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /print-transitions.cc: -------------------------------------------------------------------------------- 1 | // bin/make-pdf-to-tid-transducer.cc 2 | // Copyright 2009-2011 Microsoft Corporation 3 | 4 | // See ../../COPYING for clarification regarding multiple authors 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 14 | // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 15 | // MERCHANTABLITY OR NON-INFRINGEMENT. 16 | // See the Apache 2 License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | #include "hmm/transition-model.h" 20 | #include "hmm/hmm-utils.h" 21 | #include "util/common-utils.h" 22 | #include "fst/fstlib.h" 23 | #include "base/kaldi-common.h" 24 | #include "gmm/am-diag-gmm.h" 25 | #include "matrix/kaldi-matrix.cc" 26 | 27 | int main(int argc, char *argv[]) { 28 | #ifdef _MSC_VER 29 | if (0) { 30 | fst::VectorFst *fst = NULL; 31 | fst->Write(""); 32 | } 33 | #endif 34 | try { 35 | using namespace kaldi; 36 | typedef kaldi::int32 int32; 37 | 38 | const char *usage = 39 | "Write out transition-ids, phones, pdf-class, transition-idx\n" 40 | "Usage: write-logprobs model-filename\n" 41 | "e.g.: \n" 42 | " write-logprobs 1.mdl > out.txt\n"; 43 | ParseOptions po(usage); 44 | 45 | po.Read(argc, argv); 46 | 47 | if (po.NumArgs() <1 || po.NumArgs() > 1) { 48 | po.PrintUsage(); 49 | exit(1); 50 | } 51 | 52 | std::string trans_model_filename = po.GetArg(1); 53 | TransitionModel trans_model; 54 | ReadKaldiObject(trans_model_filename, &trans_model); 55 | 56 | for (int32 i = 1; i < trans_model.NumTransitionIds() + 1; i++) 57 | { 58 | std::cout << i << " " \ 59 | << trans_model.TransitionIdToPdf(i) << " " \ 60 | << trans_model.TransitionIdToPhone(i) << " " \ 61 | << trans_model.TransitionIdToHmmState(i) << " " \ 62 | << trans_model.TransitionIdToTransitionIndex(i) << " " \ 63 | << trans_model.TransitionIdToTransitionState(i) << " " \ 64 | << trans_model.GetTransitionProb(i) << " " \ 65 | << trans_model.IsSelfLoop(i) << " " \ 66 | << trans_model.IsFinal(i) << "\n"; 67 | } 68 | 69 | // old debug code bellow 70 | /* 71 | for (int32 i = 1; i < trans_model.NumTransitionStates() + 1; i++) 72 | { 73 | std::cout << i << " " << trans_model.TransitionStateToPhone(i) << " " \ 74 | << trans_model.TransitionStateToPdf(i) << " " \ 75 | << trans_model.TransitionStateToHmmState(i) << " " \ 76 | << trans_model.GetNonSelfLoopLogProb(i) << "\n"; 77 | } 78 | */ 79 | //std::cout << trans_model.Print(); 80 | //std::cout << trans_model.TopologyForPhone(1)[0]; 81 | /* 82 | int32 TransitionIdToTransitionState (int32 trans_id) const 83 | int32 TransitionIdToTransitionIndex (int32 trans_id) const 84 | int32 TransitionIdToPdf (int32 trans_id) const 85 | int32 TransitionIdToPhone (int32 trans_id) const 86 | int32 TransitionIdToPdfClass (int32 trans_id) const 87 | int32 TransitionIdToHmmState (int32 trans_id) const 88 | int32 TransitionStateToPhone (int32 trans_state) const 89 | int32 TransitionStateToHmmState (int32 trans_state) const 90 | int32 TransitionStateToPdf (int32 trans_state) const 91 | int32 SelfLoopOf (int32 trans_state) const 92 | */ 93 | 94 | } catch(const std::exception &e) { 95 | std::cerr << e.what(); 96 | return -1; 97 | } 98 | } 99 | 100 | --------------------------------------------------------------------------------