#!/usr/bin/env python import sys import math from cmusphinx import lattice import sphinxbase def baseword(sym): paren = sym.rfind('(') if paren != -1: return sym[0:paren] else: return sym def load_lexicon(lexfile): # load dict or filler file to get word to phone information f = open(lexfile, 'r') lines = f.readlines() f.close() lex = {} for line in lines: temp = line.split() lex[temp[0]] = temp[1:len(temp)] return lex def load_denlat(latfile): # Annotate the lattice with posterior probabilities dag = lattice.Dag(latfile) dag.remove_unreachable() arc = [] for w in dag.nodes: for l in w.exits: if (w.entry, w.sym, l.dest.entry, l.dest.sym) not in arc: arc.append((w.entry, w.sym, l.dest.entry, l.dest.sym)) lat = {} for n in arc: if n[1] != '': left = [] right = [] for m in arc: if n[3] == '' and (n[2], n[3], n[2]) not in right: right.append((n[2], n[3], n[2])) elif m[0] == n[2] and m[1] == n[3]: if (m[0], m[1], m[2]) not in right: right.append((m[0], m[1], m[2])) if m[2] == n[0] and m[3] == n[1]: if (m[0], m[1], m[2]) not in left: left.append((m[0], m[1], m[2])) if (n[0], n[1], n[2]) not in lat: lat[(n[0], n[1], n[2])] = (left, right) else: for l in left: if l not in lat[(n[0], n[1], n[2])][0]: lat[(n[0], n[1], n[2])][0].append(l) for r in right: if r not in lat[(n[0], n[1], n[2])][1]: lat[(n[0], n[1], n[2])][1].append(r) return lat def load_numlat(alignfile): # read force alignment result which is numerator lattice f = open(alignfile, 'r') f.readline() lines = f.readlines() f.close() wordseg = [] for line in lines: temp = line.split() if len(temp) == 4: if '' in temp: wordseg.append((0, 1, '')) wordseg.append((1, int(temp[1]) + 2, '')) elif '' in temp: wordseg.append((int(temp[0]) + 1, int(temp[1]) + 1, '')) wordseg.append((int(temp[1]) + 1, int(temp[1]) + 1, '')) else: wordseg.append((int(temp[0]) + 1, int(temp[1]) + 2, temp[3])) if wordseg[1][2] == wordseg[2][2] and wordseg[1][2] == '' and wordseg[ 1][1] == wordseg[2][0]: sf = wordseg[1][0] ef = wordseg[2][1] wordseg.pop(1) wordseg.pop(1) wordseg.insert(1, (sf, ef, '')) n = len(wordseg) if wordseg[n - 2][2] == wordseg[n - 3][2] and wordseg[ n - 2][2] == '' and wordseg[n - 3][1] == wordseg[n - 2][0]: sf = wordseg[n - 3][0] ef = wordseg[n - 2][1] x = wordseg.pop(n - 2) y = wordseg.pop(n - 3) wordseg.insert(n - 3, (sf, ef, '')) numlat = {} for i in range(1, len(wordseg) - 1): sf = wordseg[i][0] ef = wordseg[i][1] word = wordseg[i][2] left = [] right = [] left.append((wordseg[i - 1][0], wordseg[i - 1][2], wordseg[i - 1][1])) right.append((wordseg[i + 1][0], wordseg[i + 1][2], wordseg[i + 1][1])) numlat[(sf, word, ef)] = (left, right) return numlat def conv_lat_format(key, lat, filler, lm): # add word segment IDs and # use word IDs to present previsou and next word segments # also assign unigram language model score to each word segment newlat = [] i = 0 for sf, word, ef in key: i = i + 1 if word in filler: score = math.log(0.1) else: score = lm.prob([baseword(word)]) left = [] for context in lat[(sf, word, ef)][0]: if '' in context: ID = 0 else: ID = key.index(context) + 1 left.append(ID) right = [] for context in lat[(sf, word, ef)][1]: if '' in context: ID = 0 else: ID = key.index(context) + 1 right.append(ID) newlat.append((i, word, sf, ef, score, left, right)) return newlat def add_numlat_into_denlat(numlat, denlat): # add numerator lattice into denominator lattice n_arc = len(denlat) for i, word, sf, ef, score, left, right in numlat: aid = i + n_arc lids = [] for ids in left: if ids == 0: lids.append(ids) else: lids.append(ids + n_arc) rids = [] for ids in right: if ids == 0: rids.append(ids) else: rids.append(ids + n_arc) denlat.append((aid, word, sf, ef, score, lids, rids)) return denlat def output_lattice(lat, n_true_arc, outlatfile): # write lattice to a file f = open(outlatfile, 'w') f.write('Total arcs:\n') f.write('%d\n' % len(lat)) f.write('True arcs:\n') f.write('%d\n' % n_true_arc) f.write( 'arc_id, arc_name, start frame, end frame, lmscore, number of preceding acrs, number of succeeding arcs, preceding arc_ids, succeeding arc_ids\n' ) for ID, word, sf, ef, score, left, right in lat: if score is None: break line = str(ID) + ' ' + word + ' ' + str(sf) + ' ' + str( ef) + ' ' + str(score) + ' ' + str(len(left)) + ' ' + str( len(right)) + ' <' for lid in left: line = line + ' ' + str(lid) line = line + ' >' for rid in right: line = line + ' ' + str(rid) f.write("%s\n" % line) f.close() def write_lat(lm, filler, filelist, filecount, fileoffset, denlatdir, numlatdir, outdir): # write lattice for mmi training f = open(filelist, 'r') files = f.readlines() f.close() start = int(fileoffset) end = int(fileoffset) + int(filecount) if end > len(files): end = len(files) for i in range(start, end): line = files[i] fileid = line.strip('\n') alignfile = "%s/%s.wdseg" % (numlatdir, fileid) latfile = "%s/%s.lat.gz" % (denlatdir, fileid) print("process sent: %s" % fileid) print("\t load numerator lattice %s ... " % alignfile) try: numlat = load_numlat(alignfile) except IOError: print("\t can't open numerator lattice %s to read" % alignfile) continue print("\t load denominator lattice %s ..." % latfile) try: den_wordseg = load_denlat(latfile) except IOError: print("\t can't open denominator lattice %s to read" % latfile) continue print("\t convert numerator lattice ...") numkeys = list(numlat.keys()) numkeys.sort() conv_numlat = conv_lat_format(numkeys, numlat, filler, lm) print("\t convert denominator lattice ...") denkeys = list(den_wordseg.keys()) denkeys.sort() denlat = conv_lat_format(denkeys, den_wordseg, filler, lm) print("\t add numerator lattice into denominator lattice ...") conv_denlat = add_numlat_into_denlat(conv_numlat, denlat) numlatfile = "%s/%s.numlat" % (outdir, fileid) denlatfile = "%s/%s.denlat" % (outdir, fileid) print("\t write numerator lattice to %s ..." % numlatfile) try: output_lattice(conv_numlat, len(conv_numlat), numlatfile) except IOError: print("\t can't write numerator lattice to %s" % numlatfile) continue print("\t write denominator lattice to %s ...\n" % denlatfile) try: output_lattice(conv_denlat, len(conv_numlat), denlatfile) except IOError: print("\t can't write denominator lattice to %s" % denlatfile) print("ALL DONE\n") # If this script is being run from the command-line, do this if __name__ == '__main__': if len(sys.argv) != 9: sys.stderr.write( "Usage: %s LMFILE FILLERFILE FILELIST FILECOUNT FILEOFFSET DENLATDIR NUMLATDIR OUTLATDIR\n" % (sys.argv[0])) sys.exit(1) command = '' for argv in sys.argv: command += argv + ' ' print("%s\n" % command) lmfile, fillerfile, filelist, filecount, fileoffset, \ denlatdir, numlatdir, outdir = sys.argv[1:] # load the filler dictionary filler = load_lexicon(fillerfile) # load the language model to score the word hypothesis in a lattice lm = sphinxbase.NGramModel(lmfile) # convert lattice and output to a file write_lat(lm, filler, filelist, filecount, fileoffset, denlatdir, numlatdir, outdir)