https://github.com/Microsoft/CNTK
Tip revision: c98e0ed74084a6e32a7ba064f45a10bf0eaf6102 authored by Frank Seide on 23 February 2016, 21:20:20 UTC
FlattenDims2
FlattenDims2
Tip revision: c98e0ed
HTKMLFReader.cpp
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//
// HTKMLFReader.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "Basics.h"
#include "basetypes.h"
#include "htkfeatio.h" // for reading HTK features
#include "rollingwindowsource.h" // minibatch sources
#include "utterancesourcemulti.h"
#ifdef _WIN32
#include "readaheadsource.h"
#endif
#include "chunkevalsource.h"
#include "minibatchiterator.h"
#define DATAREADER_EXPORTS // creating the exports here
#include "DataReader.h"
#include "HTKMLFReader.h"
#include "Config.h"
#ifdef LEAKDETECT
#include <vld.h> // for memory leak detection
#endif
#ifdef __unix__
#include <limits.h>
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned int UNINT32;
#endif
#pragma warning(disable : 4127) // conditional expression is constant; "if (sizeof(ElemType)==sizeof(float))" triggers this
//#include <iostream>
//int msra::numa::node_override = -1; // for numahelpers.h
namespace Microsoft { namespace MSR { namespace CNTK {
template <class ElemType>
template <class ConfigRecordType>
void HTKMLFReader<ElemType>::InitFromConfig(const ConfigRecordType& readerConfig)
{
m_mbiter = NULL;
m_frameSource = NULL;
m_lattices = NULL;
m_seqTrainDeriv = NULL;
m_uttDerivBuffer = NULL;
m_minibatchBuffer.resize(0);
m_minibatchBufferIndex = 0;
m_noData = false;
m_convertLabelsToTargets = false;
m_doSeqTrain = false;
m_getMinibatchCopy = false;
m_doMinibatchBuffering = false;
m_doMinibatchBufferTruncation = false;
if (readerConfig.Exists(L"legacyMode"))
{
RuntimeError("legacy mode has been deprecated\n");
}
// If <m_framemode> is false, throw away any utterance that is longer
// than the specified <m_maxUtteranceLength>.
m_maxUtteranceLength = readerConfig(L"maxUtteranceLength", 10000);
// m_truncated:
// If true, truncate utterances to fit the minibatch size. Otherwise
// the actual minibatch size will be the length of the utterance.
// m_numberOfuttsPerMinibatch:
// If larger than one, then each minibatch contains multiple
// utterances.
m_truncated = readerConfig(L"Truncated", false);
m_numberOfuttsPerMinibatch = readerConfig(L"nbruttsineachrecurrentiter", 1);
if (m_numberOfuttsPerMinibatch < 1)
{
LogicError("nbrUttsInEachRecurrentIter cannot be less than 1.\n");
}
// Initializes variables related to multi-utterance.
m_actualnumberOfuttsPerMinibatch = m_numberOfuttsPerMinibatch;
m_sentenceEnd.assign(m_numberOfuttsPerMinibatch, true);
m_processedFrame.assign(m_numberOfuttsPerMinibatch, 0);
m_toProcess.assign(m_numberOfuttsPerMinibatch, 0);
m_switchFrame.assign(m_numberOfuttsPerMinibatch, 0);
m_currentBufferFrames.assign(m_numberOfuttsPerMinibatch, 0);
m_uttInfo.resize(m_numberOfuttsPerMinibatch);
// Checks if we need to do sequence training.
if (readerConfig.Exists(L"seqTrainCriterion"))
{
m_doSeqTrain = true;
m_seqTrainCriterion = (const wstring&) readerConfig(L"seqTrainCriterion", L"");
if ((m_seqTrainCriterion != L"mpfe") && (m_seqTrainCriterion != L"smbr"))
{
LogicError("Current Supported sequence training criterion are: mpfe, smbr.\n");
}
}
// Checks if framemode is false in sequence training.
m_framemode = readerConfig(L"frameMode", true);
if (m_framemode && m_doSeqTrain)
{
LogicError("frameMode has to be false in sequence training.\n");
}
// Checks if partial minibatches are allowed.
std::string minibatchMode(readerConfig(L"minibatchMode", "Partial"));
m_partialMinibatch = EqualCI(minibatchMode, "Partial");
// Figures out if we have to do minibatch buffering and how.
if (m_doSeqTrain)
{
m_doMinibatchBuffering = true;
if (m_truncated)
{
m_truncated = false;
m_doMinibatchBufferTruncation = true;
}
}
// Checks if we are in "write" mode or "train/test" mode.
wstring command(readerConfig(L"action", L""));
if (command == L"write")
{
m_trainOrTest = false;
PrepareForWriting(readerConfig);
}
else
{
m_trainOrTest = true;
PrepareForTrainingOrTesting(readerConfig);
}
}
template <class ElemType>
template <class ConfigRecordType>
void HTKMLFReader<ElemType>::PrepareForSequenceTraining(const ConfigRecordType& readerConfig)
{
// Parameters that we are looking for.
wstring denlatRspecifier, aliRspecifier, transModelFilename, silencePhoneStr;
ElemType oldAcousticScale;
ElemType acousticScale;
ElemType lmScale;
bool oneSilenceClass;
// Makes sure that "denlats" and "alignments" sections exist.
if (!readerConfig.Exists(L"denlats"))
{
LogicError("Sequence training requested, but \"denlats\" section is not provided.\n");
}
if (!readerConfig.Exists(L"alignments"))
{
LogicError("Sequence training requested, but \"alignments\" section is not provided.\n");
}
// Processes "denlats" section.
const ConfigRecordType& denlatConfig = readerConfig(L"denlats");
if (!denlatConfig.Exists(L"rx"))
{
LogicError("Rspecifier is not provided for denominator lattices.\n");
}
if (!denlatConfig.Exists(L"kaldiModel"))
{
LogicError("Rspecifier is not provided for Kaldi model.\n");
}
denlatRspecifier = (const wstring&) denlatConfig(L"rx");
transModelFilename = (const wstring&) (denlatConfig(L"kaldiModel"));
silencePhoneStr = (const wstring&) (denlatConfig(L"silPhoneList", L""));
oldAcousticScale = denlatConfig(L"oldAcousticScale", 0.0);
acousticScale = denlatConfig(L"acousticScale", 0.2);
lmScale = denlatConfig(L"lmScale", 1.0);
oneSilenceClass = denlatConfig(L"oneSilenceClass", true);
// Processes "alignments" section.
const ConfigRecordType& aliConfig = readerConfig(L"alignments");
if (!aliConfig.Exists(L"rx"))
{
LogicError("Rspecifier is not provided for alignments.\n");
}
aliRspecifier = (const wstring&) (aliConfig(L"rx"));
// Scans the configurations to get "readerDeriv" type input and
// "readerObj" type input. Both are feature nodes, we feed derivatives
// to training criterion node through "readerDeriv" and feed objective
// through "readerObj".
bool hasDrive = false, hasObj = false;
// for (auto iter = readerConfig.begin(); iter != readerConfig.end(); ++iter)
for (const auto& id : readerConfig.GetMemberIds())
{
const ConfigRecordType& temp = readerConfig(id);
if (temp.ExistsCurrent(L"type"))
{
wstring type = temp(L"type");
if (EqualCI(type, L"readerDeriv") || EqualCI(type, L"seqTrainDeriv") /*for back compatibility */)
{
m_nameToTypeMap[id] = InputOutputTypes::readerDeriv;
hasDrive = true;
}
else if (EqualCI(type, L"readerObj") || EqualCI(type, L"seqTrainObj") /*for back compatibility */)
{
m_nameToTypeMap[id] = InputOutputTypes::readerObj;
hasObj = true;
}
}
}
if (!hasDrive || !hasObj)
{
LogicError("Missing readerDeriv or readerObj type feature\n");
}
// Initializes sequence training interface.
m_seqTrainDeriv = new KaldiSequenceTrainingDerivative<ElemType>(
denlatRspecifier, aliRspecifier, transModelFilename,
silencePhoneStr, m_seqTrainCriterion, oldAcousticScale,
acousticScale, lmScale, oneSilenceClass);
// Initializes derivative buffering.
m_doMinibatchBuffering = true;
if (m_uttDerivBuffer != NULL)
{
LogicError("Derivative buffer has already been set, are you doing "
"sequence with some other metric that using derivative "
"buffering?\n");
}
m_uttDerivBuffer = new UtteranceDerivativeBuffer<ElemType>(
m_numberOfuttsPerMinibatch, m_seqTrainDeriv);
}
// Loads input and output data for training and testing. Below we list the
// categories for different input/output:
// features: InputOutputTypes::real
// labels: InputOutputTypes::category
// derivatives: InputOutputTypes::readerDeriv
// objectives: InputOutputTypes::readerObj
//
// Note that we treat <derivatives> and <objectives> as features, but they
// will be computed in the reader, rather then reading from disks. Those
// will then be fed to training criterion node for training purposes.
template <class ElemType>
template <class ConfigRecordType>
void HTKMLFReader<ElemType>::PrepareForTrainingOrTesting(const ConfigRecordType& readerConfig)
{
// Loads files for sequence training.
if (m_doSeqTrain)
{
PrepareForSequenceTraining(readerConfig);
}
// Variables related to multi-utterance.
// m_featuresBufferMultiUtt:
// Holds pointers to the data trunk for each utterance.
// m_featuresBufferAllocatedMultiUtt:
// Actual data stores here.
m_featuresBufferMultiUtt.assign(m_numberOfuttsPerMinibatch, NULL);
m_featuresBufferAllocatedMultiUtt.assign(m_numberOfuttsPerMinibatch, 0);
m_labelsBufferMultiUtt.assign(m_numberOfuttsPerMinibatch, NULL);
m_labelsBufferAllocatedMultiUtt.assign(m_numberOfuttsPerMinibatch, 0);
// Gets a list of features and labels. Note that we assume feature
// section has sub-field "scpFile" and label section has sub-field
// "mlfFile".
std::vector<std::wstring> featureNames;
std::vector<std::wstring> labelNames;
GetDataNamesFromConfig(readerConfig, featureNames, labelNames);
if (featureNames.size() + labelNames.size() <= 1)
{
RuntimeError("network needs at least 1 input and 1 output specified!");
}
// Loads feature files.
size_t iFeat = 0;
vector<size_t> numContextLeft;
vector<size_t> numContextRight;
vector<msra::asr::FeatureSection*>& scriptpaths = m_trainingOrTestingFeatureSections;
foreach_index (i, featureNames)
{
const ConfigRecordType& thisFeature = readerConfig(featureNames[i]);
m_featDims.push_back(thisFeature(L"dim"));
intargvector contextWindow = thisFeature(L"contextWindow", ConfigRecordType::Array(intargvector(vector<int>{1})));
if (contextWindow.size() == 1) // symmetric
{
size_t windowFrames = contextWindow[0];
if (windowFrames % 2 == 0)
RuntimeError("augmentationextent: neighbor expansion of input features to %d not symmetrical", (int) windowFrames);
size_t context = windowFrames / 2; // extend each side by this
numContextLeft.push_back(context);
numContextRight.push_back(context);
}
else if (contextWindow.size() == 2) // left context, right context
{
numContextLeft.push_back(contextWindow[0]);
numContextRight.push_back(contextWindow[1]);
}
else
{
RuntimeError("contextFrames must have 1 or 2 values specified, found %d", (int) contextWindow.size());
}
// Figures the actual feature dimension, with context.
m_featDims[i] = m_featDims[i] * (1 + numContextLeft[i] + numContextRight[i]);
// Figures out the category.
wstring type = thisFeature(L"type", L"real");
if (EqualCI(type, L"real"))
{
m_nameToTypeMap[featureNames[i]] = InputOutputTypes::real;
}
else
{
InvalidArgument("feature type must be 'real'");
}
m_featureNameToIdMap[featureNames[i]] = iFeat;
assert(iFeat == m_featureIdToNameMap.size());
m_featureIdToNameMap.push_back(featureNames[i]);
scriptpaths.push_back(new msra::asr::FeatureSection(thisFeature(L"scpFile"), thisFeature(L"rx"), thisFeature(L"featureTransform", L"")));
m_featureNameToDimMap[featureNames[i]] = m_featDims[i];
m_featuresBufferMultiIO.push_back(NULL);
m_featuresBufferAllocatedMultiIO.push_back(0);
iFeat++;
}
// Loads label files.
size_t iLabel = 0;
vector<wstring> statelistpaths;
vector<wstring> mlfpaths;
vector<vector<wstring>> mlfpathsmulti;
foreach_index (i, labelNames)
{
const ConfigRecordType& thisLabel = readerConfig(labelNames[i]);
// Figures out label dimension.
if (thisLabel.Exists(L"labelDim"))
m_labelDims.push_back(thisLabel(L"labelDim"));
else if (thisLabel.Exists(L"dim"))
m_labelDims.push_back(thisLabel(L"dim"));
else
InvalidArgument("labels must specify dim or labelDim");
// Figures out the category.
wstring type;
if (thisLabel.Exists(L"labelType"))
type = (const wstring&) thisLabel(L"labelType"); // let's deprecate this eventually and just use "type"...
else
type = (const wstring&) thisLabel(L"type", L"category"); // outputs should default to category
if (EqualCI(type, L"category"))
m_nameToTypeMap[labelNames[i]] = InputOutputTypes::category;
else
InvalidArgument("label type must be Category");
// Loads label mapping.
statelistpaths.push_back(thisLabel(L"labelMappingFile", L""));
m_labelNameToIdMap[labelNames[i]] = iLabel;
assert(iLabel == m_labelIdToNameMap.size());
m_labelIdToNameMap.push_back(labelNames[i]);
m_labelNameToDimMap[labelNames[i]] = m_labelDims[i];
mlfpaths.clear();
mlfpaths.push_back(thisLabel(L"mlfFile"));
mlfpathsmulti.push_back(mlfpaths);
m_labelsBufferMultiIO.push_back(NULL);
m_labelsBufferAllocatedMultiIO.push_back(0);
iLabel++;
// Figures out label to target mapping.
wstring labelToTargetMappingFile(thisLabel(L"labelToTargetMappingFile", L""));
if (labelToTargetMappingFile != L"")
{
std::vector<std::vector<ElemType>> labelToTargetMap;
m_convertLabelsToTargetsMultiIO.push_back(true);
if (thisLabel.Exists(L"targetDim"))
{
m_labelNameToDimMap[labelNames[i]] = m_labelDims[i] = thisLabel(L"targetDim");
}
else
RuntimeError("output must specify targetDim if labelToTargetMappingFile specified!");
size_t targetDim = ReadLabelToTargetMappingFile(labelToTargetMappingFile, statelistpaths[i], labelToTargetMap);
if (targetDim != m_labelDims[i])
RuntimeError("mismatch between targetDim and dim found in labelToTargetMappingFile");
m_labelToTargetMapMultiIO.push_back(labelToTargetMap);
}
else
{
m_convertLabelsToTargetsMultiIO.push_back(false);
m_labelToTargetMapMultiIO.push_back(std::vector<std::vector<ElemType>>());
}
}
// Sanity check.
if (iFeat != scriptpaths.size() || iLabel != mlfpathsmulti.size())
throw std::runtime_error(msra::strfun::strprintf("# of inputs files vs. # of inputs or # of output files vs # of outputs inconsistent\n"));
// Loads randomization method.
size_t randomize = randomizeAuto;
if (readerConfig.Exists(L"randomize"))
{
const std::string& randomizeString = readerConfig(L"randomize");
if (EqualCI(randomizeString, "none"))
{
randomize = randomizeNone;
}
else if (EqualCI(randomizeString, "auto"))
{
randomize = randomizeAuto;
}
else
{
randomize = readerConfig(L"randomize");
}
}
// Open script files for features.
size_t numFiles = 0;
size_t firstfilesonly = SIZE_MAX; // set to a lower value for testing
vector<wstring> filelist;
vector<vector<wstring>> infilesmulti;
foreach_index (i, scriptpaths)
{
filelist.clear();
std::wstring scriptpath = scriptpaths[i]->scpFile;
fprintf(stderr, "reading script file %S ...", scriptpath.c_str());
size_t n = 0;
for (msra::files::textreader reader(scriptpath); reader && filelist.size() <= firstfilesonly /*optimization*/;)
{
filelist.push_back(reader.wgetline());
n++;
}
fprintf(stderr, " %lu entries\n", n);
if (i == 0)
numFiles = n;
else if (n != numFiles)
throw std::runtime_error(msra::strfun::strprintf("number of files in each scriptfile inconsistent (%d vs. %d)", numFiles, n));
infilesmulti.push_back(filelist);
}
// Opens MLF files for labels.
set<wstring> restrictmlftokeys;
double htktimetoframe = 100000.0; // default is 10ms
std::vector<std::map<std::wstring, std::vector<msra::asr::htkmlfentry>>> labelsmulti;
int targets_delay = 0;
if (readerConfig.Exists(L"targets_delay"))
{
targets_delay = readerConfig(L"targets_delay");
}
foreach_index (i, mlfpathsmulti)
{
msra::asr::htkmlfreader<msra::asr::htkmlfentry, msra::lattices::lattice::htkmlfwordsequence>
labels(mlfpathsmulti[i], restrictmlftokeys, statelistpaths[i], htktimetoframe, targets_delay); // label MLF
// get the temp file name for the page file
labelsmulti.push_back(labels);
}
// Get the readMethod, default value is "blockRandomize", the other
// option is "rollingWindow". We only support "blockRandomize" in
// sequence training.
std::string readMethod(readerConfig(L"readMethod", "blockRandomize"));
if (EqualCI(readMethod, "blockRandomize"))
{
// construct all the parameters we don't need, but need to be passed to the constructor...
std::pair<std::vector<wstring>, std::vector<wstring>> latticetocs;
std::unordered_map<std::string, size_t> modelsymmap;
// Note, we are actually not using <m_lattices>, the only reason we
// kept it was because it was required by
// <minibatchutterancesourcemulti>.
m_lattices = new msra::dbn::latticesource(latticetocs, modelsymmap, L"");
// now get the frame source. This has better randomization and doesn't create temp files
m_frameSource = new msra::dbn::minibatchutterancesourcemulti(
scriptpaths, infilesmulti, labelsmulti, m_featDims, m_labelDims,
numContextLeft, numContextRight, randomize, *m_lattices, m_latticeMap, m_framemode);
}
else if (EqualCI(readMethod, "rollingWindow"))
{
// "rollingWindow" is not supported in sequence training.
if (m_doSeqTrain)
{
LogicError("rollingWindow is not supported in sequence training.\n");
}
std::wstring pageFilePath;
std::vector<std::wstring> pagePaths;
if (readerConfig.Exists(L"pageFilePath"))
{
pageFilePath = (const wstring&) readerConfig(L"pageFilePath");
// replace any '/' with '\' for compat with default path
std::replace(pageFilePath.begin(), pageFilePath.end(), '/', '\\');
#ifdef _WIN32
// verify path exists
DWORD attrib = GetFileAttributes(pageFilePath.c_str());
if (attrib == INVALID_FILE_ATTRIBUTES || !(attrib & FILE_ATTRIBUTE_DIRECTORY))
throw std::runtime_error("pageFilePath does not exist");
#endif
#ifdef __unix__
struct stat statbuf;
if (stat(wtocharpath(pageFilePath).c_str(), &statbuf) == -1)
{
RuntimeError("pageFilePath does not exist");
}
#endif
}
else // using default temporary path
{
#ifdef _WIN32
pageFilePath.reserve(MAX_PATH);
GetTempPath(MAX_PATH, &pageFilePath[0]);
#endif
#ifdef __unix__
pageFilePath.reserve(PATH_MAX);
pageFilePath = L"/tmp/temp.CNTK.XXXXXX";
#endif
}
#ifdef _WIN32
if (pageFilePath.size() > MAX_PATH - 14) // max length of input to GetTempFileName is PATH_MAX-14
throw std::runtime_error(msra::strfun::strprintf("pageFilePath must be less than %d characters", MAX_PATH - 14));
#endif
#ifdef __unix__
if (pageFilePath.size() > PATH_MAX - 14) // max length of input to GetTempFileName is PATH_MAX-14
throw std::runtime_error(msra::strfun::strprintf("pageFilePath must be less than %d characters", PATH_MAX - 14));
#endif
foreach_index (i, infilesmulti)
{
#ifdef _WIN32
wchar_t tempFile[MAX_PATH];
GetTempFileName(pageFilePath.c_str(), L"CNTK", 0, tempFile);
pagePaths.push_back(tempFile);
#endif
#ifdef __unix__
char* tempFile;
// GetTempFileName(pageFilePath.c_str(), L"CNTK", 0, tempFile);
tempFile = (char*) pageFilePath.c_str();
int fid = mkstemp(tempFile);
unlink(tempFile);
close(fid);
pagePaths.push_back(GetWC(tempFile));
#endif
}
const bool mayhavenoframe = false;
int addEnergy = 0;
// m_frameSourceMultiIO = new msra::dbn::minibatchframesourcemulti(infilesmulti, labelsmulti, m_featDims, m_labelDims, randomize, pagepath, mayhavenoframe, addEnergy);
// m_frameSourceMultiIO->setverbosity(verbosity);
int verbosity = readerConfig(L"verbosity", 2);
m_frameSource = new msra::dbn::minibatchframesourcemulti(scriptpaths, infilesmulti, labelsmulti, m_featDims, m_labelDims, numContextLeft, numContextRight, randomize, pagePaths, mayhavenoframe, addEnergy);
m_frameSource->setverbosity(verbosity);
}
else
{
RuntimeError("readMethod must be rollingWindow or blockRandomize");
}
}
// Loads input and output data for training and testing. Below we list the
// categories for different input/output:
// features: InputOutputTypes::real
// labels: InputOutputTypes::category
template <class ElemType>
template <class ConfigRecordType>
void HTKMLFReader<ElemType>::PrepareForWriting(const ConfigRecordType& readerConfig)
{
// Gets a list of features and labels. Note that we assume feature
// section names have prefix "features" and label section names have
// prefix "labels".
std::vector<std::wstring> featureNames;
std::vector<std::wstring> labelNames;
GetDataNamesFromConfig(readerConfig, featureNames, labelNames);
// Loads feature files.
size_t iFeat = 0;
vector<size_t> numContextLeft;
vector<size_t> numContextRight;
vector<size_t> realDims;
vector<msra::asr::FeatureSection*>& scriptpaths = m_writingFeatureSections;
foreach_index (i, featureNames)
{
ConfigParameters thisFeature = readerConfig(featureNames[i]);
// Figures out the context.
ConfigArray contextWindow = thisFeature("contextWindow", "1");
if (contextWindow.size() == 1) // symmetric
{
size_t windowFrames = contextWindow[0];
if (windowFrames % 2 == 0)
RuntimeError("augmentationextent: neighbor expansion of input features to %d not symmetrical", (int) windowFrames);
size_t context = windowFrames / 2; // extend each side by this
numContextLeft.push_back(context);
numContextRight.push_back(context);
}
else if (contextWindow.size() == 2) // left context, right context
{
numContextLeft.push_back(contextWindow[0]);
numContextRight.push_back(contextWindow[1]);
}
else
{
RuntimeError("contextFrames must have 1 or 2 values specified, found %d", (int) contextWindow.size());
}
// Figures out the feature dimension, with context.
realDims.push_back(thisFeature("dim"));
realDims[i] = realDims[i] * (1 + numContextLeft[i] + numContextRight[i]);
// Figures out the category.
string type = thisFeature("type", "Real");
if (type == "Real")
{
m_nameToTypeMap[featureNames[i]] = InputOutputTypes::real;
}
else
{
RuntimeError("feature type must be Real");
}
m_featureNameToIdMap[featureNames[i]] = iFeat;
assert(iFeat == m_featureIdToNameMap.size());
m_featureIdToNameMap.push_back(featureNames[i]);
scriptpaths.push_back(new msra::asr::FeatureSection(thisFeature("scpFile"), thisFeature("rx"), thisFeature("featureTransform", "")));
m_featureNameToDimMap[featureNames[i]] = realDims[i];
m_featuresBufferMultiIO.push_back(NULL);
m_featuresBufferAllocatedMultiIO.push_back(0);
iFeat++;
}
// Writing labels is not supported.
if (labelNames.size() > 0)
RuntimeError("writer mode does not support labels as inputs, only features");
// Opens script files correspond to features.
size_t numFiles = 0;
vector<wstring> filelist;
size_t firstfilesonly = SIZE_MAX; // set to a lower value for testing
size_t evalchunksize = 2048;
foreach_index (i, scriptpaths)
{
filelist.clear();
std::wstring scriptpath = scriptpaths[i]->scpFile;
fprintf(stderr, "reading script file %S ...", scriptpath.c_str());
size_t n = 0;
for (msra::files::textreader reader(scriptpath); reader && filelist.size() <= firstfilesonly /*optimization*/;)
{
filelist.push_back(reader.wgetline());
n++;
}
fprintf(stderr, " %zu entries\n", n);
if (i == 0)
numFiles = n;
else if (n != numFiles)
throw std::runtime_error(msra::strfun::strprintf("HTKMLFReader::InitEvalReader: number of files in each scriptfile inconsistent (%d vs. %d)", numFiles, n));
m_inputFilesMultiIO.push_back(filelist);
}
m_fileEvalSource = new msra::dbn::FileEvalSource(realDims, numContextLeft, numContextRight, evalchunksize);
}
// destructor - virtual so it gets called properly
template <class ElemType>
HTKMLFReader<ElemType>::~HTKMLFReader()
{
delete m_mbiter;
delete m_frameSource;
delete m_lattices;
delete m_seqTrainDeriv;
delete m_uttDerivBuffer;
foreach_index(i, m_featuresBufferMultiIO)
delete[] m_featuresBufferMultiIO[i];
foreach_index(i, m_labelsBufferMultiIO)
delete[] m_labelsBufferMultiIO[i];
for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
delete[] m_featuresBufferMultiUtt[i];
delete[] m_labelsBufferMultiUtt[i];
}
foreach_index (i, m_trainingOrTestingFeatureSections)
delete m_trainingOrTestingFeatureSections[i];
foreach_index (i, m_writingFeatureSections)
delete m_writingFeatureSections[i];
}
// StartMinibatchLoop - Startup a minibatch loop
// mbSize - [in] size of the minibatch (number of frames, etc.)
// epoch - [in] epoch number for this loop
// requestedEpochSamples - [in] number of samples to randomize, defaults to requestDataSize which uses the number of samples there are in the dataset
template <class ElemType>
void HTKMLFReader<ElemType>::StartMinibatchLoop(size_t mbSize, size_t epoch, size_t requestedEpochSamples)
{
m_mbSize = mbSize;
m_currentMBSize = mbSize;
if (m_trainOrTest)
{
StartMinibatchLoopToTrainOrTest(mbSize, epoch, requestedEpochSamples);
}
else
{
StartMinibatchLoopToWrite(mbSize, epoch, requestedEpochSamples);
}
m_checkDictionaryKeys = true;
}
template <class ElemType>
void HTKMLFReader<ElemType>::StartMinibatchLoopToTrainOrTest(size_t mbSize, size_t epoch, size_t requestedEpochSamples)
{
size_t datapasses = 1;
size_t totalFrames = m_frameSource->totalframes();
size_t extraFrames = totalFrames % mbSize;
size_t minibatches = totalFrames / mbSize;
// If partial minibatch is not allowed, we have to modify <totalFrames>
// and <requestedEpochSamples>.
if (!m_partialMinibatch)
{
if (totalFrames > mbSize)
{
totalFrames -= extraFrames;
}
if (requestedEpochSamples == requestDataSize)
{
requestedEpochSamples = totalFrames;
}
else if (minibatches > 0) // if we have any full minibatches
{
// since we skip the extraFrames, we need to add them to the total to get the actual number of frames requested
size_t sweeps = (requestedEpochSamples - 1) / totalFrames; // want the number of sweeps we will skip the extra, so subtract 1 and divide
requestedEpochSamples += extraFrames * sweeps;
}
}
else if (requestedEpochSamples == requestDataSize)
{
requestedEpochSamples = totalFrames;
}
// Gets a new minibatch iterator.
if (m_mbiter != NULL)
{
delete m_mbiter;
m_mbiter = NULL;
}
msra::dbn::minibatchsource* source = m_frameSource;
size_t currentMBSize = (m_framemode == true) ? mbSize : 1;
m_mbiter = new msra::dbn::minibatchiterator(*source, epoch, requestedEpochSamples, currentMBSize, datapasses);
// Resets utterance derivative buffering class.
if (m_doMinibatchBuffering)
{
assert(m_uttDerivBuffer != NULL);
m_uttDerivBuffer->ResetEpoch();
}
// Clears minibatch buffer.
m_minibatchBuffer.clear();
m_getMinibatchCopy = false;
m_minibatchBufferIndex = 0;
m_uttInfo.clear();
m_minibatchUttInfo.clear();
// Clears feature and label buffer.
if (!m_featuresBufferMultiIO.empty())
{
foreach_index (i, m_featuresBufferMultiIO)
{
if (m_featuresBufferMultiIO[i] != NULL)
{
delete[] m_featuresBufferMultiIO[i];
m_featuresBufferMultiIO[i] = NULL;
m_featuresBufferAllocatedMultiIO[i] = 0;
}
}
}
if (!m_labelsBufferMultiIO.empty())
{
foreach_index (i, m_labelsBufferMultiIO)
{
if (m_labelsBufferMultiIO[i] != NULL)
{
delete[] m_labelsBufferMultiIO[i];
m_labelsBufferMultiIO[i] = NULL;
m_labelsBufferAllocatedMultiIO[i] = 0;
}
}
}
m_noData = false;
m_featuresStartIndexMultiUtt.assign(m_featuresBufferMultiIO.size() * m_numberOfuttsPerMinibatch, 0);
m_labelsStartIndexMultiUtt.assign(m_labelsBufferMultiIO.size() * m_numberOfuttsPerMinibatch, 0);
for (size_t u = 0; u < m_numberOfuttsPerMinibatch; u++)
{
if (m_featuresBufferMultiUtt[u] != NULL)
{
delete[] m_featuresBufferMultiUtt[u];
m_featuresBufferMultiUtt[u] = NULL;
m_featuresBufferAllocatedMultiUtt[u] = 0;
}
if (m_labelsBufferMultiUtt[u] != NULL)
{
delete[] m_labelsBufferMultiUtt[u];
m_labelsBufferMultiUtt[u] = NULL;
m_labelsBufferAllocatedMultiUtt[u] = 0;
}
ReNewBufferForMultiIO(u);
}
}
template <class ElemType>
void HTKMLFReader<ElemType>::StartMinibatchLoopToWrite(size_t mbSize, size_t /*epoch*/, size_t /*requestedEpochSamples*/)
{
m_fileEvalSource->Reset();
m_fileEvalSource->SetMinibatchSize(mbSize);
// m_chunkEvalSourceMultiIO->reset();
m_inputFileIndex = 0;
foreach_index (i, m_featuresBufferMultiIO)
{
if (m_featuresBufferMultiIO[i] != NULL)
{
delete[] m_featuresBufferMultiIO[i];
m_featuresBufferMultiIO[i] = NULL;
m_featuresBufferAllocatedMultiIO[i] = 0;
}
}
}
// GetMinibatch - Get the next minibatch (features and labels)
// matrices - [in] a map with named matrix types (i.e. 'features', 'labels') mapped to the corresponding matrix,
// [out] each matrix resized if necessary containing data.
// returns - true if there are more minibatches, false if no more minibatchs remain
template <class ElemType>
bool HTKMLFReader<ElemType>::GetMinibatch(std::map<std::wstring, Matrix<ElemType>*>& matrices)
{
if (m_trainOrTest)
{
return GetMinibatchToTrainOrTest(matrices);
}
else
{
return GetMinibatchToWrite(matrices);
}
}
// The notation of "utterance" here is a little bit tricky:
// If <frameMode> is true, then it is just a trunk of data we read from
// minibatch iterator.
// If <frameMode> is false, then it is a real utterance we read from
// minibatch iterator.
// Note, startFrame and endFrame are left close and right open. For example,
// if startFrame = 5, endFrame = 10, then we copy frames 5, 6, 7, 8, 9.
template <class ElemType>
bool HTKMLFReader<ElemType>::PopulateUtteranceInMinibatch(
const std::map<std::wstring, Matrix<ElemType>*>& matrices,
size_t uttIndex, size_t startFrame,
size_t endFrame, size_t mbSize, size_t mbOffset)
{
bool success = true;
// Sanity check.
if (startFrame >= endFrame)
{
return false;
}
if (endFrame - startFrame > mbSize)
{
return false;
}
size_t numOfFea = m_featuresBufferMultiIO.size();
size_t numOfLabel = m_labelsBufferMultiIO.size();
for (auto iter = matrices.begin(); iter != matrices.end(); iter++)
{
if (m_nameToTypeMap[iter->first] == InputOutputTypes::real)
{ // Features.
size_t id = m_featureNameToIdMap[iter->first];
size_t dim = m_featureNameToDimMap[iter->first];
if (m_featuresBufferMultiIO[id] == NULL)
{
m_featuresBufferMultiIO[id] = new ElemType[dim * mbSize * m_numberOfuttsPerMinibatch];
m_featuresBufferAllocatedMultiIO[id] = dim * mbSize * m_numberOfuttsPerMinibatch;
}
else if (m_featuresBufferAllocatedMultiIO[id] < dim * mbSize * m_numberOfuttsPerMinibatch)
{ // Buffer too small, we have to increase it.
delete[] m_featuresBufferMultiIO[id];
m_featuresBufferMultiIO[id] = new ElemType[dim * mbSize * m_numberOfuttsPerMinibatch];
m_featuresBufferAllocatedMultiIO[id] = dim * mbSize * m_numberOfuttsPerMinibatch;
}
if (sizeof(ElemType) == sizeof(float))
{ // For float, we copy entire column.
for (size_t j = startFrame, k = 0; j < endFrame; j++, k++)
{
memcpy_s(&m_featuresBufferMultiIO[id][((k + mbOffset) * m_numberOfuttsPerMinibatch + uttIndex) * dim],
sizeof(ElemType) * dim,
&m_featuresBufferMultiUtt[uttIndex][j * dim + m_featuresStartIndexMultiUtt[id + uttIndex * numOfFea]],
sizeof(ElemType) * dim);
}
}
else
{ // For double, we have to copy element by element.
for (size_t j = startFrame, k = 0; j < endFrame; j++, k++)
{
for (int d = 0; d < dim; d++)
{
m_featuresBufferMultiIO[id][((k + mbOffset) * m_numberOfuttsPerMinibatch + uttIndex) * dim + d] = m_featuresBufferMultiUtt[uttIndex][j * dim + d + m_featuresStartIndexMultiUtt[id + uttIndex * numOfFea]];
}
}
}
}
else if (m_nameToTypeMap[iter->first] == InputOutputTypes::category)
{ // Labels.
size_t id = m_labelNameToIdMap[iter->first];
size_t dim = m_labelNameToDimMap[iter->first];
if (m_labelsBufferMultiIO[id] == NULL)
{
m_labelsBufferMultiIO[id] = new ElemType[dim * mbSize * m_numberOfuttsPerMinibatch];
m_labelsBufferAllocatedMultiIO[id] = dim * mbSize * m_numberOfuttsPerMinibatch;
}
else if (m_labelsBufferAllocatedMultiIO[id] < dim * mbSize * m_numberOfuttsPerMinibatch)
{
delete[] m_labelsBufferMultiIO[id];
m_labelsBufferMultiIO[id] = new ElemType[dim * mbSize * m_numberOfuttsPerMinibatch];
m_labelsBufferAllocatedMultiIO[id] = dim * mbSize * m_numberOfuttsPerMinibatch;
}
for (size_t j = startFrame, k = 0; j < endFrame; j++, k++)
{
for (int d = 0; d < dim; d++)
{
m_labelsBufferMultiIO[id][((k + mbOffset) * m_numberOfuttsPerMinibatch + uttIndex) * dim + d] = m_labelsBufferMultiUtt[uttIndex][j * dim + d + m_labelsStartIndexMultiUtt[id + uttIndex * numOfLabel]];
}
}
}
}
return success;
}
template <class ElemType>
bool HTKMLFReader<ElemType>::GetOneMinibatchToTrainOrTestDataBuffer(
const std::map<std::wstring, Matrix<ElemType>*>& matrices)
{
bool skip = false;
// On first minibatch, check if we have input for given names.
if (m_checkDictionaryKeys)
{
for (auto iter = matrices.begin(); iter != matrices.end(); iter++)
{
if (m_nameToTypeMap.find(iter->first) == m_nameToTypeMap.end())
{
throw std::runtime_error(msra::strfun::strprintf(
"minibatch requested for input node %S not found in"
"reader - cannot generate input\n",
iter->first.c_str()));
}
}
m_checkDictionaryKeys = false;
}
// If we are doing utterance derivative buffering, we need to keep the
// utterance information.
if (m_doMinibatchBuffering)
{
m_minibatchUttInfo.assign(m_numberOfuttsPerMinibatch,
std::vector<std::pair<wstring, size_t>>(0));
// For the moment we don't support same utterance in the same
// minibatch.
m_hasUttInCurrentMinibatch.clear();
for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
while (m_hasUttInCurrentMinibatch.find(m_uttInfo[i][0].first) != m_hasUttInCurrentMinibatch.end())
{
fprintf(stderr, "WARNING: Utterance \"%S\" already exists "
"in the minibatch, skipping it.\n",
m_uttInfo[i][0].first.c_str());
ReNewBufferForMultiIO(i);
}
if (m_uttInfo[i].size() > 0)
{
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
}
}
m_currentMBSize = m_mbSize;
do
{
// Checks if we have finished all the utterances.
if (m_noData)
{
bool endEpoch = true;
for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
if (m_processedFrame[i] != m_toProcess[i])
{
endEpoch = false;
}
}
if (endEpoch)
{
return false;
}
}
// If <m_truncated> is true, <m_currentMBSize> is <m_mbSize>
// If <m_truncated> is false, <m_currentMBSize> equals to the longest
// utterance in the minibatch.
if (!m_truncated)
{
m_currentMBSize = 0;
for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
if (m_currentBufferFrames[i] > m_currentMBSize)
{
m_currentMBSize = m_currentBufferFrames[i];
}
}
}
// We initialize the sentence boundary information before we process
// the utterances.
if (m_framemode)
{
assert(m_numberOfuttsPerMinibatch == 1);
m_pMBLayout->InitAsFrameMode(m_currentMBSize);
}
else
{
m_pMBLayout->Init(m_numberOfuttsPerMinibatch, m_currentMBSize);
}
/*for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
for (size_t j = 0; j < m_currentMBSize; j++)
{
m_pMBLayout->SetWithoutOr(i, j, MinibatchPackingFlags::None);
}
}*/
// Iterates over utterances. m_numberOfuttsPerMinibatch = 1 is a
// special case.
for (size_t i = 0; i < m_numberOfuttsPerMinibatch; i++)
{
size_t startFrame = m_processedFrame[i];
size_t endFrame = 0;
// Sets the utterance boundary.
if (!m_framemode)
{
if (m_toProcess[i] > startFrame)
{
m_pMBLayout->AddSequence(NEW_SEQUENCE_ID, i, -(ptrdiff_t) startFrame, m_toProcess[i] - startFrame);
}
}
// m_pMBLayout->Set(i, 0, MinibatchPackingFlags::SequenceStart);
if ((startFrame + m_currentMBSize) < m_toProcess[i])
{
// There is only 1 case:
// 1. <m_framemode> is false, and <m_truncated> is true.
assert(m_framemode == false);
assert(m_truncated == true);
endFrame = startFrame + m_currentMBSize;
bool populateSucc = PopulateUtteranceInMinibatch(matrices, i, startFrame, endFrame, m_currentMBSize);
if (m_doMinibatchBuffering && populateSucc)
{
m_minibatchUttInfo[i].push_back(m_uttInfo[i][0]);
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
m_processedFrame[i] += m_currentMBSize;
}
else if ((startFrame + m_currentMBSize) == m_toProcess[i])
{
// There are 3 cases:
// 1. <m_framemode> is false, and <m_truncated> is true,
// and it reaches the end of the utterance.
// 2. <m_framemode> is false, and <m_truncated> is false
// and it reaches the end of the utterance.
// 3. <m_framemode> is true, then we do not have to set
// utterance boundary.
// Sets the utterance boundary.
/*if (m_framemode == false)
{
if (startFrame == 0)
{
m_pMBLayout->Set(i, 0, MinibatchPackingFlags::SequenceStart);
}
// We have to set the utterance end.
m_pMBLayout->Set(i, m_pMBLayout->GetNumTimeSteps() - 1, MinibatchPackingFlags::SequenceEnd);
}*/
// Now puts the utterance into the minibatch, and loads the
// next one.
endFrame = startFrame + m_currentMBSize;
bool populateSucc = PopulateUtteranceInMinibatch(matrices, i, startFrame, endFrame, m_currentMBSize);
if (m_doMinibatchBuffering && populateSucc)
{
m_minibatchUttInfo[i].push_back(m_uttInfo[i][0]);
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
m_processedFrame[i] += m_currentMBSize;
bool reNewSucc = ReNewBufferForMultiIO(i);
}
else
{
// There are 3 cases:
// 1. <m_framemode> is true, then it must be a partial
// minibatch.
// 2. <m_framemode> is false, <m_truncated> is true,
// then we have to pull frames from next utterance.
// 3. <m_framemode> is false, <m_truncated> is false,
// then the utterance is too short, we should try to
// pull next utterance.
// Checks if we have reached the end of the minibatch.
if (startFrame == m_toProcess[i])
{
m_pMBLayout->AddGap(i, 0, m_currentMBSize);
for (size_t k = 0; k < m_currentMBSize; k++)
{
// m_pMBLayout->Set(i, k, MinibatchPackingFlags::NoInput);
// Populates <NO_INPUT> with real features, the
// following implementation is not efficient...
PopulateUtteranceInMinibatch(matrices, i, 0, 1, m_currentMBSize, k);
}
continue;
}
// First, if <m_framemode> is true, then it must be a
// partial minibatch, and if that is not allowed, we have to
// skip this minibatch.
if (m_framemode && !m_partialMinibatch)
{
skip = true;
bool reNewSucc = ReNewBufferForMultiIO(i); // Should return false?
continue;
}
// Second, we set utterance boundary for the partial
// minibatch, and then load it.
/* if (m_framemode == false)
{
if (startFrame == 0)
{
m_pMBLayout->Set(i, 0, MinibatchPackingFlags::SequenceStart);
}
// We have to set the utterance end.
assert(m_toProcess[i] - startFrame - 1 < m_pMBLayout->GetNumTimeSteps());
m_pMBLayout->Set(i, m_toProcess[i] - startFrame - 1, MinibatchPackingFlags::SequenceEnd);
}*/
endFrame = m_toProcess[i];
size_t currentMBFilled = endFrame - startFrame;
bool populateSucc = PopulateUtteranceInMinibatch(matrices, i, startFrame, endFrame, m_currentMBSize);
if (m_doMinibatchBuffering && populateSucc)
{
m_minibatchUttInfo[i].push_back(m_uttInfo[i][0]);
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
m_processedFrame[i] += currentMBFilled;
bool reNewSucc = ReNewBufferForMultiIO(i);
// Third, if the next utterance can fit into the current
// minibatch, we also pack the next utterance.
while (reNewSucc && (currentMBFilled + m_toProcess[i] <= m_currentMBSize))
{
// Sets the utterance boundary.
assert(currentMBFilled + m_toProcess[i] <= m_pMBLayout->GetNumTimeSteps());
m_pMBLayout->AddSequence(NEW_SEQUENCE_ID, i, currentMBFilled, currentMBFilled + m_toProcess[i]);
// m_pMBLayout->Set(i, currentMBFilled, MinibatchPackingFlags::SequenceStart);
// m_pMBLayout->Set(i, currentMBFilled + m_toProcess[i] - 1, MinibatchPackingFlags::SequenceEnd);
populateSucc = PopulateUtteranceInMinibatch(matrices, i, 0, m_toProcess[i], m_currentMBSize, currentMBFilled);
if (m_doMinibatchBuffering && populateSucc)
{
m_minibatchUttInfo[i].push_back(m_uttInfo[i][0]);
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
assert(m_processedFrame[i] == 0);
m_processedFrame[i] = m_toProcess[i];
currentMBFilled += m_toProcess[i];
reNewSucc = ReNewBufferForMultiIO(i);
}
// Finally, pulls frames from next utterance if the current
// minibatch is not full.
if (reNewSucc && !m_framemode && m_truncated)
{
populateSucc = PopulateUtteranceInMinibatch(matrices, i, 0, m_currentMBSize - currentMBFilled, m_currentMBSize, currentMBFilled);
if (m_doMinibatchBuffering && populateSucc)
{
m_minibatchUttInfo[i].push_back(m_uttInfo[i][0]);
m_hasUttInCurrentMinibatch[m_uttInfo[i][0].first] = true;
}
m_processedFrame[i] += m_currentMBSize - currentMBFilled;
if (currentMBFilled < m_currentMBSize)
{
m_pMBLayout->AddSequence(NEW_SEQUENCE_ID, i, currentMBFilled, currentMBFilled + m_toProcess[i]);
// m_pMBLayout->Set(i, currentMBFilled, MinibatchPackingFlags::SequenceStart);
}
}
else
{
m_pMBLayout->AddGap(i, currentMBFilled, m_currentMBSize);
for (size_t k = currentMBFilled; k < m_currentMBSize; k++)
{
// m_pMBLayout->Set(i, k, MinibatchPackingFlags::NoInput);
// Populates <NO_INPUT> with real features, the
// following implementation is not efficient...
PopulateUtteranceInMinibatch(matrices, i, 0, 1, m_currentMBSize, k);
}
}
}
}
skip = false;
} while (skip);
return true;
}
template <class ElemType>
bool HTKMLFReader<ElemType>::ShouldCopyMinibatchFromBuffer()
{
if (m_doMinibatchBuffering)
{
// If <m_getMinibatchCopy> is false, then we should copy data from
// buffer for back-propagation.
if (m_getMinibatchCopy == false && m_minibatchBuffer.size() > 0)
{
m_minibatchBufferIndex = 0;
return true;
}
// If <m_getMinibatchCopy> is true, we first have to re-compute
// the likelihood for the frames that are already in the buffer.
if (m_getMinibatchCopy == true && m_minibatchBufferIndex + 1 < m_minibatchBuffer.size())
{
m_minibatchBufferIndex += 1;
return true;
}
}
return false;
}
template <class ElemType>
void HTKMLFReader<ElemType>::CopyMinibatchToBuffer()
{
size_t originalMBSize = m_currentMBSize;
size_t currentMBSize = m_currentMBSize;
size_t numMinibatches = 1;
if (m_doMinibatchBufferTruncation)
{
currentMBSize = m_mbSize;
numMinibatches = (ElemType) originalMBSize / (ElemType) m_mbSize;
numMinibatches += (originalMBSize % m_mbSize == 0) ? 0 : 1;
}
for (size_t i = 0; i < numMinibatches; ++i)
{
MinibatchBufferUnit currentMinibatch;
size_t startIndex = i * currentMBSize;
size_t numFrames =
(startIndex + currentMBSize <= originalMBSize) ? currentMBSize : (originalMBSize - startIndex);
// Sets MBLayout.
// currentMinibatch.pMBLayout->CopyFromRange(m_pMBLayout, startIndex, numFrames);
currentMinibatch.pMBLayout->Init(m_pMBLayout->GetNumParallelSequences(), numFrames);
const auto& sequences = m_pMBLayout->GetAllSequences();
for (const auto& seq : sequences)
{
if (seq.tEnd > startIndex && seq.tBegin < (ptrdiff_t)(startIndex + numFrames))
{
auto shiftedSeq = seq;
shiftedSeq.tBegin -= startIndex;
shiftedSeq.tEnd -= startIndex;
currentMinibatch.pMBLayout->AddSequence(shiftedSeq);
}
}
// Sets the minibatch size for the current minibatch.
currentMinibatch.currentMBSize = numFrames;
// Sets the utterance information for the current minibatch.
currentMinibatch.minibatchUttInfo.assign(
m_numberOfuttsPerMinibatch,
std::vector<std::pair<wstring, size_t>>(0));
for (size_t j = 0; j < m_minibatchUttInfo.size(); ++j)
{
size_t uttStartIndex = 0;
for (size_t k = 0; k < m_minibatchUttInfo[j].size(); ++k)
{
if (startIndex >= uttStartIndex + m_minibatchUttInfo[j][k].second)
{
uttStartIndex += m_minibatchUttInfo[j][k].second;
continue;
}
if (startIndex + numFrames <= uttStartIndex)
{
break;
}
currentMinibatch.minibatchUttInfo[j].push_back(m_minibatchUttInfo[j][k]);
uttStartIndex += m_minibatchUttInfo[j][k].second;
}
}
size_t startDataCopy = startIndex * m_numberOfuttsPerMinibatch;
size_t endDataCopy = (startIndex + numFrames) * m_numberOfuttsPerMinibatch;
// Copies features.
currentMinibatch.features.resize(0);
for (size_t i = 0; i < m_featuresBufferMultiIO.size(); ++i)
{
std::vector<ElemType> tmpFeatures(
m_featuresBufferMultiIO[i] + startDataCopy * m_featureNameToDimMap[m_featureIdToNameMap[i]],
m_featuresBufferMultiIO[i] + endDataCopy * m_featureNameToDimMap[m_featureIdToNameMap[i]]);
currentMinibatch.features.push_back(tmpFeatures);
}
// Copies labels.
currentMinibatch.labels.resize(0);
for (size_t i = 0; i < m_labelsBufferMultiIO.size(); ++i)
{
std::vector<ElemType> tmpLabels(
m_labelsBufferMultiIO[i] + startDataCopy * m_labelNameToDimMap[m_labelIdToNameMap[i]],
m_labelsBufferMultiIO[i] + endDataCopy * m_labelNameToDimMap[m_labelIdToNameMap[i]]);
currentMinibatch.labels.push_back(tmpLabels);
}
m_minibatchBuffer.push_back(currentMinibatch);
}
}
template <class ElemType>
void HTKMLFReader<ElemType>::CopyMinibatchFromBufferToMatrix(
size_t index,
std::map<std::wstring, Matrix<ElemType>*>& matrices)
{
assert(m_minibatchBuffer.size() > index);
// Restores the variables related to the minibatch.
m_pMBLayout->CopyFrom(m_minibatchBuffer[index].pMBLayout);
m_currentMBSize = m_minibatchBuffer[index].currentMBSize;
m_minibatchUttInfo = m_minibatchBuffer[index].minibatchUttInfo;
// Copies data to the matrix.
for (auto iter = matrices.begin(); iter != matrices.end(); iter++)
{
Matrix<ElemType>& data = *matrices[iter->first];
if (m_nameToTypeMap[iter->first] == InputOutputTypes::real)
{
size_t id = m_featureNameToIdMap[iter->first];
size_t dim = m_featureNameToDimMap[iter->first];
assert(id < m_minibatchBuffer[index].features.size());
data.SetValue(dim,
m_minibatchBuffer[index].features[id].size() / dim,
data.GetDeviceId(),
m_minibatchBuffer[index].features[id].data(),
matrixFlagNormal);
}
else if (m_nameToTypeMap[iter->first] == InputOutputTypes::category)
{
size_t id = m_labelNameToIdMap[iter->first];
size_t dim = m_labelNameToDimMap[iter->first];
assert(id < m_minibatchBuffer[index].labels.size());
data.SetValue(dim,
m_minibatchBuffer[index].labels[id].size() / dim,
data.GetDeviceId(),
m_minibatchBuffer[index].labels[id].data(),
matrixFlagNormal);
}
else if (m_doMinibatchBuffering)
{
if (m_nameToTypeMap[iter->first] == InputOutputTypes::readerDeriv)
{
if (m_getMinibatchCopy)
{
if (data.GetNumCols() != m_currentMBSize * m_numberOfuttsPerMinibatch)
{
matrices[iter->first]->Resize(data.GetNumRows(),
m_currentMBSize * m_numberOfuttsPerMinibatch);
}
matrices[iter->first]->SetValue(0);
}
else
{
m_uttDerivBuffer->GetDerivative(m_minibatchUttInfo,
m_pMBLayout,
matrices[iter->first]);
}
}
else if (m_nameToTypeMap[iter->first] == InputOutputTypes::readerObj)
{
if (m_getMinibatchCopy)
{
if (data.GetNumCols() != 1)
{
data.Resize(1, 1);
}
data.SetValue(0);
}
else
{
m_uttDerivBuffer->GetObjective(m_minibatchUttInfo,
matrices[iter->first]);
}
}
}
}
if (m_getMinibatchCopy == false)
{
assert(index == 0);
m_minibatchBuffer.pop_front();
}
}
template <class ElemType>
void HTKMLFReader<ElemType>::CopyMinibatchToMatrix(
size_t size,
const vector<ElemType*>& featureBuffer,
const vector<ElemType*>& labelBuffer,
std::map<std::wstring, Matrix<ElemType>*>& matrices) const
{
for (auto iter = matrices.begin(); iter != matrices.end(); iter++)
{
Matrix<ElemType>& data = *matrices[iter->first];
if (m_nameToTypeMap.at(iter->first) == InputOutputTypes::real)
{
size_t id = m_featureNameToIdMap.at(iter->first);
size_t dim = m_featureNameToDimMap.at(iter->first);
assert(id < featureBuffer.size());
data.SetValue(dim, size, data.GetDeviceId(), featureBuffer[id], matrixFlagNormal);
}
else if (m_nameToTypeMap.at(iter->first) == InputOutputTypes::category)
{
size_t id = m_labelNameToIdMap.at(iter->first);
size_t dim = m_labelNameToDimMap.at(iter->first);
assert(id < labelBuffer.size());
data.SetValue(dim, size, data.GetDeviceId(), labelBuffer[id], matrixFlagNormal);
}
else if (m_doMinibatchBuffering)
{
if (m_nameToTypeMap.at(iter->first) == InputOutputTypes::readerDeriv)
{
if (data.GetNumCols() != m_currentMBSize * m_numberOfuttsPerMinibatch)
{
data.Resize(data.GetNumRows(),
m_currentMBSize * m_numberOfuttsPerMinibatch);
}
data.SetValue(0);
}
else if (m_nameToTypeMap.at(iter->first) == InputOutputTypes::readerObj)
{
if (data.GetNumCols() != 1)
{
data.Resize(1, 1);
}
data.SetValue(0);
}
}
}
}
template <class ElemType>
bool HTKMLFReader<ElemType>::GetMinibatchToTrainOrTest(
std::map<std::wstring, Matrix<ElemType>*>& matrices)
{
// We either copy a new minibatch from buffer or read one from minibatch
// iterator.
bool success = false;
if (ShouldCopyMinibatchFromBuffer())
{
CopyMinibatchFromBufferToMatrix(m_minibatchBufferIndex, matrices);
return true;
}
else
{
success = GetOneMinibatchToTrainOrTestDataBuffer(matrices);
if (success)
{
if (m_getMinibatchCopy)
{
assert(m_minibatchBuffer.size() == 0);
CopyMinibatchToBuffer();
CopyMinibatchFromBufferToMatrix(0, matrices);
m_minibatchBufferIndex = 0;
}
else
{
CopyMinibatchToMatrix(
m_currentMBSize * m_numberOfuttsPerMinibatch,
m_featuresBufferMultiIO, m_labelsBufferMultiIO, matrices);
}
}
// If we are in the "copy" mode, and we cannot get a full minibatch,
// then we have computed the posteriors for all the minibatches.
if (m_doMinibatchBuffering && !success && m_getMinibatchCopy)
{
m_uttDerivBuffer->SetEpochEnd();
}
return success;
}
return false;
}
template <class ElemType>
bool HTKMLFReader<ElemType>::GetMinibatchToWrite(std::map<std::wstring, Matrix<ElemType>*>& matrices)
{
std::map<std::wstring, size_t>::iterator iter;
if (m_checkDictionaryKeys)
{
for (auto iter = m_featureNameToIdMap.begin(); iter != m_featureNameToIdMap.end(); iter++)
{
if (matrices.find(iter->first) == matrices.end())
{
fprintf(stderr, "GetMinibatchToWrite: feature node %S specified in reader not found in the network\n", iter->first.c_str());
throw std::runtime_error("GetMinibatchToWrite: feature node specified in reader not found in the network.");
}
}
/*
for (auto iter=matrices.begin();iter!=matrices.end();iter++)
{
if (m_featureNameToIdMap.find(iter->first)==m_featureNameToIdMap.end())
throw std::runtime_error(msra::strfun::strprintf("minibatch requested for input node %ws not found in reader - cannot generate input\n",iter->first.c_str()));
}
*/
m_checkDictionaryKeys = false;
}
if (m_inputFileIndex < m_inputFilesMultiIO[0].size())
{
m_fileEvalSource->Reset();
// load next file (or set of files)
foreach_index (i, m_inputFilesMultiIO)
{
msra::asr::htkfeatreader reader;
const auto path = reader.parse(m_inputFilesMultiIO[i][m_inputFileIndex], m_writingFeatureSections[i]);
// read file
msra::dbn::matrix feat;
string featkind;
unsigned int sampperiod;
msra::util::attempt(5, [&]()
{
reader.readAlloc(path, featkind, sampperiod, feat); // whole file read as columns of feature vectors
});
fprintf(stderr, "evaluate: reading %zu frames of %S\n", feat.cols(), ((wstring) path).c_str());
m_fileEvalSource->AddFile(feat, featkind, sampperiod, i);
}
m_inputFileIndex++;
// turn frames into minibatch (augment neighbors, etc)
m_fileEvalSource->CreateEvalMinibatch();
// populate input matrices
bool first = true;
typename std::map<std::wstring, Matrix<ElemType>*>::iterator iter;
for (iter = matrices.begin(); iter != matrices.end(); iter++)
{
// dereference matrix that corresponds to key (input/output name) and
// populate based on whether its a feature or a label
if (m_nameToTypeMap.find(iter->first) != m_nameToTypeMap.end() && m_nameToTypeMap[iter->first] == InputOutputTypes::real)
{
Matrix<ElemType>& data = *matrices[iter->first]; // can be features or labels
size_t id = m_featureNameToIdMap[iter->first];
size_t dim = m_featureNameToDimMap[iter->first];
const msra::dbn::matrix feat = m_fileEvalSource->ChunkOfFrames(id);
if (first)
{
m_pMBLayout->Init(1, feat.cols());
m_pMBLayout->AddSequence(NEW_SEQUENCE_ID, 0, 0, feat.cols());
// m_pMBLayout->SetWithoutOr(0, feat.cols() - 1, MinibatchPackingFlags::SequenceEnd);
first = false;
}
// copy the features over to our array type
assert(feat.rows() == dim);
dim; // check feature dimension matches what's expected
if (m_featuresBufferMultiIO[id] == NULL)
{
m_featuresBufferMultiIO[id] = new ElemType[feat.rows() * feat.cols()];
m_featuresBufferAllocatedMultiIO[id] = feat.rows() * feat.cols();
}
else if (m_featuresBufferAllocatedMultiIO[id] < feat.rows() * feat.cols()) // buffer size changed. can be partial minibatch
{
delete[] m_featuresBufferMultiIO[id];
m_featuresBufferMultiIO[id] = new ElemType[feat.rows() * feat.cols()];
m_featuresBufferAllocatedMultiIO[id] = feat.rows() * feat.cols();
}
// shouldn't need this since we fill up the entire buffer below
// memset(m_featuresBufferMultiIO[id],0,sizeof(ElemType)*feat.rows()*feat.cols());
if (sizeof(ElemType) == sizeof(float))
{
for (int j = 0; j < feat.cols(); j++) // column major, so iterate columns
{
// copy over the entire column at once, need to do this because SSEMatrix may have gaps at the end of the columns
memcpy_s(&m_featuresBufferMultiIO[id][j * feat.rows()], sizeof(ElemType) * feat.rows(), &feat(0, j), sizeof(ElemType) * feat.rows());
}
}
else
{
for (int j = 0; j < feat.cols(); j++) // column major, so iterate columns in outside loop
{
for (int i = 0; i < feat.rows(); i++)
{
m_featuresBufferMultiIO[id][j * feat.rows() + i] = feat(i, j);
}
}
}
data.SetValue(feat.rows(), feat.cols(), data.GetDeviceId(), m_featuresBufferMultiIO[id], matrixFlagNormal);
}
else
{ // Resizes other inputs so they won't affect actual minibatch size.
Matrix<ElemType>& data = *matrices[iter->first];
data.Resize(data.GetNumRows(), 1);
}
}
return true;
}
else
{
return false;
}
}
template <class ElemType>
bool HTKMLFReader<ElemType>::ReNewBufferForMultiIO(size_t i)
{
if (m_noData)
{
m_currentBufferFrames[i] = 0;
m_processedFrame[i] = 0;
m_toProcess[i] = 0;
m_uttInfo[i].clear();
return false;
}
size_t numOfFea = m_featuresBufferMultiIO.size();
size_t numOfLabel = m_labelsBufferMultiIO.size();
// Number of frames we get from minibatch iterator.
m_currentBufferFrames[i] = m_mbiter->currentmbframes();
// If we operate at utterance level, we get the utterance information.
if (!m_framemode)
{
m_uttInfo[i] = m_mbiter->getutteranceinfo();
assert(m_uttInfo[i].size() > 0);
// For now, let's just assume that the utterance length will be
// larger than the minibatch size. We can handle this more
// gracefully later, e.g., remove the utterance in the reader.
if (m_uttInfo[i].size() > 1)
{
fprintf(stderr, "WARNING: Utterance length is smaller than the "
"minibatch size, you may want to remove the utterance or "
"reduce the minibatch size.\n");
}
if (!m_truncated && (m_currentBufferFrames[i] > m_maxUtteranceLength))
{
(*m_mbiter)++;
if (!(*m_mbiter))
{
m_noData = true;
}
fprintf(stderr, "WARNING: Utterance \"%S\" has length longer "
"than the %zd, skipping it.\n",
m_uttInfo[i][0].first.c_str(), m_maxUtteranceLength);
return ReNewBufferForMultiIO(i);
}
if (m_doMinibatchBuffering && !m_uttDerivBuffer->HasResourceForDerivative(m_uttInfo[i][0].first))
{
(*m_mbiter)++;
if (!(*m_mbiter))
{
m_noData = true;
}
fprintf(stderr, "WARNING: Utterance \"%S\" does not have "
"resource to compute derivative, skipping it.\n",
m_uttInfo[i][0].first.c_str());
return ReNewBufferForMultiIO(i);
}
// We don't support having two utterances in the same buffer.
if (m_doMinibatchBuffering && m_hasUttInCurrentMinibatch.find(m_uttInfo[i][0].first) != m_hasUttInCurrentMinibatch.end())
{
(*m_mbiter)++;
if (!(*m_mbiter))
{
m_noData = true;
}
fprintf(stderr, "WARNING: Utterance \"%S\" already exists in "
"the minibatch, skipping it.\n",
m_uttInfo[i][0].first.c_str());
return ReNewBufferForMultiIO(i);
}
}
// Sets up feature buffers.
// foreach_index(id, m_featuresBufferAllocatedMultiIO)
size_t totalFeatNum = 0;
for (auto it = m_featureNameToIdMap.begin(); it != m_featureNameToIdMap.end(); ++it)
{
size_t id = m_featureNameToIdMap[it->first];
const msra::dbn::matrixstripe featOri = m_mbiter->frames(id);
size_t fdim = featOri.rows();
const size_t actualmbsizeOri = featOri.cols();
m_featuresStartIndexMultiUtt[id + i * numOfFea] = totalFeatNum;
totalFeatNum = fdim * actualmbsizeOri + m_featuresStartIndexMultiUtt[id + i * numOfFea];
}
if (m_featuresBufferMultiUtt[i] == NULL)
{
m_featuresBufferMultiUtt[i] = new ElemType[totalFeatNum];
m_featuresBufferAllocatedMultiUtt[i] = totalFeatNum;
}
else if (m_featuresBufferAllocatedMultiUtt[i] < totalFeatNum) // buffer size changed. can be partial minibatch
{
delete[] m_featuresBufferMultiUtt[i];
m_featuresBufferMultiUtt[i] = new ElemType[totalFeatNum];
m_featuresBufferAllocatedMultiUtt[i] = totalFeatNum;
}
// Sets up label buffers.
size_t totalLabelsNum = 0;
for (auto it = m_labelNameToIdMap.begin(); it != m_labelNameToIdMap.end(); ++it)
{
size_t id = m_labelNameToIdMap[it->first];
size_t dim = m_labelNameToDimMap[it->first];
const vector<size_t>& uids = m_mbiter->labels(id);
size_t actualmbsizeOri = uids.size();
m_labelsStartIndexMultiUtt[id + i * numOfLabel] = totalLabelsNum;
totalLabelsNum = m_labelsStartIndexMultiUtt[id + i * numOfLabel] + dim * actualmbsizeOri;
}
if (m_labelsBufferMultiUtt[i] == NULL)
{
m_labelsBufferMultiUtt[i] = new ElemType[totalLabelsNum];
m_labelsBufferAllocatedMultiUtt[i] = totalLabelsNum;
}
else if (m_labelsBufferAllocatedMultiUtt[i] < totalLabelsNum)
{
delete[] m_labelsBufferMultiUtt[i];
m_labelsBufferMultiUtt[i] = new ElemType[totalLabelsNum];
m_labelsBufferAllocatedMultiUtt[i] = totalLabelsNum;
}
memset(m_labelsBufferMultiUtt[i], 0, sizeof(ElemType) * totalLabelsNum);
// Copies features to buffer.
// foreach_index(id, m_featuresBufferMultiIO)
bool first = true;
for (auto it = m_featureNameToIdMap.begin(); it != m_featureNameToIdMap.end(); ++it)
{
size_t id = m_featureNameToIdMap[it->first];
const msra::dbn::matrixstripe featOri = m_mbiter->frames(id);
const size_t actualmbsizeOri = featOri.cols();
size_t fdim = featOri.rows();
if (first)
{
m_toProcess[i] = actualmbsizeOri;
first = false;
}
else
{
if (m_toProcess[i] != actualmbsizeOri)
{
throw std::runtime_error("The multi-IO features has inconsistent number of frames!");
}
}
assert(actualmbsizeOri == m_mbiter->currentmbframes());
if (sizeof(ElemType) == sizeof(float))
{
for (int k = 0; k < actualmbsizeOri; k++) // column major, so iterate columns
{
// copy over the entire column at once, need to do this because SSEMatrix may have gaps at the end of the columns
memcpy_s(&m_featuresBufferMultiUtt[i][k * fdim + m_featuresStartIndexMultiUtt[id + i * numOfFea]], sizeof(ElemType) * fdim, &featOri(0, k), sizeof(ElemType) * fdim);
}
}
else
{
for (int k = 0; k < actualmbsizeOri; k++) // column major, so iterate columns in outside loop
{
for (int d = 0; d < featOri.rows(); d++)
{
m_featuresBufferMultiUtt[i][k * fdim + d + m_featuresStartIndexMultiUtt[id + i * numOfFea]] = featOri(d, k);
}
}
}
}
for (auto it = m_labelNameToIdMap.begin(); it != m_labelNameToIdMap.end(); ++it)
{
size_t id = m_labelNameToIdMap[it->first];
size_t dim = m_labelNameToDimMap[it->first];
const vector<size_t>& uids = m_mbiter->labels(id);
size_t actualmbsizeOri = uids.size();
if (m_convertLabelsToTargetsMultiIO[id])
{
size_t labelDim = m_labelToTargetMapMultiIO[id].size();
for (int k = 0; k < actualmbsizeOri; k++)
{
assert(uids[k] < labelDim);
labelDim;
size_t labelId = uids[k];
for (int j = 0; j < dim; j++)
{
m_labelsBufferMultiUtt[i][k * dim + j + m_labelsStartIndexMultiUtt[id + i * numOfLabel]] = m_labelToTargetMapMultiIO[id][labelId][j];
}
}
}
else
{
// loop through the columns and set one value to 1
// in the future we want to use a sparse matrix here
for (int k = 0; k < actualmbsizeOri; k++)
{
assert(uids[k] < dim);
// labels(uids[i], i) = (ElemType)1;
m_labelsBufferMultiUtt[i][k * dim + uids[k] + m_labelsStartIndexMultiUtt[id + i * numOfLabel]] = (ElemType) 1;
}
}
}
m_processedFrame[i] = 0;
(*m_mbiter)++;
if (!(*m_mbiter))
m_noData = true;
return true;
}
// Gets a copy of the utterance that corresponds to the current minibatches,
// which will be used to do a neural network forward computation.
template <class ElemType>
bool HTKMLFReader<ElemType>::GetMinibatchCopy(
std::vector<std::vector<std::pair<wstring, size_t>>>& uttInfo,
std::map<std::wstring, Matrix<ElemType>*>& matrices,
MBLayoutPtr pMBLayout)
{
// We need to get a "copy" of the minibatch to do the forward
// computation for sequence training.
if (m_doMinibatchBuffering)
{
assert(m_framemode == false);
if (m_uttDerivBuffer->NeedLikelihoodToComputeDerivative())
{
m_getMinibatchCopy = true;
if (GetMinibatchToTrainOrTest(matrices))
{
pMBLayout->CopyFrom(m_pMBLayout);
uttInfo = m_minibatchUttInfo;
m_getMinibatchCopy = false;
return true;
}
m_getMinibatchCopy = false;
}
return false;
}
return false;
}
template <class ElemType>
bool HTKMLFReader<ElemType>::SetNetOutput(
const std::vector<std::vector<std::pair<wstring, size_t>>>& uttInfo,
const Matrix<ElemType>& outputs,
const MBLayoutPtr pMBLayout)
{
// Set the likelihoods for the utterance with which we can comput the
// derivatives. Note that the minibatch may only contain partial output
// for the utterance, <m_uttDerivBuffer> takes care of "gluing" them
// together.
if (m_doMinibatchBuffering)
{
assert(m_framemode == false);
return m_uttDerivBuffer->SetLikelihood(uttInfo, outputs, pMBLayout);
}
return false;
}
// GetLabelMapping - Gets the label mapping from integer to type in file
// mappingTable - a map from numeric datatype to native label type stored as a string
template <class ElemType>
const std::map<typename IDataReader<ElemType>::LabelIdType, typename IDataReader<ElemType>::LabelType>& HTKMLFReader<ElemType>::GetLabelMapping(const std::wstring& /*sectionName*/)
{
return m_idToLabelMap;
}
// SetLabelMapping - Sets the label mapping from integer index to label
// labelMapping - mapping table from label values to IDs (must be 0-n)
// note: for tasks with labels, the mapping table must be the same between a training run and a testing run
template <class ElemType>
void HTKMLFReader<ElemType>::SetLabelMapping(const std::wstring& /*sectionName*/, const std::map<typename IDataReader<ElemType>::LabelIdType, LabelType>& labelMapping)
{
m_idToLabelMap = labelMapping;
}
template <class ElemType>
size_t HTKMLFReader<ElemType>::ReadLabelToTargetMappingFile(const std::wstring& labelToTargetMappingFile, const std::wstring& labelListFile, std::vector<std::vector<ElemType>>& labelToTargetMap)
{
if (labelListFile == L"")
throw std::runtime_error("HTKMLFReader::ReadLabelToTargetMappingFile(): cannot read labelToTargetMappingFile without a labelMappingFile!");
vector<std::wstring> labelList;
size_t count, numLabels;
count = 0;
// read statelist first
msra::files::textreader labelReader(labelListFile);
while (labelReader)
{
labelList.push_back(labelReader.wgetline());
count++;
}
numLabels = count;
count = 0;
msra::files::textreader mapReader(labelToTargetMappingFile);
size_t targetDim = 0;
while (mapReader)
{
std::wstring line(mapReader.wgetline());
// find white space as a demarcation
std::wstring::size_type pos = line.find(L" ");
std::wstring token = line.substr(0, pos);
std::wstring targetstring = line.substr(pos + 1);
if (labelList[count] != token)
RuntimeError("HTKMLFReader::ReadLabelToTargetMappingFile(): mismatch between labelMappingFile and labelToTargetMappingFile");
if (count == 0)
targetDim = targetstring.length();
else if (targetDim != targetstring.length())
RuntimeError("HTKMLFReader::ReadLabelToTargetMappingFile(): inconsistent target length among records");
std::vector<ElemType> targetVector(targetstring.length(), (ElemType) 0.0);
foreach_index (i, targetstring)
{
if (targetstring.compare(i, 1, L"1") == 0)
targetVector[i] = (ElemType) 1.0;
else if (targetstring.compare(i, 1, L"0") != 0)
RuntimeError("HTKMLFReader::ReadLabelToTargetMappingFile(): expecting label2target mapping to contain only 1's or 0's");
}
labelToTargetMap.push_back(targetVector);
count++;
}
// verify that statelist and label2target mapping file are in same order (to match up with reader) while reading mapping
if (count != labelList.size())
RuntimeError("HTKMLFReader::ReadLabelToTargetMappingFile(): mismatch between lengths of labelMappingFile vs labelToTargetMappingFile");
return targetDim;
}
// GetData - Gets metadata from the specified section (into CPU memory)
// sectionName - section name to retrieve data from
// numRecords - number of records to read
// data - pointer to data buffer, if NULL, dataBufferSize will be set to size of required buffer to accomidate request
// dataBufferSize - [in] size of the databuffer in bytes
// [out] size of buffer filled with data
// recordStart - record to start reading from, defaults to zero (start of data)
// returns: true if data remains to be read, false if the end of data was reached
template <class ElemType>
bool HTKMLFReader<ElemType>::GetData(const std::wstring& /*sectionName*/, size_t /*numRecords*/, void* /*data*/, size_t& /*dataBufferSize*/, size_t /*recordStart*/)
{
throw std::runtime_error("GetData not supported in HTKMLFReader");
}
template <class ElemType>
bool HTKMLFReader<ElemType>::DataEnd()
{
// each minibatch is considered a "sentence"
// for the truncated BPTT, we need to support check whether it's the end of data
if (m_truncated)
return m_sentenceEnd[0];
else
return true; // useless in current condition
template <class ElemType>
void HTKMLFReader<ElemType>::SetSentenceEndInBatch(vector<size_t>& sentenceEnd)
{
sentenceEnd.resize(m_switchFrame.size());
for (size_t i = 0; i < m_switchFrame.size(); i++)
{
sentenceEnd[i] = m_switchFrame[i];
}
}
// For Kaldi2Reader, we now make the following assumptions
// 1. feature sections will always have a sub-field "scpFile"
// 2. label sections will always have a sub-field "mlfFile"
template <class ElemType>
template <class ConfigRecordType>
void HTKMLFReader<ElemType>::GetDataNamesFromConfig(const ConfigRecordType& readerConfig, std::vector<std::wstring>& features, std::vector<std::wstring>& labels)
{
for (auto& id : readerConfig.GetMemberIds())
{
if (!readerConfig.CanBeConfigRecord(id))
continue;
const ConfigRecordType& temp = readerConfig(id);
// see if we have a config parameters that contains a "file" element, it's a sub key, use it
if (temp.ExistsCurrent(L"scpFile"))
{
features.push_back(id);
}
else if (temp.ExistsCurrent(L"mlfFile"))
{
labels.push_back(id);
}
}
}
template class HTKMLFReader<float>;
template class HTKMLFReader<double>;
} } }