Deserializer HTKFeatureDeserializer(const std::vector<HTKFeatureConfiguration>& streams)
 {
     Deserializer htk;
     Dictionary input;
     for (const auto& s : streams)
     {
         const auto& key = s.m_streamName;
         Dictionary stream;
         std::vector<DictionaryValue> ctxWindow = { DictionaryValue(s.m_left), DictionaryValue(s.m_right) };
         stream.Add(L"scpFile", s.m_scp, L"dim", s.m_dim, L"contextWindow", ctxWindow, L"expandToUtterance", s.m_broadcast);
         stream[L"definesMBSize"] = s.m_definesMbSize;
         input[key] = stream;
     }
     htk.Add(L"type", L"HTKFeatureDeserializer", L"input", input);
     return htk;
 }
 Deserializer BuildImageDeserializer(const std::wstring deserializer,
     const std::wstring& fileName, const std::wstring& labelStreamName, size_t numLabels,
     const std::wstring& imageStreamName, const std::vector<ImageTransform>& transforms) 
 {
     Deserializer img;
     std::vector<DictionaryValue> actualTransforms;
     std::transform(transforms.begin(), transforms.end(), std::back_inserter(actualTransforms), [](ImageTransform t) { return static_cast<DictionaryValue>(t); });
     Dictionary labeldim;
     labeldim[L"labelDim"] = numLabels;
     Dictionary xforms;
     xforms[L"transforms"] = actualTransforms;
     Dictionary input;
     input.Add(imageStreamName.c_str(), xforms, labelStreamName.c_str(), labeldim);
     img.Add(L"type", deserializer, L"file", fileName, L"input", input);
     return img;
 }
 Deserializer CTFDeserializer(const std::wstring& fileName, const std::vector<StreamConfiguration>& streams)
 {
     Deserializer ctf;
     Dictionary input;
     for (const auto& s : streams)
     {
         const auto& key = s.m_streamName;
         Dictionary stream;
         stream[L"dim"] = s.m_dim;
         stream[L"format"] = s.m_isSparse ? L"sparse" : L"dense";
         stream[L"definesMBSize"] = s.m_definesMbSize;
         if (!s.m_streamAlias.empty())
             stream[L"alias"] = s.m_streamAlias;
         input[key] = stream;
     }
     ctf.Add(L"type", L"CNTKTextFormatDeserializer", L"file", fileName, L"input", input);
     return ctf;
 }
 Deserializer HTKMLFDeserializer(const std::wstring& streamName, const std::wstring& labelMappingFile, size_t dimension, const std::vector<std::wstring>& mlfFiles, bool phoneBoundaries)
 {
     Deserializer htk;
     Dictionary stream;
     Dictionary labels;
     labels.Add(L"labelMappingFile", labelMappingFile, L"dim", dimension);
     std::vector<DictionaryValue> actualFiles;
     std::transform(mlfFiles.begin(), mlfFiles.end(), std::back_inserter(actualFiles), [](const std::wstring& s) {return static_cast<DictionaryValue>(s); });
     if (actualFiles.size() > 1)
         labels[L"mlfFileList"] = actualFiles;
     else if (actualFiles.size() == 1)
         labels[L"mlfFile"] = actualFiles[0];
     else
         LogicError("HTKMLFDeserializer: No mlf files were specified");
     if (phoneBoundaries)
         labels[L"phoneBoundaries"] = L"true";
     else
         labels[L"phoneBoundaries"] = L"false";
     stream[streamName] = labels;
     htk.Add(L"type", L"HTKMLFDeserializer", L"input", stream);
     return htk;
 }