mirror of
https://github.com/cmusphinx/sphinxtrain.git
synced 2026-06-16 13:14:30 +00:00
293 lines
8.8 KiB
Python
Executable File
293 lines
8.8 KiB
Python
Executable File
#!/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] != '<s>':
|
|
left = []
|
|
right = []
|
|
for m in arc:
|
|
if n[3] == '</s>' 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 '<s>' in temp:
|
|
wordseg.append((0, 1, '<s>'))
|
|
wordseg.append((1, int(temp[1]) + 2, '<sil>'))
|
|
elif '</s>' in temp:
|
|
wordseg.append((int(temp[0]) + 1, int(temp[1]) + 1, '<sil>'))
|
|
wordseg.append((int(temp[1]) + 1, int(temp[1]) + 1, '</s>'))
|
|
else:
|
|
wordseg.append((int(temp[0]) + 1, int(temp[1]) + 2, temp[3]))
|
|
|
|
if wordseg[1][2] == wordseg[2][2] and wordseg[1][2] == '<sil>' 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, '<sil>'))
|
|
n = len(wordseg)
|
|
if wordseg[n - 2][2] == wordseg[n - 3][2] and wordseg[
|
|
n - 2][2] == '<sil>' 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, '<sil>'))
|
|
|
|
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 '<s>' in context:
|
|
ID = 0
|
|
else:
|
|
ID = key.index(context) + 1
|
|
left.append(ID)
|
|
right = []
|
|
for context in lat[(sf, word, ef)][1]:
|
|
if '</s>' 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)
|