// // 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 "basetypes.h" #include "htkfeatio.h" // for reading HTK features #include "ssematrix.h" #define DATAWRITER_EXPORTS // creating the exports here #include "DataWriter.h" #include "Config.h" #include "HTKMLFWriter.h" #include "Config.h" #ifdef LEAKDETECT #include // for memory leak detection #endif namespace Microsoft { namespace MSR { namespace CNTK { // Create a Data Writer //DATAWRITER_API IDataWriter* DataWriterFactory(void) template template void HTKMLFWriter::InitFromConfig(const ConfigRecordType& writerConfig) { m_tempArray = nullptr; m_tempArraySize = 0; m_overflowWarningCount = 0; vector scriptpaths; vector filelist; size_t numFiles; size_t firstfilesonly = SIZE_MAX; // set to a lower value for testing m_verbosity = writerConfig(L"verbosity", 2); m_overflowValue = writerConfig(L"overflowValue", 50); m_maxNumOverflowWarning = writerConfig(L"maxNumOverflowWarning", 10); vector outputNames = writerConfig(L"outputNodeNames", ConfigRecordType::Array(stringargvector())); if (outputNames.size() < 1) RuntimeError("writer needs at least one outputNodeName specified in config"); int counter = 0; foreach_index (i, outputNames) // inputNames should map to node names { ConfigParameters thisOutput = writerConfig(outputNames[i]); if (thisOutput.Exists("dim")) udims.push_back(thisOutput(L"dim")); else RuntimeError("HTKMLFWriter::Init: writer need to specify dim of output"); if (thisOutput.Exists("file")) scriptpaths.push_back(thisOutput(L"file")); else if (thisOutput.Exists("scpFile")) scriptpaths.push_back(thisOutput(L"scpFile")); else RuntimeError("HTKMLFWriter::Init: writer needs to specify scpFile for output"); if (thisOutput.Exists("Kaldicmd")) { kaldicmd.push_back(thisOutput(L"Kaldicmd")); kaldi::BaseFloatMatrixWriter wfea; feature_writer.push_back(wfea); feature_writer[i].Open(msra::strfun::utf8(kaldicmd[counter])); } outputNameToIdMap[outputNames[i]] = i; outputNameToDimMap[outputNames[i]] = udims[i]; wstring type = thisOutput(L"type", "Real"); if (type == L"Real") { outputNameToTypeMap[outputNames[i]] = OutputTypes::outputReal; } else { throw std::runtime_error("HTKMLFWriter::Init: output type for writer output expected to be Real"); } counter++; } numFiles = 0; foreach_index (i, scriptpaths) { filelist.clear(); std::wstring scriptPath = scriptpaths[i]; fprintf(stderr, "HTKMLFWriter::Init: reading output script file %S ...", scriptPath.c_str()); size_t n = 0; for (msra::files::textreader reader(scriptPath); reader && filelist.size() <= firstfilesonly /*optimization*/;) { std::wstring line = reader.wgetline(); wstringstream ss(line); std::wstring first_col; ss >> first_col; filelist.push_back(first_col); // LEOTODO n++; } fprintf(stderr, " %zu entries\n", n); if (i == 0) numFiles = n; else if (n != numFiles) throw std::runtime_error(msra::strfun::strprintf("HTKMLFWriter:Init: number of files in each scriptfile inconsistent (%d vs. %d)", numFiles, n)); outputFiles.push_back(filelist); } outputFileIndex = 0; sampPeriod = 100000; } template void HTKMLFWriter::Destroy() { delete[] m_tempArray; m_tempArray = nullptr; m_tempArraySize = 0; for (size_t i = 0; i < feature_writer.size(); i++) { feature_writer[i].Close(); fprintf(stderr, "Closed Kaldi writer\n"); } } template void HTKMLFWriter::GetSections(std::map& /*sections*/) { } template bool HTKMLFWriter::SaveData(size_t /*recordStart*/, const std::map& matrices, size_t /*numRecords*/, size_t /*datasetSize*/, size_t /*byteVariableSized*/) { if (kaldicmd.size() == 0) { // std::map::iterator iter; if (outputFileIndex >= outputFiles[0].size()) RuntimeError("index for output scp file out of range..."); for (auto iter = matrices.begin(); iter != matrices.end(); iter++) { wstring outputName = iter->first; Matrix& outputData = *(static_cast*>(iter->second)); size_t id = outputNameToIdMap[outputName]; size_t dim = outputNameToDimMap[outputName]; wstring outFile = outputFiles[id][outputFileIndex]; assert(outputData.GetNumRows() == dim); dim; SaveToKaldiFile(outFile, outputData); } outputFileIndex++; } else { if (outputFileIndex >= outputFiles[0].size()) RuntimeError("index for output scp file out of range..."); int i = 0; for (auto iter = matrices.begin(); iter != matrices.end(); iter++) { wstring outputName = iter->first; Matrix& outputData = *(static_cast*>(iter->second)); size_t id = outputNameToIdMap[outputName]; size_t dim = outputNameToDimMap[outputName]; wstring outFile = outputFiles[id][outputFileIndex]; string wfea = "ark:" + msra::strfun::utf8(outFile); // wfea = msra::strfun::utf8(kaldicmd[i]); // feature_writer[i].Open(wfea); kaldi::Matrix nnet_out_host; assert(outputData.GetNumRows() == dim); dim; const std::string outputPath = msra::strfun::utf8(outFile); const std::string file_key = removeExtension(basename(outputPath)); nnet_out_host.Resize(outputData.GetNumCols(), outputData.GetNumRows()); outputData.CopyToArray(m_tempArray, m_tempArraySize); ElemType* pValue = m_tempArray; for (int j = 0; j < outputData.GetNumCols(); j++) { for (int i = 0; i < outputData.GetNumRows(); i++) { nnet_out_host(j, i) = (float) *pValue++; if (nnet_out_host(j, i) > m_overflowValue) { nnet_out_host(j, i) = -(float) log(1.0 / outputData.GetNumCols()); if (m_verbosity > 0 && m_overflowWarningCount < m_maxNumOverflowWarning) { fprintf(stderr, "overflowed!! : %d %d frames of %s\n", i, j, wfea.c_str()); m_overflowWarningCount++; } } } } fprintf(stderr, "evaluate: writing %zu frames of %s\n", outputData.GetNumCols(), wfea.c_str()); feature_writer[i].Write(file_key, nnet_out_host); i++; } outputFileIndex++; } return true; } template void HTKMLFWriter::Save(std::wstring& outputFile, Matrix& outputData) { msra::dbn::matrix output; output.resize(outputData.GetNumRows(), outputData.GetNumCols()); outputData.CopyToArray(m_tempArray, m_tempArraySize); ElemType* pValue = m_tempArray; for (int j = 0; j < outputData.GetNumCols(); j++) { for (int i = 0; i < outputData.GetNumRows(); i++) { output(i, j) = (float) *pValue++; } } const size_t nansinf = output.countnaninf(); if (nansinf > 0) fprintf(stderr, "chunkeval: %d NaNs or INF detected in '%S' (%d frames)\n", (int) nansinf, outputFile.c_str(), (int) output.cols()); // save it msra::files::make_intermediate_dirs(outputFile); msra::util::attempt(5, [&]() { msra::asr::htkfeatwriter::write(outputFile, "USER", this->sampPeriod, output); }); fprintf(stderr, "evaluate: writing %zu frames of %S\n", output.cols(), outputFile.c_str()); } template void HTKMLFWriter::SaveToKaldiFile(std::wstring& outputFile, Matrix& outputData) { msra::dbn::matrix output; output.resize(outputData.GetNumRows(), outputData.GetNumCols()); outputData.CopyToArray(m_tempArray, m_tempArraySize); ElemType* pValue = m_tempArray; for (int j = 0; j < outputData.GetNumCols(); j++) { for (int i = 0; i < outputData.GetNumRows(); i++) { output(i, j) = (float) *pValue++; } } const size_t nansinf = output.countnaninf(); if (nansinf > 0) fprintf(stderr, "chunkeval: %d NaNs or INF detected in '%S' (%d frames)\n", (int) nansinf, outputFile.c_str(), (int) output.cols()); // save it msra::files::make_intermediate_dirs(outputFile); msra::util::attempt(5, [&]() { msra::asr::htkfeatwriter::writeKaldi(outputFile, "USER", this->sampPeriod, output, sizeof(ElemType)); }); fprintf(stderr, "evaluate: writing %zu frames of %S\n", output.cols(), outputFile.c_str()); } template void HTKMLFWriter::SaveMapping(std::wstring saveId, const std::map& /*labelMapping*/) { } template class HTKMLFWriter; template class HTKMLFWriter; } } }