def main(): # ------------- Parse arguments from command line ---------------------- # 1. Add a discription of this program args.discribe("This program is used to train triphone GMM-HMM model") # 2. Add options args.add("--expDir", abbr="-e", dtype=str, default="exp", discription="The data and output path of current experiment.") args.add("--splice", abbr="-c", dtype=int, default=3, discription="How many left-right frames to splice.") args.add("--numIters", abbr="-n", dtype=int, default=35, discription="How many iterations to train.") args.add("--maxIterInc", abbr="-m", dtype=int, default=25, discription="The final iteration of increasing gaussians.") args.add("--realignIter", abbr="-r", dtype=int, default=[10, 20, 30], discription="The iteration to realign feature.") args.add("--fmllrIter", abbr="-f", dtype=int, default=[2, 4, 6, 12], discription="The iteration to estimate fmllr matrix.") args.add("--order", abbr="-o", dtype=int, default=6, discription="Which N-grams model to use.") args.add("--beam", abbr="-b", dtype=int, default=13, discription="Decode beam size.") args.add("--latBeam", abbr="-l", dtype=int, default=6, discription="Lattice beam size.") args.add("--acwt", abbr="-a", dtype=float, default=0.083333, discription="Acoustic model weight.") args.add( "--parallel", abbr="-p", dtype=int, default=4, minV=1, maxV=10, discription= "The number of parallel process to compute feature of train dataset.") args.add("--skipTrain", abbr="-s", dtype=bool, default=False, discription="If True, skip training. Do decoding only.") # 3. Then start to parse arguments. args.parse() # 4. Take a backup of arguments argsLogFile = os.path.join(args.expDir, "conf", "train_sat.args") args.save(argsLogFile) if not args.skipTrain: # ------------- Prepare feature and previous alignment for training ---------------------- # 1. Load the feature for training print(f"Load MFCC+CMVN feature.") feat = exkaldi.load_index_table( os.path.join(args.expDir, "mfcc", "train", "mfcc_cmvn.ark")) print(f"Splice {args.splice} frames.") originalFeat = exkaldi.splice_feature(feat, left=args.splice, right=args.splice, outFile=os.path.join( args.expDir, "train_delta", "mfcc_cmvn_splice.ark")) print(f"Transform LDA feature") ldaFeat = exkaldi.transform_feat( feat=originalFeat, matFile=os.path.join(args.expDir, "train_lda_mllt", "trans.mat"), outFile=os.path.join(args.expDir, "train_sat", "lda_feat.ark"), ) del originalFeat # 2. Load previous alignment and lexicons ali = exkaldi.load_index_table(os.path.join(args.expDir, "train_lda_mllt", "*final.ali"), useSuffix="ark") lexicons = exkaldi.load_lex( os.path.join(args.expDir, "dict", "lexicons.lex")) # 3. Estimate the primary fMLLR transform matrix print("Estiminate the primary fMLLR transform matrixs") fmllrTransMat = exkaldi.hmm.estimate_fMLLR_matrix( aliOrLat=ali, lexicons=lexicons, aliHmm=os.path.join(args.expDir, "train_lda_mllt", "final.mdl"), feat=ldaFeat, spk2utt=os.path.join(args.expDir, "data", "train", "spk2utt"), outFile=os.path.join(args.expDir, "train_sat", "trans.ark"), ) print("Transform feature") fmllrFeat = exkaldi.use_fmllr( ldaFeat, fmllrTransMat, utt2spk=os.path.join("exp", "data", "train", "utt2spk"), outFile=os.path.join(args.expDir, "train_sat", "fmllr_feat.ark"), ) # -------------- Build the decision tree ------------------------ print("Start build a tree") tree = exkaldi.hmm.DecisionTree(lexicons=lexicons, contextWidth=3, centralPosition=1) tree.train( feat=fmllrFeat, hmm=os.path.join(args.expDir, "train_lda_mllt", "final.mdl"), ali=ali, topoFile=os.path.join(args.expDir, "dict", "topo"), numLeaves=2500, tempDir=os.path.join(args.expDir, "train_sat"), ) tree.save(os.path.join(args.expDir, "train_sat", "tree")) print(f"Build tree done.") del fmllrFeat # ------------- Start training ---------------------- # 1. Initialize a monophone HMM object print("Initialize a triphone HMM object") model = exkaldi.hmm.TriphoneHMM(lexicons=lexicons) model.initialize( tree=tree, topoFile=os.path.join(args.expDir, "dict", "topo"), treeStatsFile=os.path.join(args.expDir, "train_sat", "treeStats.acc"), ) print(f"Initialized a monophone HMM-GMM model: {model.info}.") # 2. convert the previous alignment print(f"Transform the alignment") newAli = exkaldi.hmm.convert_alignment( ali=ali, originHmm=os.path.join(args.expDir, "train_lda_mllt", "final.mdl"), targetHmm=model, tree=tree, outFile=os.path.join(args.expDir, "train_sat", "initial.ali"), ) # 2. Split data for parallel training transcription = exkaldi.load_transcription( os.path.join(args.expDir, "data", "train", "text")) transcription = transcription.sort() if args.parallel > 1: # split feature ldaFeat = ldaFeat.sort(by="utt").subset(chunks=args.parallel) # split transcription depending on utterance IDs of each feat tempTrans = [] tempAli = [] tempFmllrMat = [] for f in ldaFeat: tempTrans.append(transcription.subset(keys=f.utts)) tempAli.append(newAli.subset(keys=f.utts)) spks = exkaldi.utt_to_spk(f.utts, utt2spk=os.path.join( args.expDir, "data", "train", "utt2spk")) tempFmllrMat.append(fmllrTransMat.subset(keys=spks)) transcription = tempTrans newAli = tempAli fmllrTransMat = tempFmllrMat # 3. Train print("Train the triphone model") model.train( ldaFeat, transcription, os.path.join(args.expDir, "dict", "L.fst"), tree, tempDir=os.path.join(args.expDir, "train_sat"), initialAli=newAli, fmllrTransMat=fmllrTransMat, spk2utt=os.path.join(args.expDir, "data", "train", "spk2utt"), utt2spk=os.path.join(args.expDir, "data", "train", "utt2spk"), numIters=args.numIters, maxIterInc=args.maxIterInc, totgauss=15000, realignIter=args.realignIter, fmllrIter=args.fmllrIter, boostSilence=1.0, power=0.2, fmllrSilWt=0.0, ) print(model.info) del ldaFeat del fmllrTransMat del newAli else: declare.is_file(os.path.join(args.expDir, "train_sat", "final.mdl")) declare.is_file(os.path.join(args.expDir, "train_sat", "tree")) model = exkaldi.load_hmm( os.path.join(args.expDir, "train_sat", "final.mdl")) tree = exkaldi.load_tree(os.path.join(args.expDir, "train_sat", "tree")) # ------------- Compile WFST training ---------------------- # Make a WFST decoding graph make_WFST_graph( outDir=os.path.join(args.expDir, "train_sat", "graph"), hmm=model, tree=tree, ) # Decode test data GMM_decode_fmllr_and_score( outDir=os.path.join(args.expDir, "train_sat", f"decode_{args.order}grams"), hmm=model, HCLGfile=os.path.join(args.expDir, "train_sat", "graph", f"HCLG.{args.order}.fst"), tansformMatFile=os.path.join(args.expDir, "train_lda_mllt", "trans.mat"), )
def train(): # ------------- Prepare data for dnn training ---------------------- stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") outDir = f"dnn_exp/out_{stamp}" exkaldi.utils.make_dependent_dirs(outDir, pathIsFile=False) args.save( os.path.join(outDir,"conf") ) #------------------------ Training and Validation dataset----------------------------- hmm = exkaldi.load_hmm(f"{args.root}/exp/tri3b_ali_train_clean_5/final.mdl") pdfDim = hmm.info.pdfs del hmm print('Prepare Data Iterator...') # Prepare fMLLR feature files featDim, trainDataset = prepare_data() traindataLen = len(trainDataset) train_gen = tf.data.Dataset.from_generator( lambda: make_generator(trainDataset), (tf.float32, tf.int32), (tf.TensorShape([featDim,]), tf.TensorShape([])), ).batch(args.batchSize).prefetch(3) steps_per_epoch = traindataLen//args.batchSize featDim, devDataset = prepare_data(training=False) devdataLen = len(devDataset) dev_gen = tf.data.Dataset.from_generator( lambda: make_generator(devDataset), (tf.float32, tf.int32), (tf.TensorShape([featDim,]), tf.TensorShape([])), ).batch(args.batchSize).prefetch(3) validation_steps = devdataLen//args.batchSize #------------------------ Train Step ----------------------------- model = make_DNN_acoustic_model(featDim,pdfDim) #model.summary() model.compile( loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics = keras.metrics.SparseCategoricalAccuracy(), optimizer = keras.optimizers.SGD(0.08,momentum=0.0), ) def lrScheduler(epoch): if epoch > 25: return 0.001 elif epoch > 22: return 0.0025 elif epoch > 19: return 0.005 elif epoch > 17: return 0.01 elif epoch > 15: return 0.02 elif epoch > 10: return 0.04 else: return 0.08 model.fit( x = train_gen, steps_per_epoch=steps_per_epoch, epochs=args.epoch, validation_data=dev_gen, validation_steps=validation_steps, verbose=1, initial_epoch=0, callbacks=[ keras.callbacks.EarlyStopping(patience=5, verbose=1), keras.callbacks.TensorBoard(log_dir=outDir), keras.callbacks.LearningRateScheduler(lrScheduler), ModelSaver(model,outDir), ], )
def main(): # ------------- Parse arguments from command line ---------------------- # 1. Add a discription of this program args.describe("This program is used to train monophone GMM-HMM model") # 2. Add options args.add("--expDir", abbr="-e", dtype=str, default="exp", discription="The data and output path of current experiment.") args.add("--delta", abbr="-d", dtype=int, default=2, discription="Add n-order to feature.") args.add("--numIters", abbr="-n", dtype=int, default=40, discription="How many iterations to train.") args.add("--maxIterInc", abbr="-m", dtype=int, default=30, discription="The final iteration of increasing gaussians.") args.add("--realignIter", abbr="-r", dtype=int, default=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 38 ], discription="the iteration to realign feature.") args.add("--order", abbr="-o", dtype=int, default=6, minV=1, maxV=6, discription="Which N-grams model to use.") args.add("--beam", abbr="-b", dtype=int, default=13, discription="Decode beam size.") args.add("--latBeam", abbr="-l", dtype=int, default=6, discription="Lattice beam size.") args.add("--acwt", abbr="-a", dtype=float, default=0.083333, discription="Acoustic model weight.") args.add( "--parallel", abbr="-p", dtype=int, default=4, minV=1, maxV=10, discription= "The number of parallel process to compute feature of train dataset.") args.add("--skipTrain", abbr="-s", dtype=bool, default=False, discription="If True, skip training. Do decoding only.") # 3. Then start to parse arguments. args.parse() # 4. Take a backup of arguments args.print_args() # print arguments to display argsLogFile = os.path.join(args.expDir, "conf", "train_mono.args") args.save(argsLogFile) if not args.skipTrain: # ------------- Prepare feature for training ---------------------- # 1. Load the feature for training (We use the index table format) feat = exkaldi.load_index_table( os.path.join(args.expDir, "mfcc", "train", "mfcc_cmvn.ark")) print(f"Load MFCC+CMVN feature.") feat = exkaldi.add_delta(feat, order=args.delta, outFile=os.path.join(args.expDir, "train_mono", "mfcc_cmvn_delta.ark")) print(f"Add {args.delta}-order deltas.") # 2. Load lexicon bank lexicons = exkaldi.load_lex( os.path.join(args.expDir, "dict", "lexicons.lex")) print(f"Restorage lexicon bank.") # ------------- Start training ---------------------- # 1. Initialize a monophone HMM object model = exkaldi.hmm.MonophoneHMM(lexicons=lexicons, name="mono") model.initialize(feat=feat, topoFile=os.path.join(args.expDir, "dict", "topo")) print(f"Initialized a monophone HMM-GMM model: {model.info}.") # 2. Split data for parallel training transcription = exkaldi.load_transcription( os.path.join(args.expDir, "data", "train", "text")) transcription = transcription.sort() if args.parallel > 1: # split feature feat = feat.sort(by="utt").subset(chunks=args.parallel) # split transcription depending on utterance IDs of each feature temp = [] for f in feat: temp.append(transcription.subset(keys=f.utts)) transcription = temp # 3. Train model.train( feat, transcription, LFile=os.path.join(args.expDir, "dict", "L.fst"), tempDir=os.path.join(args.expDir, "train_mono"), numIters=args.numIters, maxIterInc=args.maxIterInc, totgauss=1000, realignIter=args.realignIter, boostSilence=1.0, ) print(model.info) # Save the tree model.tree.save(os.path.join(args.expDir, "train_mono", "tree")) print(f"Tree has been saved.") # 4. Realign with boostSilence 1.25 print("Realign the training feature (boost silence = 1.25)") trainGraphFiles = exkaldi.utils.list_files( os.path.join(args.expDir, "train_mono", "*train_graph")) model.align( feat, trainGraphFile= trainGraphFiles, # train graphs have been generated in the train step. boostSilence=1.25, #1.5 outFile=os.path.join(args.expDir, "train_mono", "final.ali")) del feat print("Save the new alignment done.") tree = model.tree else: declare.is_file(os.path.join(args.expDir, "train_mono", "final.mdl")) declare.is_file(os.path.join(args.expDir, "train_mono", "tree")) model = exkaldi.load_hmm( os.path.join(args.expDir, "train_mono", "final.mdl")) tree = exkaldi.load_tree( os.path.join(args.expDir, "train_mono", "tree")) # ------------- Compile WFST training ---------------------- # Make a WFST decoding graph make_WFST_graph( outDir=os.path.join(args.expDir, "train_mono", "graph"), hmm=model, tree=tree, ) # Decode test data GMM_decode_mfcc_and_score( outDir=os.path.join(args.expDir, "train_mono", f"decode_{args.order}grams"), hmm=model, HCLGfile=os.path.join(args.expDir, "train_mono", "graph", f"HCLG.{args.order}.fst"), )
def compute_dev_wer(): flag = "dev_clean_2" featsFile = f"{args.root}/{args.feat}/raw_{args.feat}_{flag}.*.ark" feats = exkaldi.load_feat(featsFile) if args.cmn: print("Use cmvn...") cmvnFile = f"{args.root}/{args.feat}/cmvn_{flag}.ark" cmvn = exkaldi.load_cmvn(cmvnFile) feats = exkaldi.use_cmvn(feats,cmvn,utt2spk=f"{args.root}/data/{flag}/utt2spk") del cmvn if args.delta > 0: print("Add delta...") feats = feats.add_delta(args.delta) if args.splice > 0: print("Splice feature...") feats = feats.splice(args.splice) feats = feats.to_numpy() featDim = feats.dim hmm = exkaldi.load_hmm(f"{args.root}/exp/tri3b_ali_train_clean_5/final.mdl") pdfDim = hmm.info.pdfs phoneDim = hmm.info.phones del hmm print("featDim:",featDim,"pdfDim:",pdfDim,"phoneDim:",phoneDim) minWER = None try: for ModelPathID in range(args.epoch,0,-1): #ModelPathID = args.epoch ModelPath = f"{args.testModelDir}/model_ep{ModelPathID}.h5" if not os.path.isfile(ModelPath): continue print("Use Model:",ModelPath) decodeOut = ModelPath[:-3] exkaldi.utils.make_dependent_dirs(decodeOut,pathIsFile=False) model = make_DNN_acoustic_model(featDim,pdfDim) model.load_weights(ModelPath) print("Forward...") result = {} for uttID in feats.keys(): pdfP = model(feats[uttID],training=False) result[uttID] = exkaldi.nn.log_softmax(pdfP.numpy(),axis=1) amp = exkaldi.load_prob(result) hmmFile = f"{args.root}/exp/tri3b_ali_dev_clean_2/final.mdl" HCLGFile = f"{args.root}/exp/tri3b/graph_tgsmall/HCLG.fst" table = f"{args.root}/exp/tri3b/graph_tgsmall/words.txt" trans = f"{args.root}/data/dev_clean_2/text" print("Decoding...") lat = exkaldi.decode.wfst.nn_decode( prob=amp.subset(chunks=4), hmm=hmmFile, HCLGFile=HCLGFile, symbolTable=table, beam=10, latBeam=8, acwt=0.1, minActive=200, maxActive=7000, outFile=os.path.join(decodeOut,"lat") ) lat = exkaldi.merge_archives(lat) print("Scoring...") for LMWT in range(1,10,1): #newLat = lat.add_penalty(penalty) result = lat.get_1best(table,hmmFile,lmwt=LMWT,acwt=0.1,phoneLevel=False) result = exkaldi.hmm.transcription_from_int(result,table) result.save( os.path.join(decodeOut,f"trans.{LMWT}") ) score = exkaldi.decode.score.wer(ref=trans,hyp=result,mode="present") print("LMWT: ",LMWT ,"WER: ",score.WER) if minWER == None or score.WER < minWER[0]: minWER = (score.WER, LMWT, ModelPath) finally: if minWER is not None: werOut = os.path.basename(decodeOut) print("Best WER:",minWER) with open(f"{args.testModelDir}/best_wer","w") as fw: fw.write(str(minWER))
def main(): # ------------- Parse arguments from command line ---------------------- # 1. Add a discription of this program args.discribe("This program is used to train triphone GMM-HMM model") # 2. Add options args.add("--expDir", abbr="-e", dtype=str, default="exp", discription="The data and output path of current experiment.") args.add("--delta", abbr="-d", dtype=int, default=2, discription="Add n-order to feature.") args.add("--numIters", abbr="-n", dtype=int, default=35, discription="How many iterations to train.") args.add("--maxIterInc", abbr="-m", dtype=int, default=25, discription="The final iteration of increasing gaussians.") args.add("--realignIter", abbr="-r", dtype=int, default=[10, 20, 30], discription="the iteration to realign feature.") args.add("--order", abbr="-o", dtype=int, default=6, discription="Which N-grams model to use.") args.add("--beam", abbr="-b", dtype=int, default=13, discription="Decode beam size.") args.add("--latBeam", abbr="-l", dtype=int, default=6, discription="Lattice beam size.") args.add("--acwt", abbr="-a", dtype=float, default=0.083333, discription="Acoustic model weight.") args.add( "--parallel", abbr="-p", dtype=int, default=4, minV=1, maxV=10, discription= "The number of parallel process to compute feature of train dataset.") args.add("--skipTrain", abbr="-s", dtype=bool, default=False, discription="If True, skip training. Do decoding only.") # 3. Then start to parse arguments. args.parse() # 4. Take a backup of arguments argsLogFile = os.path.join(args.expDir, "conf", "train_delta.args") args.save(argsLogFile) if not args.skipTrain: # ------------- Prepare feature and previous alignment for training ---------------------- # 1. Load the feature for training feat = exkaldi.load_index_table( os.path.join(args.expDir, "mfcc", "train", "mfcc_cmvn.ark")) print(f"Load MFCC+CMVN feature.") feat = exkaldi.add_delta(feat, order=args.delta, outFile=os.path.join(args.expDir, "train_delta", "mfcc_cmvn_delta.ark")) print(f"Add {args.delta}-order deltas.") # 2. Load lexicon bank lexicons = exkaldi.load_lex( os.path.join(args.expDir, "dict", "lexicons.lex")) print(f"Restorage lexicon bank.") # 3. Load previous alignment ali = exkaldi.load_index_table(os.path.join(args.expDir, "train_mono", "*final.ali"), useSuffix="ark") # -------------- Build the decision tree ------------------------ print("Start build a tree") tree = exkaldi.hmm.DecisionTree(lexicons=lexicons, contextWidth=3, centralPosition=1) tree.train( feat=feat, hmm=os.path.join(args.expDir, "train_mono", "final.mdl"), ali=ali, topoFile=os.path.join(args.expDir, "dict", "topo"), numLeaves=2500, tempDir=os.path.join(args.expDir, "train_delta"), ) print(f"Build tree done.") # ------------- Start training ---------------------- # 1. Initialize a monophone HMM object model = exkaldi.hmm.TriphoneHMM(lexicons=lexicons, name="mono") model.initialize( tree=tree, topoFile=os.path.join(args.expDir, "dict", "topo"), treeStatsFile=os.path.join(args.expDir, "train_delta", "treeStats.acc"), ) print(f"Initialized a monophone HMM-GMM model: {model.info}.") # 2. convert the previous alignment print(f"Transform the alignment") newAli = exkaldi.hmm.convert_alignment( ali=ali, originHmm=os.path.join("exp", "train_mono", "final.mdl"), targetHmm=model, tree=tree, outFile=os.path.join(args.expDir, "train_delta", "initial.ali"), ) # 2. Split data for parallel training transcription = exkaldi.load_transcription( os.path.join(args.expDir, "data", "train", "text")) transcription = transcription.sort() if args.parallel > 1: # split feature feat = feat.sort(by="utt").subset(chunks=args.parallel) # split transcription depending on utterance IDs of each feat tempTrans = [] tempAli = [] for f in feat: tempTrans.append(transcription.subset(keys=f.utts)) tempAli.append(newAli.subset(keys=f.utts)) transcription = tempTrans newAli = tempAli # 3. Train print("Train the triphone model") model.train( feat, transcription, os.path.join("exp", "dict", "L.fst"), tree, tempDir=os.path.join(args.expDir, "train_delta"), initialAli=newAli, numIters=args.numIters, maxIterInc=args.maxIterInc, totgauss=15000, realignIter=args.realignIter, boostSilence=1.0, ) print(model.info) # Save the tree model.tree.save(os.path.join(args.expDir, "train_delta", "tree")) print(f"Tree has been saved.") del feat else: declare.is_file(os.path.join(args.expDir, "train_delta", "final.mdl")) declare.is_file(os.path.join(args.expDir, "train_delta", "tree")) model = exkaldi.load_hmm( os.path.join(args.expDir, "train_delta", "final.mdl")) tree = exkaldi.load_tree( os.path.join(args.expDir, "train_delta", "tree")) # ------------- Compile WFST training ---------------------- # Make a WFST decoding graph make_WFST_graph( outDir=os.path.join(args.expDir, "train_delta", "graph"), hmm=model, tree=tree, ) # Decode test data GMM_decode_mfcc_and_score( outDir=os.path.join(args.expDir, "train_delta", f"decode_{args.order}grams"), hmm=model, HCLGfile=os.path.join(args.expDir, "train_delta", "graph", f"HCLG.{args.order}.fst"), )