Files
nshmyrev 66224be606 Separate variable for mdef is not used anymore
git-svn-id: svn+ssh://svn.code.sf.net/p/cmusphinx/code/trunk/SphinxTrain@11721 94700074-3cef-4d97-a70e-9c8c206c02f5
2013-03-23 12:15:31 +00:00

261 lines
8.5 KiB
Perl

#!/usr/bin/perl
## ====================================================================
##
## Copyright (c) 2006 Carnegie Mellon University. All rights
## reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
##
## 1. Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
##
## 2. Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in
## the documentation and/or other materials provided with the
## distribution.
##
## This work was supported in part by funding from the Defense Advanced
## Research Projects Agency and the National Science Foundation of the
## United States of America, and the CMU Sphinx Speech Consortium.
##
## THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
## ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
## NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
##
## ====================================================================
##
## Author: David Huggins-Daines
##
use strict;
use File::Copy;
use File::Basename;
use File::Spec::Functions;
use File::Path;
use lib catdir(dirname($0), updir(), 'lib');
use SphinxTrain::Config;
use SphinxTrain::Util;
my ($iter, $n_parts) = @ARGV;
$iter = 1 unless defined $iter;
$n_parts = (defined($ST::CFG_NPART) ? $ST::CFG_NPART : 1) unless defined $n_parts;
$| = 1; # Turn on autoflushing
my $logdir = "$ST::CFG_LOG_DIR/11.force_align";
my $outdir = "$ST::CFG_BASE_DIR/falignout";
Log("MODULE: 11 Force-aligning transcripts\n");
if ($ST::CFG_FORCEDALIGN ne "yes") {
Log("Skipped: \$ST::CFG_FORCEDALIGN set to \'$ST::CFG_FORCEDALIGN\' in sphinx_train.cfg\n");
exit(0);
}
if ($ST::CFG_VTLN eq "yes") {
Log("Skipped: \$ST::CFG_VTLN set to \'$ST::CFG_VTLN\' in sphinx_train.cfg\n");
exit(0);
}
unless (-x catfile($ST::CFG_BIN_DIR, "sphinx3_align")
or -x catfile($ST::CFG_BIN_DIR, "sphinx3_align.exe")) {
Log("Skipped: No sphinx3_align(.exe) found in $ST::CFG_BIN_DIR\n");
Log("If you wish to do force-alignment, please copy or link the\n");
Log("sphinx3_align binary from Sphinx 3 to $ST::CFG_BIN_DIR\n");
Log("and either define \$CFG_MODEL_DIR in sphinx_train.cfg or\n");
Log("run context-independent training first.\n");
exit 1;
}
unless (defined($ST::CFG_FORCE_ALIGN_MODELDIR)
or -f "$ST::CFG_MODEL_DIR/$ST::CFG_EXPTNAME.falign_ci_$ST::CFG_DIRLABEL/means") {
Log("Skipped: No acoustic models available for force alignment\n");
Log("If you wish to do force-alignment, please define \$CFG_MODEL_DIR\n");
Log("in sphinx_train.cfg or run context-independent training first.\n");
exit 0;
}
Log("Phase 1: Cleaning up directories:");
LogProgress("logs...");
rmtree($logdir, 0, 1);
mkdir($logdir,0777);
LogProgress("output...");
rmtree($outdir, 0, 1);
mkdir($outdir,0777);
LogProgress("qmanager...");
rmtree($ST::CFG_QMGR_DIR, 0, 1);
mkdir($ST::CFG_QMGR_DIR,0777);
if (defined($ST::CFG_STSEG_DIR)) {
LogProgress("stseg...");
rmtree($ST::CFG_STSEG_DIR, 0, 1);
mkdir($ST::CFG_STSEG_DIR,0777);
}
if (defined($ST::CFG_PHSEG_DIR)) {
LogProgress("phseg...");
rmtree($ST::CFG_PHSEG_DIR, 0, 1);
mkdir($ST::CFG_PHSEG_DIR,0777);
}
if (defined($ST::CFG_WDSEG_DIR)) {
LogProgress("wdseg...");
rmtree($ST::CFG_WDSEG_DIR, 0, 1);
mkdir($ST::CFG_WDSEG_DIR,0777);
}
LogProgress("\n");
# Build state segmentation directories
if (defined($ST::CFG_PHSEG_DIR)
or defined($ST::CFG_WDSEG_DIR)
or defined($ST::CFG_STSEG_DIR)) {
Log("Phase 2: Building state/phone/word segmentation directories...");
open INPUT,"${ST::CFG_LISTOFFILES}" or die "Failed to open $ST::CFG_LISTOFFILES: $!";
my %dirs;
while (<INPUT>) {
chomp;
my @fields = split;
my $fileid = shift @fields;
my $basedir = dirname($fileid);
next if $basedir eq ".";
unless ($dirs{$basedir}) {
$dirs{$basedir}++;
mkpath(catdir($ST::CFG_STSEG_DIR, $basedir), 0, 0777)
if defined($ST::CFG_STSEG_DIR);
mkpath(catdir($ST::CFG_PHSEG_DIR, $basedir), 0, 0777)
if defined($ST::CFG_PHSEG_DIR);
mkpath(catdir($ST::CFG_WDSEG_DIR, $basedir), 0, 0777)
if defined($ST::CFG_WDSEG_DIR);
}
}
}
close INPUT;
my %silences = ();
# Create a new dictionary unless one is given
unless (defined($ST::CFG_FORCE_ALIGN_DICTIONARY) or defined($ST::CFG_FORCE_ALIGN_FILLERDICT)) {
my $dict = "$outdir/$ST::CFG_EXPTNAME.falign.dict";
my $fdict = "$outdir/$ST::CFG_EXPTNAME.falign.fdict";
my $dictfn = GetDict();
Log("Phase 3: Creating dictionary for alignment...");
open INFDICT, "<$ST::CFG_FILLERDICT" or die "Failed to open $ST::CFG_FILLERDICT: $!";
open OUTFDICT, ">$fdict" or die "Failed to open $fdict: $!";
my %fillers;
# Strip out all fillers except silence
while (<INFDICT>) {
my ($word, @phones) = split;
if (($#phones == 0) and ($phones[0] =~ m,^SIL[be]?$,i)) {
$silences{$word} = "@phones";
print OUTFDICT;
}
else {
$fillers{$word} = "@phones";
}
}
close INFDICT;
close OUTFDICT;
# Add the extra fillers to the main dictionary
open INDICT, "< $dictfn" or die "Failed to open $dictfn: $!";
open OUTDICT, ">$dict" or die "Failed to open $dict: $!";
while (<INDICT>) {
print OUTDICT;
}
for my $k (sort keys %fillers) {
print OUTDICT "$k\t$fillers{$k}\n";
}
close INDICT;
close OUTDICT;
}
# Preprocess the transcript to remove extraneous <s> and </s> markers (argh)
my $transcriptfile = "$outdir/$ST::CFG_EXPTNAME.aligninput";
Log("Phase 4: Creating transcript for alignment...");
open INPUT,"<$ST::CFG_TRANSCRIPTFILE" or die "Failed to open $ST::CFG_TRANSCRIPTFILE: $!";
open OUTPUT,">$transcriptfile" or die "Failed to open $transcriptfile: $!";
while (<INPUT>) {
chomp;
# Remove silences
foreach my $sil (keys %silences) {
s,(\s|^)\Q$sil\E(\s|$),$1$2,g;
}
# These are now done by the above removal of silence
#s,</?s>,,g;
#s,</?sil>,,g;
# Also remove pronunciation variants
s,\(\d+\),,g;
# Also normalize whitespaces
s,^\s+,,;
s,\s+$,,;
s,\s+, ,g;
print OUTPUT $_, "\n";
}
close INPUT;
close OUTPUT;
# Run n_parts of force alignment
Log("Phase 5: Running force alignment in $n_parts parts\n");
my @jobs;
for (my $i = 1; $i <= $n_parts; ++$i) {
push @jobs, LaunchScript("falign.$i", ['force_align.pl', $i, $n_parts]);
}
# Wait for them all to finish, and concatenate their output
my $listoffiles = catfile($outdir, "${ST::CFG_EXPTNAME}.alignedfiles");
my $transcriptfile = catfile($outdir, "${ST::CFG_EXPTNAME}.alignedtranscripts");
open CTL, ">$listoffiles" or die "Failed to open $listoffiles: $!";
open LSN, ">$transcriptfile" or die "Failed to open $transcriptfile: $!";
my $i = 1;
my $return_value = 0;
foreach my $job (@jobs) {
WaitForScript($job);
my $logfile = catfile($logdir, "${ST::CFG_EXPTNAME}.$i.falign.log");
open LOG, "<$logfile" or die "Failed to open $logfile: $!";
my $success = 0;
while (<LOG>) {
if (/TOTAL FRAMES/) {
$success = 1;
last;
}
}
unless ($success) {
Log("Failed in part $i");
$return_value = 1;
next;
}
close LOG;
my $part = catfile($outdir, "${ST::CFG_EXPTNAME}.alignedtranscripts.$i");
open INPUT, "<$part" or die "Failed to open $part: $!";
open INCTL,"${ST::CFG_LISTOFFILES}" or die "Failed to open $ST::CFG_LISTOFFILES: $!";
while (<INPUT>) {
my ($uttid) = (/\(([^\(\)]+)\)$/);
print LSN;
# Now scan forward in the control past any utterances that were missed
while (defined(my $ctlline = <INCTL>)) {
# For whatever reason, the full path isn't in the align output
chomp(my $ctl_uttid = (split " ", $ctlline)[-1]);
if ($ctl_uttid =~ /$uttid$/) {
print CTL $ctlline;
last;
}
}
}
++$i;
}
# Create a single pronunciation dictionary and transcript if requested
$return_value = RunScript("make_spd.pl");
exit $return_value;