Update to fix the requirement for fully quantified dot paths in NDL.
In MEL, you still need to use the fully quantified path if you are passing something that wasn't defined in NDL.
This commit is contained in:
Родитель
52eabc6e88
Коммит
3b21b530f3
|
@ -173,7 +173,7 @@ void BestGpu::GetCudaProperties()
|
|||
|
||||
int dev = 0;
|
||||
|
||||
for each (ProcessorData* pd in m_procData)
|
||||
for (ProcessorData* pd : m_procData)
|
||||
{
|
||||
cudaSetDevice(dev);
|
||||
pd->deviceId = dev;
|
||||
|
@ -217,7 +217,7 @@ void BestGpu::Init()
|
|||
|
||||
BestGpu::~BestGpu()
|
||||
{
|
||||
for each (ProcessorData* data in m_procData)
|
||||
for (ProcessorData* data : m_procData)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ int BestGpu::GetDevice(BestGpuFlags bestFlags)
|
|||
void BestGpu::SetAllowedDevices(const std::vector<int>& devices)
|
||||
{
|
||||
m_allowedDevices = 0;
|
||||
for each (int device in devices)
|
||||
for (int device : devices)
|
||||
{
|
||||
m_allowedDevices |= (1 << device);
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ std::vector<int> BestGpu::GetDevices(int number, BestGpuFlags p_bestFlags)
|
|||
speedW *= 2;
|
||||
}
|
||||
|
||||
for each (ProcessorData* pd in m_procData)
|
||||
for (ProcessorData* pd : m_procData)
|
||||
{
|
||||
double score = 0.0;
|
||||
|
||||
|
@ -430,7 +430,7 @@ void BestGpu::QueryNvmlData()
|
|||
}
|
||||
|
||||
ProcessorData* curPd = NULL;
|
||||
for each (ProcessorData* pd in m_procData)
|
||||
for (ProcessorData* pd : m_procData)
|
||||
{
|
||||
if (pd->deviceProp.pciBusID == pci.bus)
|
||||
{
|
||||
|
@ -472,7 +472,7 @@ void BestGpu::QueryNvmlData()
|
|||
{
|
||||
std::vector<nvmlProcessInfo_t> processInfo(size);
|
||||
processInfo.resize(size);
|
||||
for each (nvmlProcessInfo_t info in processInfo)
|
||||
for (nvmlProcessInfo_t info : processInfo)
|
||||
info.usedGpuMemory = 0;
|
||||
result = nvmlDeviceGetComputeRunningProcesses(device, &size, &processInfo[0]);
|
||||
if (NVML_SUCCESS != result)
|
||||
|
@ -481,7 +481,7 @@ void BestGpu::QueryNvmlData()
|
|||
}
|
||||
bool cnFound = false;
|
||||
bool dbnFound = false;
|
||||
for each (nvmlProcessInfo_t info in processInfo)
|
||||
for (nvmlProcessInfo_t info : processInfo)
|
||||
{
|
||||
std::string name;
|
||||
name.resize(256);
|
||||
|
|
|
@ -115,13 +115,13 @@ void BinaryReader<ElemType>::DisplayProperties()
|
|||
|
||||
fprintf(stderr,"BinaryReader in use...\n");
|
||||
// enumerate the files
|
||||
for each (SectionFile* file in m_secFiles)
|
||||
for (SectionFile* file : m_secFiles)
|
||||
{
|
||||
Section* section = file->FileSection();
|
||||
fprintf(stderr,"File: %ls, Records: %lld\n", file->GetName(), section->GetElementCount());
|
||||
}
|
||||
|
||||
for each (auto pair in m_sections)
|
||||
for (auto pair : m_sections)
|
||||
{
|
||||
Section* section = pair.second;
|
||||
fprintf(stderr,"Section: %ls, Elements: %lld, ElementsPerRecord: %lld, ElementSize: %lld\n", pair.first.c_str(), section->GetElementCount(), section->GetElementsPerRecord(), section->GetElementSize());
|
||||
|
@ -132,7 +132,7 @@ void BinaryReader<ElemType>::DisplayProperties()
|
|||
size_t size = sizeof(NumericStatistics)*stats.size();
|
||||
GetData(pair.first, stats.size(), &stats[0], size);
|
||||
fprintf(stderr," *Stats*: ");
|
||||
for each (NumericStatistics stat in stats)
|
||||
for (NumericStatistics stat : stats)
|
||||
{
|
||||
fprintf(stderr,"%s:%lf, ",stat.statistic, stat.value);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ BinaryReader<ElemType>::~BinaryReader()
|
|||
// clear the section references, they will be deleted by the sectionFile destructors
|
||||
m_sections.clear();
|
||||
|
||||
for each (SectionFile* secFile in m_secFiles)
|
||||
for (SectionFile* secFile : m_secFiles)
|
||||
{
|
||||
delete secFile;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ BinaryWriter<ElemType>::~BinaryWriter()
|
|||
m_sections.clear();
|
||||
|
||||
// delete all the sectionfiles
|
||||
for each (auto pair in m_secFiles)
|
||||
for (auto pair : m_secFiles)
|
||||
{
|
||||
delete pair.second;
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ Section* BinaryWriter<ElemType>::CreateSection(const ConfigParameters& config, S
|
|||
FindConfigNames(config, "sectionType", subsections);
|
||||
|
||||
// look for any children and create them as well
|
||||
for each (std::wstring subsection in subsections)
|
||||
for (std::wstring subsection : subsections)
|
||||
{
|
||||
Section* newSection = CreateSection(config(subsection), section, records, windowSize);
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ void BinaryWriter<ElemType>::Init(const ConfigParameters& config)
|
|||
template<class ElemType>
|
||||
void BinaryWriter<ElemType>::GetSections(std::map<std::wstring, SectionType, nocase_compare>& sections)
|
||||
{
|
||||
for each (auto pair in m_sections)
|
||||
for (auto pair : m_sections)
|
||||
{
|
||||
sections[pair.first] = pair.second->GetSectionType();
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ bool BinaryWriter<ElemType>::SaveData(size_t recordStart, const std::map<std::ws
|
|||
throw runtime_error(message);
|
||||
}
|
||||
bool written = false;
|
||||
for each (auto pair in m_sections)
|
||||
for (auto pair : m_sections)
|
||||
{
|
||||
Section* section = pair.second;
|
||||
written = section->SaveData(recordStart, matrices, numRecords, datasetSize, byteVariableSized) || written;
|
||||
|
|
|
@ -503,7 +503,7 @@ void LUSequenceReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
found = true;
|
||||
}
|
||||
FindConfigNames(readerConfig, "wfile", names);
|
||||
for each (auto name in names)
|
||||
for (auto name : names)
|
||||
{
|
||||
ConfigParameters config = readerConfig(name);
|
||||
filesList.push_back(config("wfile"));
|
||||
|
@ -528,7 +528,7 @@ void LUSequenceReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
// now get the section names for map and category types
|
||||
std::map<std::wstring, SectionType, nocase_compare> sections;
|
||||
m_cachingWriter->GetSections(sections);
|
||||
for each (auto pair in sections)
|
||||
for (auto pair : sections)
|
||||
{
|
||||
// TODO: we would need to add a sequenceMap type here as well
|
||||
// or maybe change to heirarchal name (i.e. root.labelIn.map)
|
||||
|
@ -761,7 +761,7 @@ void LUSequenceReader<ElemType>::SetLabelMapping(const std::wstring& sectionName
|
|||
|
||||
labelInfo.mapIdToLabel = labelMapping;
|
||||
labelInfo.mapLabelToId.clear();
|
||||
for each (std::pair<unsigned, LabelType> var in labelMapping)
|
||||
for (std::pair<unsigned, LabelType> var : labelMapping)
|
||||
{
|
||||
labelInfo.mapLabelToId[var.second] = var.first;
|
||||
}
|
||||
|
|
|
@ -660,7 +660,7 @@ void SequenceReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
found = true;
|
||||
}
|
||||
FindConfigNames(readerConfig, "wfile", names);
|
||||
for each (auto name in names)
|
||||
for (auto name : names)
|
||||
{
|
||||
ConfigParameters config = readerConfig(name);
|
||||
filesList.push_back(config("wfile"));
|
||||
|
@ -685,7 +685,7 @@ void SequenceReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
// now get the section names for map and category types
|
||||
std::map<std::wstring, SectionType, nocase_compare> sections;
|
||||
m_cachingWriter->GetSections(sections);
|
||||
for each (auto pair in sections)
|
||||
for (auto pair : sections)
|
||||
{
|
||||
// TODO: we would need to add a sequenceMap type here as well
|
||||
// or maybe change to heirarchal name (i.e. root.labelIn.map)
|
||||
|
@ -1273,7 +1273,7 @@ void SequenceReader<ElemType>::SetLabelMapping(const std::wstring& sectionName,
|
|||
|
||||
labelInfo.mapIdToLabel = labelMapping;
|
||||
labelInfo.mapLabelToId.clear();
|
||||
for each (std::pair<unsigned, LabelType> var in labelMapping)
|
||||
for (std::pair<unsigned, LabelType> var : labelMapping)
|
||||
{
|
||||
labelInfo.mapLabelToId[var.second] = var.first;
|
||||
}
|
||||
|
|
|
@ -446,7 +446,7 @@ void UCIFastReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
found = true;
|
||||
}
|
||||
FindConfigNames(readerConfig, "wfile", names);
|
||||
for each (auto name in names)
|
||||
for (auto name : names)
|
||||
{
|
||||
ConfigParameters config = readerConfig(name);
|
||||
filesList.push_back(config("wfile"));
|
||||
|
@ -471,7 +471,7 @@ void UCIFastReader<ElemType>::InitCache(const ConfigParameters& readerConfig)
|
|||
// now get the section names for map and category types
|
||||
std::map<std::wstring, SectionType, nocase_compare> sections;
|
||||
m_cachingWriter->GetSections(sections);
|
||||
for each (auto pair in sections)
|
||||
for (auto pair : sections)
|
||||
{
|
||||
if (pair.second == sectionTypeCategoryLabel)
|
||||
{
|
||||
|
@ -925,7 +925,7 @@ void UCIFastReader<ElemType>::SetLabelMapping(const std::wstring& sectionName, c
|
|||
}
|
||||
m_mapIdToLabel = labelMapping;
|
||||
m_mapLabelToId.clear();
|
||||
for each (std::pair<unsigned, LabelType> var in labelMapping)
|
||||
for (std::pair<unsigned, LabelType> var : labelMapping)
|
||||
{
|
||||
m_mapLabelToId[var.second] = var.first;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ void CNTKEval<ElemType>::GetNodeDimensions(std::map<std::wstring, size_t>& dimen
|
|||
case nodeInput:
|
||||
{
|
||||
std::list<ComputationNode<ElemType>*> nodes = m_net->InputNodes(outputNodes[0]);
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
std::wstring name = node->NodeName();
|
||||
size_t size = node->FunctionValues().GetNumRows();
|
||||
|
@ -104,7 +104,7 @@ void CNTKEval<ElemType>::GetNodeDimensions(std::map<std::wstring, size_t>& dimen
|
|||
case nodeOutput:
|
||||
{
|
||||
std::vector<ComputationNode<ElemType>*> nodes = outputNodes;
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
std::wstring name = node->NodeName();
|
||||
size_t size = node->FunctionValues().GetNumRows();
|
||||
|
|
|
@ -1711,8 +1711,9 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
// first give criteria nodes as root node
|
||||
if (FinalCriterionNodes().size() > 0)
|
||||
{
|
||||
for each (ComputationNodePtr node in FinalCriterionNodes())
|
||||
for (ComputationNodePtr node : FinalCriterionNodes())
|
||||
{
|
||||
PrintComputationTree(node, false);
|
||||
if(!allowFragment) FormRecurentLoops(node);
|
||||
size_t actualMBSize = this->GetActualMBSize();
|
||||
this->SetActualMiniBatchSize(actualMBSize);
|
||||
|
@ -1726,7 +1727,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
// now output nodes
|
||||
if (OutputNodes().size() > 0)
|
||||
{
|
||||
for each (ComputationNodePtr node in OutputNodes())
|
||||
for (ComputationNodePtr node : OutputNodes())
|
||||
ValidateNetwork(node);
|
||||
}
|
||||
else if (!allowFragment)
|
||||
|
@ -1736,7 +1737,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
// now evaluation nodes
|
||||
if (EvaluationNodes().size() > 0)
|
||||
{
|
||||
for each (ComputationNodePtr node in EvaluationNodes())
|
||||
for (ComputationNodePtr node : EvaluationNodes())
|
||||
ValidateNetwork(node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
std::map<size_t, std::map<size_t, DoubleMatrix*>> ComputationNode<double>::s_constOnes;
|
||||
|
||||
template<class ElemType>
|
||||
TaskDescriptor<ElemType>* LearnableParameter<ElemType>::GetPTaskDescriptor(TaskType taskType, size_t inputIndex=0) const
|
||||
TaskDescriptor<ElemType>* LearnableParameter<ElemType>::GetPTaskDescriptor(TaskType taskType, size_t inputIndex/*=0*/) const
|
||||
{
|
||||
TaskDescriptor<ElemType>* descriptor = new TaskDescriptor<ElemType>(this, taskType);
|
||||
switch(taskType)
|
||||
|
|
|
@ -318,7 +318,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
Error("CopyInputs requires two symbols from the same network, %s and %s belong to different networks", params[0], params[1]);
|
||||
|
||||
ProcessNDLScript(netNdlFrom, ndlPassAll);
|
||||
for each (GenNameValue name in names)
|
||||
for (GenNameValue name : names)
|
||||
{
|
||||
ComputationNode<ElemType>* node = name.first;
|
||||
std::wstring nodeName = node->NodeName();
|
||||
|
@ -350,7 +350,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
|
||||
// process outstanding NDL scripts ensuring that the inputs have all been resolved
|
||||
ProcessNDLScript(netNdlFrom, ndlPassResolve);
|
||||
for each (ComputationNode<ElemType>* node in nodeTo)
|
||||
for (ComputationNode<ElemType>* node : nodeTo)
|
||||
{
|
||||
node->SetInput(inputNum, nodeFrom[0]);
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
ProcessNDLScript(netNdl, ndlPassInitial, false);
|
||||
|
||||
ComputationNetwork<ElemType>* cn = netNdl->cn;
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
switch(prop)
|
||||
{
|
||||
|
@ -519,7 +519,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
// make sure all NDL links have been resolved
|
||||
ProcessNDLScript(netNdl, ndlPassResolve);
|
||||
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
switch(prop)
|
||||
{
|
||||
|
@ -557,7 +557,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
|
||||
if (nodes.size() < 1)
|
||||
Error("Delete must have at least one target, %s doesn't represent any items",params[i]);
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
netNdl->cn->DeleteNode(node->NodeName());
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ void MELScript<ElemType>::CallFunction(const std::string& p_name, const ConfigPa
|
|||
ProcessNDLScript(netNdlFrom, ndlPassAll);
|
||||
|
||||
// now we have the original nodeNames from the input symbol, generate the output nodeNames
|
||||
for each (GenNameValue nodeName in nodeNames)
|
||||
for (GenNameValue nodeName : nodeNames)
|
||||
{
|
||||
ComputationNode<ElemType>* node = nodeName.first;
|
||||
netNdlFrom->cn->RenameNode(node, nodeName.second);
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
// cleanup all the computational networks we loaded
|
||||
~MELScript()
|
||||
{
|
||||
for each (auto iter in m_mapNameToNetNdl)
|
||||
for (auto iter : m_mapNameToNetNdl)
|
||||
{
|
||||
iter.second.Clear();
|
||||
}
|
||||
|
@ -58,15 +58,21 @@ public:
|
|||
Parse(m_scriptString);
|
||||
}
|
||||
|
||||
|
||||
// copy and move constructors
|
||||
MELScript(const MELScript& melScript) : ConfigParser(melScript)
|
||||
{
|
||||
*this = melScript;
|
||||
m_scriptString = melScript.m_scriptString;
|
||||
m_mapNameToNetNdl = melScript.m_mapNameToNetNdl; // computational networks
|
||||
m_netNdlDefault = melScript.m_netNdlDefault;
|
||||
// don't need to copy m_ndlScript, only used to store macros (which are stored in global instance anyway)
|
||||
}
|
||||
MELScript(const MELScript&& melScript) : ConfigParser(move(melScript))
|
||||
{
|
||||
*this = move(melScript);
|
||||
}
|
||||
m_scriptString = move(melScript.m_scriptString);
|
||||
m_mapNameToNetNdl = move(melScript.m_mapNameToNetNdl); // computational networks
|
||||
m_netNdlDefault = move(melScript.m_netNdlDefault);
|
||||
}
|
||||
void ProcessNDLScript(NetNdl<ElemType>* netNdl, NDLPass ndlPassUntil=ndlPassAll, bool fullValidate = false);
|
||||
void MELScript<ElemType>::SetProperty(ComputationNode<ElemType>* nodeProp, vector<ComputationNode<ElemType>*>& propArray, bool set);
|
||||
void CallFunction(const std::string& name, const ConfigParamList& params);
|
||||
|
@ -252,7 +258,7 @@ public:
|
|||
|
||||
// this is the *.W = L2.W case
|
||||
// We want to find all the destination existing matches and then assign the in node to all of them
|
||||
for each (ComputationNode<ElemType>* node in nodesOut)
|
||||
for (ComputationNode<ElemType>* node : nodesOut)
|
||||
{
|
||||
std::wstring nodeOutName = node->NodeName();
|
||||
GenNameValue value(nodeIn, nodeOutName);
|
||||
|
@ -263,7 +269,7 @@ public:
|
|||
else
|
||||
{
|
||||
// we are matching up one for one the input to output
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
std::wstring nodeName = node->NodeName();
|
||||
size_t start = firstCount;
|
||||
|
@ -307,7 +313,7 @@ public:
|
|||
copyFlags = CopyNodeFlags(copyFlags | CopyNodeFlags::copyNodeChildrenCrossNetwork);
|
||||
|
||||
// now we have the original names from the input symbol, generate the output names
|
||||
for each (GenNameValue name in copyNodes)
|
||||
for (GenNameValue name : copyNodes)
|
||||
{
|
||||
ComputationNode<ElemType>* node = name.first;
|
||||
std::wstring nodeName = node->NodeName();
|
||||
|
@ -321,7 +327,7 @@ public:
|
|||
if (copyFlags & CopyNodeFlags::copyNodeChildren)
|
||||
{
|
||||
// loop through the nodes that were copied and fixup all the child links
|
||||
for each (GenNameValue nodeVal in copyNodes)
|
||||
for (GenNameValue nodeVal : copyNodes)
|
||||
{
|
||||
ComputationNode<ElemType>* fromNode = nodeVal.first;
|
||||
ComputationNode<ElemType>* toNode = mapCopied[fromNode];
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
std::list<ComputationNodePtr> inputs = m_net->GetNodesWithType(InputValue<ElemType>::TypeName());
|
||||
int minibatchMax = 0;
|
||||
bool minibatchDifferent = false; // flag to see if all the values are already the same
|
||||
for each (ComputationNodePtr node in inputs)
|
||||
for (ComputationNodePtr node : inputs)
|
||||
{
|
||||
size_t cols = node->FunctionValues().GetNumCols();
|
||||
if (cols != minibatchMax)
|
||||
|
@ -51,7 +51,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
}
|
||||
if (minibatchDifferent)
|
||||
{
|
||||
for each (ComputationNodePtr node in inputs)
|
||||
for (ComputationNodePtr node : inputs)
|
||||
{
|
||||
Matrix<ElemType>& matrix = node->FunctionValues();
|
||||
size_t cols = matrix.GetNumCols();
|
||||
|
@ -143,31 +143,37 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
void CheckOutputNodes(NDLScript<ElemType>* script, std::string symbolName, std::vector<ComputationNodePtr>& compNodes)
|
||||
{
|
||||
NDLNode<ElemType>* nodeArray = script->FindSymbol(symbolName);
|
||||
bool valid = (nodeArray != NULL && nodeArray->GetType() == ndlTypeArray) || m_net->FeatureNodes().size() > 0;
|
||||
bool valid = m_net->FeatureNodes().size() > 0; // see if it's already valid
|
||||
if (!valid && nodeArray) //otherwise, see if we found a symbol
|
||||
{
|
||||
NDLType outputType = nodeArray->GetType();
|
||||
// accept either an array of nodes, or a single node
|
||||
valid = (outputType == ndlTypeArray || outputType == ndlTypeFunction || outputType == ndlTypeMacroCall);
|
||||
}
|
||||
if (!valid)
|
||||
Error("Invalid network node definition for '%s', nonexistant or wrong type", symbolName.c_str());
|
||||
if (nodeArray)
|
||||
{
|
||||
vector<NDLNode<ElemType>*> nodes = nodeArray->GetParameters();
|
||||
vector<NDLNode<ElemType>*> nodes;
|
||||
if (nodeArray->GetType() == ndlTypeArray)
|
||||
nodes = nodeArray->GetParameters();
|
||||
else
|
||||
nodes.push_back(nodeArray);
|
||||
|
||||
for (size_t i=0; i<nodes.size(); i++)
|
||||
{
|
||||
// get the computation node
|
||||
ComputationNodePtr cnNode = (ComputationNodePtr)nodes[i]->GetEvalValue();
|
||||
|
||||
// if no evaluation value exists and the NDL node is a dot name, look it up
|
||||
if (cnNode == nullptr && nodes[i]->GetType() == ndlTypeDotParameter)
|
||||
// if no evaluation value exists throw an error
|
||||
if (cnNode == nullptr)
|
||||
{
|
||||
const std::wstring& name = msra::strfun::utf16(nodes[i]->GetName());
|
||||
if (m_net->NodeNameExist(name))
|
||||
{
|
||||
cnNode = m_net->GetNodeFromName(name);
|
||||
nodes[i]->SetEvalValue(cnNode);
|
||||
}
|
||||
Error("Invalid node '%s' as an output node, nonexistant or wrong type", nodes[i]->GetName().c_str());
|
||||
}
|
||||
|
||||
// see if it's already in the collection
|
||||
bool found = false;
|
||||
for each (ComputationNodePtr compNode in compNodes)
|
||||
for (ComputationNodePtr compNode : compNodes)
|
||||
{
|
||||
if (cnNode == compNode)
|
||||
{
|
||||
|
|
|
@ -10,8 +10,96 @@
|
|||
|
||||
namespace Microsoft { namespace MSR { namespace CNTK {
|
||||
|
||||
// NOTE: We changed the behavior to require complete match
|
||||
// EqualInsensitive - check to see if two nodes are equal up to the length of the first string (must be at least half as long as actual node name)
|
||||
// DuplicateNode - Duplicate a node in a macro as needed (it might already exist)
|
||||
// node - node we are duplicating
|
||||
// return - the new duplicated node if it didn't exist, or the previously duplicated node if it already did
|
||||
template <typename ElemType>
|
||||
NDLNode<ElemType>* NDLScript<ElemType>::DuplicateNode(NDLNode<ElemType>* node)
|
||||
{
|
||||
NDLNode<ElemType>* newNode = node->Copy();
|
||||
m_children.push_back(newNode);
|
||||
newNode->SetParentScript(this);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
template <typename ElemType>
|
||||
NDLScript<ElemType>::NDLScript(const NDLScript& copyMe) : ConfigParser(copyMe)
|
||||
{
|
||||
m_baseName = copyMe.m_baseName;
|
||||
m_scriptString = copyMe.m_scriptString;
|
||||
m_macroNode = copyMe.m_macroNode;
|
||||
m_noDefinitions = copyMe.m_noDefinitions; // no definitions can be made in this script, interpret all macro/function names as calls
|
||||
m_definingMacro = false; // not defining when expanding macros (only reason to call this method
|
||||
m_cn = copyMe.m_cn; // computation network to use for backup symbol lookup. Used for MEL where NDL and network nodes are mixed
|
||||
|
||||
// script lines in parsed node order
|
||||
for (NDLNode<ElemType>* node : copyMe.m_script)
|
||||
{
|
||||
// duplicate this node
|
||||
NDLNode<ElemType>* newNode = DuplicateNode(node);
|
||||
AddSymbol(newNode->GetName(), newNode);
|
||||
|
||||
// now get the parameters to the functions added
|
||||
ConfigValue value = newNode->GetParamString();
|
||||
ParseParameters(newNode, value, true /*createNew*/);
|
||||
|
||||
// add it to the new script
|
||||
m_script.push_back(newNode);
|
||||
}
|
||||
|
||||
// now search the symbol table for other symbols that haven't been copied yet
|
||||
// this happens for constants defined in macros and such
|
||||
for (std::pair<std::string, NDLNode<ElemType>*> pair : copyMe.m_symbols)
|
||||
{
|
||||
// if we can't find the symbol in the copied symbol table, copy it here
|
||||
if (m_symbols.find(pair.first) == end(m_symbols))
|
||||
{
|
||||
// duplicate this node
|
||||
NDLNode<ElemType>* newNode = DuplicateNode(pair.second);
|
||||
AddSymbol(pair.first, newNode);
|
||||
// anything that takes parameters should be evaluated in the script loop
|
||||
assert(newNode->GetParamString().empty());
|
||||
}
|
||||
}
|
||||
// NOTE: the child nodes get populated as the nodes are duplicated in the loop above
|
||||
// we shouldn't try to duplicate them separately
|
||||
}
|
||||
|
||||
// copy constructor, creates a new disconnected copy of this node
|
||||
// doesn't copy everything, so use for macro expansion only (it's private)
|
||||
// copyMe - node to copy
|
||||
template <typename ElemType>
|
||||
NDLNode<ElemType>::NDLNode(const NDLNode<ElemType>& copyMe)
|
||||
{
|
||||
m_name = copyMe.m_name; // value on the left of the equals
|
||||
m_value = copyMe.m_value; // value on the right of the equals (CN node name, or value)
|
||||
m_parent = copyMe.m_parent; // parent script
|
||||
m_type = copyMe.m_type; //type of node
|
||||
m_paramString = copyMe.m_paramString; // parameter of a function/array
|
||||
m_paramMacro = copyMe.m_paramMacro; // parameter of a macro (the variables used in the macro definition)
|
||||
// don't copy over the parameters, they will be reparsed after the copy
|
||||
//m_parameters = copyMe.m_parameters; // copy over the parameters straight
|
||||
|
||||
m_eval = nullptr; // pointer to an arbitrary eval structure
|
||||
// script for macro calls, need to expand the macro for each call
|
||||
// if it's not expanded the evalValue will be overwitten on multiple calls to a macro
|
||||
m_script = (copyMe.m_script) ? new NDLScript<ElemType>(*copyMe.m_script) : nullptr;
|
||||
}
|
||||
template <typename ElemType>
|
||||
NDLScript<ElemType>::NDLScript(const NDLScript&& moveMe) : ConfigParser(move(moveMe))
|
||||
{
|
||||
m_baseName = move(moveMe.m_baseName);
|
||||
m_scriptString = move(moveMe.m_scriptString);
|
||||
m_script = move(moveMe.m_script); // script lines in parsed node order, macros will have definition followed by body
|
||||
m_symbols = move(moveMe.m_symbols); // symbol table
|
||||
m_macroNode = move(moveMe.m_macroNode); // set when interpretting a macro definition
|
||||
m_noDefinitions = move(moveMe.m_noDefinitions); // no definitions can be made in this script, interpret all macro/function names as calls
|
||||
m_definingMacro = move(moveMe.m_definingMacro);
|
||||
m_children = move(moveMe.m_children); // child nodes. Note that m_script nodes may not be children of this object, they include macro nodes
|
||||
m_cn = move(moveMe.m_cn); // computation network to use for backup symbol lookup. Used for MEL where NDL and network nodes are mixed
|
||||
}
|
||||
|
||||
// EqualInsensitive - check to see if two nodes are equal
|
||||
// string1 - [in,out] string to compare, if comparision is equal insensitive but not sensitive, will replace with sensitive version
|
||||
// string2 - second string to compare
|
||||
// alternate - alternate naming of the string
|
||||
|
|
|
@ -37,7 +37,6 @@ enum NDLType
|
|||
ndlTypeVariable,
|
||||
ndlTypeParameter, // parameter value, must be looked up to get actual value
|
||||
ndlTypeUndetermined, // an undetermined value that will later be resolved
|
||||
ndlTypeDotParameter, // a dot parameter that needs to be fully resolved
|
||||
ndlTypeOptionalParameter,
|
||||
ndlTypeArray,
|
||||
ndlTypeMacroCall, // calling a macro
|
||||
|
@ -183,11 +182,18 @@ public:
|
|||
~NDLNode()
|
||||
{}
|
||||
|
||||
// publicly accessible Copy method
|
||||
// should only be used for macro expansion
|
||||
NDLNode* Copy() const
|
||||
{
|
||||
NDLNode* ret = new NDLNode(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
NDLNode(NDLNode& copyMe)
|
||||
{
|
||||
throw std::logic_error("'NDLNode(NDLNode& copyMe)' should never be called.");
|
||||
}
|
||||
|
||||
// copy constructor, creates a new disconnected copy of this node for macro expansion
|
||||
NDLNode(const NDLNode& copyMe);
|
||||
|
||||
NDLNode& operator=(NDLNode& copyMe) //this is just a place holder implementation which is not functioning but prevent callers to use it.
|
||||
{
|
||||
|
@ -205,29 +211,30 @@ private:
|
|||
|
||||
public:
|
||||
void SetScript(NDLScript<ElemType>* script) {m_script = script;}
|
||||
NDLScript<ElemType>* GetScript() {return m_script;}
|
||||
NDLScript<ElemType>* GetScript() const {return m_script;}
|
||||
void SetType(NDLType type) {m_type = type;}
|
||||
NDLType GetType() {return m_type;}
|
||||
std::string GetName() {return m_name;}
|
||||
NDLType GetType() const {return m_type;}
|
||||
const std::string& GetName() const {return m_name;}
|
||||
void SetName(std::string &name) {m_name = name;}
|
||||
ConfigValue GetValue() {return m_value;}
|
||||
ConfigValue GetValue() const {return m_value;}
|
||||
void SetValue(std::string &value) {m_value = value;}
|
||||
|
||||
// parameters of a function (ndlTypFunction), or parameters in the call to a macro
|
||||
void SetParamString(ConfigValue paramString) {m_paramString = paramString;}
|
||||
ConfigArray GetParamString() {return m_paramString;}
|
||||
ConfigArray GetParamString() const {return m_paramString;}
|
||||
|
||||
// parameters of a macro
|
||||
void SetParamMacro(ConfigValue paramMacro) {m_paramMacro = paramMacro;}
|
||||
ConfigArray GetParamMacro() {return m_paramMacro;}
|
||||
ConfigArray GetParamMacro() const {return m_paramMacro;}
|
||||
|
||||
NDLScript<ElemType>* GetParentScript() {return m_parent;}
|
||||
void SetParentScript(NDLScript<ElemType>* script) {m_parent = script;}
|
||||
NDLScript<ElemType>* GetParentScript() { return m_parent; }
|
||||
|
||||
// get parameters, either just optional or just regular
|
||||
vector<NDLNode*> GetParameters(bool optional=false)
|
||||
vector<NDLNode*> GetParameters(bool optional=false) const
|
||||
{
|
||||
vector<NDLNode*> result;
|
||||
for each(NDLNode* param in m_parameters)
|
||||
for (NDLNode* param : m_parameters)
|
||||
{
|
||||
bool optParam = param->GetType() == ndlTypeOptionalParameter;
|
||||
if (optParam == optional)
|
||||
|
@ -237,16 +244,16 @@ public:
|
|||
}
|
||||
|
||||
// Get/Set eval values
|
||||
void* GetEvalValue() { return m_eval;}
|
||||
void* GetEvalValue() const { return m_eval;}
|
||||
void SetEvalValue(void* evalValue) {m_eval = evalValue;}
|
||||
|
||||
// FindOptionalParameter - Get an optional parameter value
|
||||
// GetOptionalParameter - Get an optional parameter value
|
||||
// name - the name to search for in the optional parameters
|
||||
// default - the default value (if not found)
|
||||
// returns: parameter value if found, or default value otherwise
|
||||
ConfigValue GetOptionalParameter(const std::string& name, const std::string& default)
|
||||
ConfigValue GetOptionalParameter(const std::string& name, const std::string& default) const
|
||||
{
|
||||
for each(NDLNode* param in m_parameters)
|
||||
for (NDLNode* param : m_parameters)
|
||||
{
|
||||
bool optParam = param->GetType() == ndlTypeOptionalParameter;
|
||||
if (optParam && !_strcmpi(param->GetName().c_str(), name.c_str()))
|
||||
|
@ -274,8 +281,7 @@ public:
|
|||
ConfigValue GetScalar()
|
||||
{
|
||||
NDLNode<ElemType>* node = this;
|
||||
while (node && (node->GetType() == ndlTypeVariable || node->GetType() == ndlTypeParameter
|
||||
|| node->GetType() == ndlTypeDotParameter))
|
||||
while (node && (node->GetType() == ndlTypeVariable || node->GetType() == ndlTypeParameter))
|
||||
{
|
||||
node = node->FindNode(node->GetValue(), true /*searchForDotNames*/);
|
||||
}
|
||||
|
@ -306,9 +312,18 @@ public:
|
|||
m_parameters.size(),m_paramMacro.size(),m_value.c_str());
|
||||
}
|
||||
|
||||
// on the initial pass we want to expand the macros out,
|
||||
// in other words make a copy of the global macro so we can call macros multiple times
|
||||
// and have each instance refer to different nodes
|
||||
//if (pass == ndlPassInitial)
|
||||
//{
|
||||
// // make a copy of the script
|
||||
// NDLScript<ElemType>* macroScript = m_script;
|
||||
// m_script = new NDLScript<ElemType>(*macroScript);
|
||||
//}
|
||||
// we need to clear out the eval values, because we need to re-evaluate each time a macro is called
|
||||
// otherwise, we look at the eval values from last time and think it is accurate
|
||||
m_script->ClearEvalValues();
|
||||
// m_script->ClearEvalValues();
|
||||
|
||||
// assign the actual parameters in the script so we can execute it
|
||||
for (int i=0; i < m_parameters.size(); ++i)
|
||||
|
@ -339,13 +354,15 @@ public:
|
|||
m_script->AssignSymbol(paramName, nodeParam);
|
||||
|
||||
// look for the symbol already in the node evaluators symbols
|
||||
const wstring& name = msra::strfun::utf16(paramName);
|
||||
void* evalValue = nodeEval.FindSymbol(name);
|
||||
// if it's there, use it
|
||||
if (evalValue != NULL)
|
||||
{
|
||||
nodeParam->SetEvalValue(evalValue);
|
||||
}
|
||||
// this code should not happen, it's looking in the computation network for parameter names, just wrong
|
||||
// const wstring& name = msra::strfun::utf16(paramName);
|
||||
// void* evalValue = nodeEval.FindSymbol(name);
|
||||
// // if it's there, use it
|
||||
// if (evalValue != NULL)
|
||||
// {
|
||||
//assert(nullptr == nodeParam->GetEvalValue() || evalValue == nodeParam->GetEvalValue());
|
||||
// nodeParam->SetEvalValue(evalValue);
|
||||
// }
|
||||
}
|
||||
|
||||
std::wstring newBase = baseName;
|
||||
|
@ -389,14 +406,16 @@ private:
|
|||
static NDLScript<ElemType> s_global; //("global"); // global script for storing macros and global nodes
|
||||
std::vector<NDLNode<ElemType>*> m_children; // child nodes. Note that m_script nodes may not be children of this object, they include macro nodes
|
||||
ComputationNetwork<ElemType>* m_cn; // computation network to use for backup symbol lookup. Used for MEL where NDL and network nodes are mixed
|
||||
bool m_definingMacro; // currently defining a macro, flag to determine if we are defining or interpretting a macro call
|
||||
|
||||
public:
|
||||
// constructors that take a config name
|
||||
NDLScript (const std::string & configname) : ConfigParser(';', configname) { m_macroNode = NULL; m_noDefinitions=false;}
|
||||
NDLScript (const std::wstring & configname) : ConfigParser(';', configname) { m_macroNode = NULL; m_noDefinitions=false;}
|
||||
NDLScript(const std::string & configname) : ConfigParser(';', configname) { m_macroNode = NULL; m_noDefinitions = false; m_definingMacro = false; }
|
||||
NDLScript(const std::wstring & configname) : ConfigParser(';', configname) { m_macroNode = NULL; m_noDefinitions = false; m_definingMacro = false; }
|
||||
~NDLScript()
|
||||
{
|
||||
// need to free all the child nodes attached to this script node
|
||||
for each (NDLNode<ElemType>* node in m_children)
|
||||
for (NDLNode<ElemType>* node : m_children)
|
||||
{
|
||||
delete node;
|
||||
}
|
||||
|
@ -404,13 +423,14 @@ public:
|
|||
}
|
||||
|
||||
// empty constructor
|
||||
NDLScript () : ConfigParser(';') { m_macroNode = NULL; m_noDefinitions=false; } // parameterless version if needed
|
||||
NDLScript() : ConfigParser(';') { m_macroNode = NULL; m_noDefinitions = false; m_definingMacro = false; } // parameterless version if needed
|
||||
|
||||
// construct NDLScript from a ConfigValue, propogate the config Name
|
||||
NDLScript(const ConfigValue& configValue) : ConfigParser(';',configValue.Name())
|
||||
{
|
||||
m_macroNode = NULL;
|
||||
m_noDefinitions=false;
|
||||
m_definingMacro = false;
|
||||
m_scriptString = configValue;
|
||||
Parse(m_scriptString);
|
||||
}
|
||||
|
@ -422,6 +442,7 @@ public:
|
|||
NDLScript(const ConfigValue& configValue, std::string macroName, bool oneLineDefinition) : ConfigParser(';',configValue.Name())
|
||||
{
|
||||
m_noDefinitions = oneLineDefinition;
|
||||
m_definingMacro = true;
|
||||
m_macroNode = NULL;
|
||||
m_scriptString = configValue;
|
||||
NDLNode<ElemType>* ndlNode = s_global.CheckName(macroName, true);
|
||||
|
@ -441,21 +462,16 @@ public:
|
|||
AddSymbol(param, paramNode);
|
||||
}
|
||||
Parse(m_scriptString);
|
||||
m_definingMacro = false;
|
||||
}
|
||||
|
||||
|
||||
// copy and move constructors
|
||||
NDLScript(const NDLScript& configValue) : ConfigParser(configValue)
|
||||
{
|
||||
*this = configValue;
|
||||
m_macroNode = NULL;
|
||||
}
|
||||
NDLScript(const NDLScript&& configValue) : ConfigParser(move(configValue))
|
||||
{
|
||||
*this = move(configValue);
|
||||
m_macroNode = NULL;
|
||||
}
|
||||
|
||||
NDLScript(const NDLScript& copyMe);
|
||||
NDLScript(const NDLScript&& moveMe);
|
||||
private:
|
||||
NDLNode<ElemType>* NDLScript<ElemType>::DuplicateNode(NDLNode<ElemType>* node);
|
||||
public:
|
||||
// GlobalScript - Access to global script
|
||||
static NDLScript<ElemType>& GlobalScript() {return s_global;}
|
||||
|
||||
|
@ -483,12 +499,12 @@ public:
|
|||
void Clear()
|
||||
{
|
||||
|
||||
for each (NDLNode<ElemType>* node in m_children)
|
||||
for (NDLNode<ElemType>* node : m_children)
|
||||
{
|
||||
delete node;
|
||||
}
|
||||
m_children.clear();
|
||||
for each (NDLNode<ElemType>* node in m_script)
|
||||
for (NDLNode<ElemType>* node : m_script)
|
||||
{
|
||||
delete node;
|
||||
}
|
||||
|
@ -498,7 +514,7 @@ public:
|
|||
}
|
||||
void ClearEvalValues()
|
||||
{
|
||||
for each (NDLNode<ElemType>* node in m_children)
|
||||
for (NDLNode<ElemType>* node : m_children)
|
||||
{
|
||||
node->SetEvalValue(NULL);
|
||||
}
|
||||
|
@ -521,7 +537,7 @@ public:
|
|||
// symbol - symbol to find
|
||||
// searchForDotNames - search for NDL symbols traversing call heirarchy
|
||||
// returns - node this symbol references
|
||||
NDLNode<ElemType>* FindSymbol(const std::string& symbol, bool searchForDotNames=false)
|
||||
NDLNode<ElemType>* FindSymbol(const std::string& symbol, bool searchForDotNames=true)
|
||||
{
|
||||
// handle the no dot names case
|
||||
if (!searchForDotNames)
|
||||
|
@ -551,7 +567,7 @@ public:
|
|||
{
|
||||
if (node->GetType() != ndlTypeMacroCall || script == NULL)
|
||||
Error("Symbol name not valid, %s is not a macro, so %s cannot be interpretted",search.c_str(),symbol.c_str() );
|
||||
return script->FindSymbol(symbol.substr(firstDot+1));
|
||||
return script->FindSymbol(symbol.substr(firstDot+1), searchForDotNames);
|
||||
}
|
||||
}
|
||||
return found->second;
|
||||
|
@ -573,7 +589,7 @@ public:
|
|||
{
|
||||
vector<NDLNode<ElemType>*> result;
|
||||
std::string empty;
|
||||
for each (auto symbol in m_symbols)
|
||||
for (auto symbol : m_symbols)
|
||||
{
|
||||
NDLNode<ElemType>* node = symbol.second;
|
||||
std::string value = node->GetOptionalParameter(optParamName, empty);
|
||||
|
@ -657,6 +673,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// IsMacroDefinition - is this a macro definition?
|
||||
// returns - true if a definition, otherwise false
|
||||
bool IsMacroDefinition()
|
||||
{
|
||||
return m_definingMacro;
|
||||
}
|
||||
|
||||
// CheckName - check for a name in our symbols, see if it exists
|
||||
// name - name we are looking for
|
||||
// localOnly - only look in the current scope, and not the global scope
|
||||
|
@ -682,7 +705,15 @@ public:
|
|||
// if we are calling a macro we need to keep track of formal parameters,
|
||||
// keep them as strings in this macroCall node
|
||||
NDLNode<ElemType>* newNode = new NDLNode<ElemType>("", name, this, ndlTypeMacroCall);
|
||||
newNode->SetScript(node->GetScript());
|
||||
NDLScript<ElemType>* script = node->GetScript();
|
||||
|
||||
// if this is a macro call (and not a definition), we want to expand the macro (make a copy)
|
||||
if (!IsMacroDefinition())
|
||||
{
|
||||
script = new NDLScript<ElemType>(*script);
|
||||
}
|
||||
newNode->SetScript(script);
|
||||
|
||||
newNode->SetParamMacro(node->GetParamMacro());
|
||||
node = newNode;
|
||||
}
|
||||
|
@ -724,7 +755,8 @@ public:
|
|||
// ParseParameters - parse the parameters of a macro, or an array
|
||||
// ndlNode - node we should add the parameters to
|
||||
// value - parameters as config value
|
||||
void ParseParameters(NDLNode<ElemType>* ndlNode, const ConfigValue& value)
|
||||
// createNew - create a new parameter node if one does not exist
|
||||
void ParseParameters(NDLNode<ElemType>* ndlNode, const ConfigValue& value, bool createNew=false)
|
||||
{
|
||||
ConfigArray parameters = value;
|
||||
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter)
|
||||
|
@ -736,13 +768,12 @@ public:
|
|||
paramNode = ParseCall(param);
|
||||
else // must be predefined variable or constant
|
||||
{
|
||||
paramNode = ParseVariable(param, false);
|
||||
paramNode = ParseVariable(param, createNew);
|
||||
|
||||
// if the method we are allowing undetermined parameters, create a placeholder that will be filled in later
|
||||
// if we can't find the node right now, it's undetermined, must be defined later, or throw an error later
|
||||
if (paramNode == nullptr)
|
||||
{
|
||||
bool dotName = param.find('.') != npos; // look for a dot name
|
||||
paramNode = new NDLNode<ElemType>(param, param, this, dotName?ndlTypeDotParameter:ndlTypeUndetermined);
|
||||
paramNode = new NDLNode<ElemType>(param, param, this, ndlTypeUndetermined);
|
||||
// add to the symbol table
|
||||
AddSymbol(param, paramNode);
|
||||
}
|
||||
|
@ -779,7 +810,7 @@ public:
|
|||
if (found == npos)
|
||||
{
|
||||
ndlNode = new NDLNode<ElemType>("", token, this, ndlTypeConstant);
|
||||
}
|
||||
}
|
||||
// not a constant, so must be a variable
|
||||
else
|
||||
{
|
||||
|
@ -794,13 +825,18 @@ public:
|
|||
Trim(value);
|
||||
|
||||
ndlNode = new NDLNode<ElemType>(name, value, this, ndlTypeOptionalParameter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ndlNode = CheckName(token);
|
||||
if (createNew && ndlNode == NULL)
|
||||
ndlNode = new NDLNode<ElemType>("", token, this, ndlTypeVariable);
|
||||
}
|
||||
if (createNew && ndlNode == NULL)
|
||||
{
|
||||
// NOTE: currently we only get here in Parameter scenarios,
|
||||
// if other scenarios present themselves, need a good way to change the type
|
||||
ndlNode = new NDLNode<ElemType>(token, token, this, ndlTypeParameter);
|
||||
AddSymbol(token, ndlNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ndlNode;
|
||||
}
|
||||
|
@ -975,6 +1011,31 @@ public:
|
|||
return tokenEnd;
|
||||
}
|
||||
|
||||
// ExpandMacro - Expand a macro into a new macro definition
|
||||
// node - NDLNode that holds the macro call
|
||||
// returns: new node with the expanded macro
|
||||
NDLNode<ElemType>* ExpandMacro(const NDLNode<ElemType>* node)
|
||||
{
|
||||
assert(node->GetType() == ndlTypeMacroCall); // needs to be a macro call (not definition)
|
||||
|
||||
std::string name = node->GetName();
|
||||
// if we are calling a macro make a new copy of it and execute that instead (macro expansion)
|
||||
// we do this so the evalValues in the macros will be valid regardless of number of instantiations
|
||||
NDLNode<ElemType>* newNode = new NDLNode<ElemType>(name, node->GetValue(), this, ndlTypeMacroCall);
|
||||
NDLScript<ElemType>* newScript = new NDLScript<ElemType>(*node->GetScript());
|
||||
newNode->SetScript(newScript);
|
||||
newNode->SetParamMacro(node->GetParamMacro());
|
||||
|
||||
// now get the parameters to the macro added
|
||||
ConfigValue paramString = node->GetParamString();
|
||||
ParseParameters(newNode, paramString, true /*createNew*/);
|
||||
newNode->SetParamString(paramString);
|
||||
|
||||
// fixup the symbol table to point to this one instead
|
||||
AssignSymbol(name, newNode);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
// Evaluate - Evaluate the script
|
||||
// nodeEval - the node evaluator to call
|
||||
// baseName - baseName for all labels
|
||||
|
@ -987,7 +1048,7 @@ public:
|
|||
std::wstring prevBaseName = GetBaseName();
|
||||
SetBaseName(baseName);
|
||||
|
||||
for each (auto node in m_script)
|
||||
for (auto& node : m_script)
|
||||
{
|
||||
// if we are in skip mode, and we found the skipThrough node,
|
||||
// move out of skip mode and start processing at next node
|
||||
|
|
|
@ -162,7 +162,7 @@ void TaskDescriptor<ElemType>::ConfigureInputsAndOutputs(UINT& uidCounter, std::
|
|||
// get the counts of ports
|
||||
m_numInputPorts = 0;
|
||||
m_numOutputPorts = 0;
|
||||
for each (ParamData<ElemType>* param in m_paramData)
|
||||
for (ParamData<ElemType>* param : m_paramData)
|
||||
{
|
||||
if (param->options & paramOptionsInput)
|
||||
m_numInputPorts++;
|
||||
|
@ -189,7 +189,7 @@ void TaskDescriptor<ElemType>::ConfigureInputsAndOutputs(UINT& uidCounter, std::
|
|||
|
||||
// create the ports for the other parameters
|
||||
int paramNum = 0;
|
||||
for each (ParamData<ElemType>* param in m_paramData)
|
||||
for (ParamData<ElemType>* param : m_paramData)
|
||||
{
|
||||
Port* port = NULL;
|
||||
|
||||
|
@ -504,7 +504,7 @@ template<class ElemType>
|
|||
void TaskDescriptor<ElemType>::CreateBackAndInitChannel(Graph* graph, std::map<const std::string, PTask::GraphOutputChannel*>& outputNameToChannelsMap)
|
||||
{
|
||||
const vector<ParamData<ElemType>*>& params = this->GetParameters();
|
||||
for each (const ParamData<ElemType>* param in params)
|
||||
for (const ParamData<ElemType>* param : params)
|
||||
{
|
||||
// initialize the values at the beginning, copy from source matrix
|
||||
if ((param->options & (paramOptionsInitOnBOF | paramOptionsMaintainValue | paramOptionsInitalValuesOnDestinations)) && param->assocData != NULL)
|
||||
|
@ -548,14 +548,14 @@ void TaskDescriptor<ElemType>::CreateBackAndInitChannel(Graph* graph, std::map<c
|
|||
template<class ElemType>
|
||||
void PTaskGraphBuilder<ElemType>::PushActualMBSize(const std::list<ComputationNodePtr>& learnableNodes, size_t actualMBSize, PTask::CONTROLSIGNAL signal/*=DBCTLC_NONE*/)
|
||||
{
|
||||
for each (ComputationNodePtr node in learnableNodes)
|
||||
for (ComputationNodePtr node : learnableNodes)
|
||||
{
|
||||
std::string inputName = msra::strfun::utf8(node->NodeName())+"_actualMBSize";
|
||||
auto iter = m_inputNameToChannelsMap.find(inputName);
|
||||
if (iter == m_inputNameToChannelsMap.end())
|
||||
throw std::runtime_error("input channel not created for actualMBSize");
|
||||
std::vector<PTask::GraphInputChannel*>* channels = iter->second;
|
||||
for each (PTask::GraphInputChannel* channel in *channels)
|
||||
for (PTask::GraphInputChannel* channel : *channels)
|
||||
{
|
||||
Datablock* pblock = PTask::Runtime::AllocateDatablock(channel->GetTemplate(), (void *)&actualMBSize, sizeof(size_t), channel, PT_ACCESS_DEFAULT, signal);
|
||||
channel->Push(pblock);
|
||||
|
@ -570,14 +570,14 @@ void PTaskGraphBuilder<ElemType>::PushActualMBSize(const std::list<ComputationNo
|
|||
template<class ElemType>
|
||||
void PTaskGraphBuilder<ElemType>::PushData(std::map<std::wstring, Matrix<ElemType>*>& data, PTask::CONTROLSIGNAL signal/*=DBCTLC_NONE*/)
|
||||
{
|
||||
for each (std::pair<std::wstring, Matrix<ElemType>*> pair in data)
|
||||
for (std::pair<std::wstring, Matrix<ElemType>*> pair : data)
|
||||
{
|
||||
std::string inputName = msra::strfun::utf8(pair.first)+"_FunctionValues";
|
||||
auto iter = m_inputNameToChannelsMap.find(inputName);
|
||||
if (iter == m_inputNameToChannelsMap.end())
|
||||
throw std::runtime_error("input channel not created for data matrix");
|
||||
std::vector<PTask::GraphInputChannel*>* channels = iter->second;
|
||||
for each (PTask::GraphInputChannel* channel in *channels)
|
||||
for (PTask::GraphInputChannel* channel : *channels)
|
||||
{
|
||||
Matrix<ElemType>* matrix = pair.second;
|
||||
PushMatrix(*matrix, channel, signal);
|
||||
|
@ -658,7 +658,7 @@ void PTaskGraphBuilder<ElemType>::GetValue(ComputationNode<ElemType>* node, Matr
|
|||
template<class ElemType>
|
||||
void PTaskGraphBuilder<ElemType>::CreateOutputChannels(const vector<ComputationNodePtr>& nodes)
|
||||
{
|
||||
for each (ComputationNode<ElemType>* node in nodes)
|
||||
for (ComputationNode<ElemType>* node : nodes)
|
||||
{
|
||||
std::string nameOutChannel = msra::strfun::utf8(node->NodeName());
|
||||
std::string name = nameOutChannel+"_FunctionValues";
|
||||
|
@ -916,7 +916,7 @@ template<class ElemType>
|
|||
void PTaskGraphBuilder<ElemType>::UpdateParameters(void* sgd, const ElemType learnRatePerSample, const size_t expectedMBSize)
|
||||
{
|
||||
std::list<ComputationNodePtr> precompNodes = m_cn->GetNodesRequirePreComputation(nullptr, false);
|
||||
for each (ComputationNodePtr node in precompNodes)
|
||||
for (ComputationNodePtr node : precompNodes)
|
||||
{
|
||||
std::string name = msra::strfun::utf8(node->NodeName()) + "_FunctionValues";
|
||||
std::map<const std::string, std::vector<PTask::GraphInputChannel*>*>::iterator iter
|
||||
|
@ -929,14 +929,14 @@ void PTaskGraphBuilder<ElemType>::UpdateParameters(void* sgd, const ElemType lea
|
|||
mat.TransferFromDeviceToDevice(mat.GetDeviceId(), CPUDEVICE, true);
|
||||
|
||||
vector<GraphInputChannel*>* inChannels = iter->second;
|
||||
for each (GraphInputChannel* input in *inChannels)
|
||||
for (GraphInputChannel* input : *inChannels)
|
||||
{
|
||||
PushMatrix(node->FunctionValues(), input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for each (std::pair<const std::string, TaskDescriptorPtr> pair in m_taskNameToTaskDescriptorMap)
|
||||
for (std::pair<const std::string, TaskDescriptorPtr> pair : m_taskNameToTaskDescriptorMap)
|
||||
{
|
||||
const TaskDescriptorPtr taskDescriptor = pair.second;
|
||||
const std::vector<ParamData<ElemType>*>& params = taskDescriptor->GetParameters();
|
||||
|
|
|
@ -472,7 +472,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
{
|
||||
// set the minibatch size to the largest thing we will ever see
|
||||
int maxMbSize = 0;
|
||||
for each (int val in m_mbSize)
|
||||
for (int val : m_mbSize)
|
||||
{
|
||||
maxMbSize = max(val, maxMbSize);
|
||||
}
|
||||
|
@ -888,7 +888,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
ptaskGraphBuilder->StartPTaskGraph();
|
||||
|
||||
// currently CNTK likes to keep things on the GPU, and PTask expects things to be on the CPU, so tell CNTK to keep data on the CPU
|
||||
for each (std::pair<std::wstring, Matrix<ElemType>*> inpair in inputMatrices)
|
||||
for (std::pair<std::wstring, Matrix<ElemType>*> inpair : inputMatrices)
|
||||
{
|
||||
Matrix<ElemType>* mat = inpair.second;
|
||||
mat->SetPreferredDeviceId(CPUDEVICE);
|
||||
|
@ -1030,7 +1030,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
|
|||
{
|
||||
// when the epoch is complete, we need to transfer all the values back to the LearnableNodes, which will be saved off as the model
|
||||
std::list<ComputationNodePtr> learnableNodes = net.LearnableNodes(criterionNodes[0]);
|
||||
for each (ComputationNodePtr node in learnableNodes)
|
||||
for (ComputationNodePtr node : learnableNodes)
|
||||
{
|
||||
ptaskGraphBuilder->GetValue(node, node->FunctionValues());
|
||||
}
|
||||
|
|
|
@ -51,11 +51,16 @@ public:
|
|||
std::wstring cnNodeType = msra::strfun::utf16(node->GetValue());
|
||||
|
||||
ComputationNodePtr nodePtr = nullptr;
|
||||
if (pass != ndlPassInitial)
|
||||
{
|
||||
nodePtr = (ComputationNodePtr)m_net.GetNodeFromName(name);
|
||||
// set the node eval pointer just to be safe (should already be set)
|
||||
node->SetEvalValue(nodePtr);
|
||||
|
||||
// get the node pointer for the node, should be stored in the EvalValue;
|
||||
if (pass > ndlPassInitial)
|
||||
{
|
||||
nodePtr = (ComputationNodePtr)node->GetEvalValue();
|
||||
if (nodePtr == nullptr)
|
||||
{
|
||||
nodePtr = (ComputationNodePtr)m_net.GetNodeFromName(name);
|
||||
node->SetEvalValue(nodePtr);
|
||||
}
|
||||
}
|
||||
|
||||
if (InputValue<ElemType>::TypeName() == cnNodeType)
|
||||
|
@ -65,8 +70,10 @@ public:
|
|||
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t rows = parameter[0]->GetScalar();
|
||||
size_t cols = parameter.size() > 1? parameter[1]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t rows = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t cols = params.size() > 1 ? ((NDLNode<ElemType>*)params[1])->GetScalar() : 1;
|
||||
|
||||
// first look for this node already existing in the network
|
||||
if (m_net.NodeNameExist(name))
|
||||
|
@ -80,10 +87,12 @@ public:
|
|||
if (parameter.size() < 1 || parameter.size() > 2)
|
||||
Error("%ws should have 1 or 2 parameters[rows, [cols=1]].", cnNodeType);
|
||||
|
||||
if (pass == ndlPassInitial);
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t rows = parameter[0]->GetScalar();
|
||||
size_t cols = parameter.size() > 1? parameter[1]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t rows = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t cols = params.size() > 1 ? ((NDLNode<ElemType>*)params[1])->GetScalar() : 1;
|
||||
|
||||
// first look for this node already existing in the network
|
||||
if (m_net.NodeNameExist(name))
|
||||
|
@ -99,10 +108,12 @@ public:
|
|||
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t imageWidth = parameter[0]->GetScalar();
|
||||
size_t imageHeight = parameter[1]->GetScalar();
|
||||
size_t imageChannels = parameter[2]->GetScalar();
|
||||
size_t numImages = parameter.size() > 3? parameter[3]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t imageWidth = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t imageHeight = ((NDLNode<ElemType>*)params[1])->GetScalar();
|
||||
size_t imageChannels = ((NDLNode<ElemType>*)params[2])->GetScalar();
|
||||
size_t numImages = parameter.size() > 3 ? ((NDLNode<ElemType>*)params[3])->GetScalar() : 1;
|
||||
|
||||
nodePtr = m_net.CreateInputNode(name, imageWidth, imageHeight, imageChannels, numImages);
|
||||
}
|
||||
|
@ -114,8 +125,10 @@ public:
|
|||
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t rows = parameter[0]->GetScalar();
|
||||
size_t cols = parameter.size() > 1? parameter[1]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t rows = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t cols = params.size() > 1 ? ((NDLNode<ElemType>*)params[1])->GetScalar() : 1;
|
||||
|
||||
bool needGradient = node->GetOptionalParameter("needGradient", "true");
|
||||
|
||||
|
@ -160,8 +173,10 @@ public:
|
|||
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t rows = parameter[0]->GetScalar();
|
||||
size_t cols = parameter.size() > 1? parameter[1]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t rows = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t cols = params.size() > 1 ? ((NDLNode<ElemType>*)params[1])->GetScalar() : 1;
|
||||
|
||||
bool needGradient = node->GetOptionalParameter("needGradient", "true");
|
||||
|
||||
|
@ -227,8 +242,11 @@ public:
|
|||
nodeParamStart = parameter.size() > 2?2:1;
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t start_index = parameter[0]->GetScalar();
|
||||
size_t num_rows = parameter[1]->GetScalar();
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t start_index = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
size_t num_rows = ((NDLNode<ElemType>*)params[1])->GetScalar();
|
||||
|
||||
bool needGradient = node->GetOptionalParameter("needGradient", "false");
|
||||
nodePtr = m_net.RowSlice(NULL, start_index, num_rows, name);
|
||||
nodePtr->NeedGradient() = needGradient;
|
||||
|
@ -244,9 +262,12 @@ public:
|
|||
|
||||
if (pass == ndlPassInitial)
|
||||
{
|
||||
size_t rows = parameter[0]->GetScalar();
|
||||
// if we have three parameters the second is columns
|
||||
size_t cols = parameter.size() > 2? parameter[1]->GetScalar() : 1;
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, 0, parameter.size(), pass);
|
||||
size_t rows = ((NDLNode<ElemType>*)params[0])->GetScalar();
|
||||
// if we have three parameters the second is columns
|
||||
size_t cols = parameter.size() > 2 ? ((NDLNode<ElemType>*)params[1])->GetScalar() : 1;
|
||||
|
||||
bool needGradient = node->GetOptionalParameter("needGradient", "false");
|
||||
float defaultHiddenActivity = node->GetOptionalParameter("defaultHiddenActivity", "0.1");
|
||||
nodePtr = m_net.Delay(NULL, defaultHiddenActivity, rows, cols, name);
|
||||
|
@ -269,13 +290,16 @@ public:
|
|||
{
|
||||
int id = 2; // skip weightNode and inputValueNode
|
||||
|
||||
size_t kernelWidth = parameter[id++]->GetScalar();
|
||||
size_t kernelHeight = parameter[id++]->GetScalar();
|
||||
size_t outputChannels = parameter[id++]->GetScalar();
|
||||
size_t horizontalSubsample = parameter[id++]->GetScalar();
|
||||
size_t verticalSubsample = parameter[id++]->GetScalar();
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, id, parameter.size()-id, pass);
|
||||
id = 0; // reset counter because the params array starts at zero
|
||||
size_t kernelWidth = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t kernelHeight = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t outputChannels = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t horizontalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t verticalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
|
||||
assert (id == 7);
|
||||
assert (id == 5);
|
||||
|
||||
//optional
|
||||
bool zeroPadding = node->GetOptionalParameter("zeroPadding", "false");
|
||||
|
@ -299,12 +323,15 @@ public:
|
|||
{
|
||||
int id = 1; // skip inputValueNode
|
||||
|
||||
size_t windowWidth = parameter[id++]->GetScalar();
|
||||
size_t windowHeight = parameter[id++]->GetScalar();
|
||||
size_t horizontalSubsample = parameter[id++]->GetScalar();
|
||||
size_t verticalSubsample = parameter[id++]->GetScalar();
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, id, parameter.size() - id, pass);
|
||||
id = 0; // reset counter because the params array starts at zero
|
||||
size_t windowWidth = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t windowHeight = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t horizontalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t verticalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
|
||||
assert (id == 5);
|
||||
assert (id == 4);
|
||||
|
||||
nodePtr = m_net.MaxPooling(NULL, /*inputWidth,inputHeight, channels,*/windowWidth, windowHeight,
|
||||
horizontalSubsample, verticalSubsample, name);
|
||||
|
@ -313,7 +340,7 @@ public:
|
|||
else if (cnNodeType == AveragePoolingNode<ElemType>::TypeName())
|
||||
{
|
||||
if (parameter.size() != 5)
|
||||
Error("%ws should have 8 parameters[inputValueNodeName, windowWidth, windowHeight, horizontalSubsample, verticalSubsample].", cnNodeType);
|
||||
Error("%ws should have 5 parameters[inputValueNodeName, windowWidth, windowHeight, horizontalSubsample, verticalSubsample].", cnNodeType);
|
||||
|
||||
// setup the parameter position of children so we can hook them up later
|
||||
nodeParamCount = 1;
|
||||
|
@ -323,15 +350,15 @@ public:
|
|||
{
|
||||
int id = 1; // skip inputValueNode
|
||||
|
||||
//size_t inputWidth = parameter[id++]->GetScalar();
|
||||
//size_t inputHeight = parameter[id++]->GetScalar();
|
||||
//size_t channels = parameter[id++]->GetScalar();
|
||||
size_t windowWidth = parameter[id++]->GetScalar();
|
||||
size_t windowHeight = parameter[id++]->GetScalar();
|
||||
size_t horizontalSubsample = parameter[id++]->GetScalar();
|
||||
size_t verticalSubsample = parameter[id++]->GetScalar();
|
||||
|
||||
assert (id == 5);
|
||||
// evaluate only scalar parameters
|
||||
vector<void*> params = EvaluateParameters(node, baseName, id, parameter.size() - id, pass);
|
||||
id = 0; // reset counter because the params array starts at zero
|
||||
size_t windowWidth = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t windowHeight = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t horizontalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
size_t verticalSubsample = ((NDLNode<ElemType>*)params[id++])->GetScalar();
|
||||
|
||||
assert (id == 4);
|
||||
|
||||
nodePtr = m_net.AveragePooling(NULL, /*inputWidth,inputHeight, channels,*/windowWidth, windowHeight,
|
||||
horizontalSubsample, verticalSubsample, name);
|
||||
|
@ -387,6 +414,99 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LATER
|
||||
// EvaluateDotName - Evaluate a dot name and resolve to target node
|
||||
// node - NDLNode of the script
|
||||
// nodeParam - NDLNode parameter we are evaluating
|
||||
// baseName - name of the base node
|
||||
// pass - which pass through the NDL nodes
|
||||
// returns: the node that is the evaluated parameter
|
||||
virtual NDLNode<ElemType>* EvaluateDotName(NDLNode<ElemType>* node, NDLNode<ElemType>* nodeParam, const std::wstring& baseNameP, const NDLPass pass)
|
||||
|
||||
{
|
||||
if (pass > ndlPassInitial && evaluateNode)
|
||||
{
|
||||
std::string name = nodeParam->GetName();
|
||||
std::wstring wname = msra::strfun::utf16(name);
|
||||
if (nodeParam->GetType() == ndlTypeDotParameter)
|
||||
{
|
||||
// When we see a variable of the form "A.B" in a macro, we need to resolve it to an actual node, by first constructing it's
|
||||
// fully-qualified name. There are 2 possibilities:
|
||||
// 1) "A" was defined locally within the macro. In this case, we must find the fully-qualified name of the node that this macro
|
||||
// call is being assigned to (eg, "C" in the example "C=Macro(X)"), and concatenate it's name with "A.B" (eg, "C.A.B").
|
||||
// 2) "A" was passed in as a parameter to a macro. In this case, we must find the fully-qualified name of the node that
|
||||
// was passed in as "A", and replace the "A" and "A.B" with this name.
|
||||
|
||||
// Consider the following example:
|
||||
// NdlBLob=[
|
||||
// P=MacroCall1(...)
|
||||
// C=MacroCall2(P)
|
||||
// ]
|
||||
// # MacroDefinition
|
||||
// MacroCall2(X)
|
||||
// {
|
||||
// A=MacroCall3(...)
|
||||
// D=Times(A.B,X.B)}
|
||||
// }
|
||||
//
|
||||
|
||||
// In this example, in the call D=Times(A.B,X.B), we need to resolve A.B and X.B appropriately.
|
||||
// Specifically, "A.B" must be resolved to the fully qualified name "C.A.B", whereas "X.B" must be resolved to the fully qualified name "P.B".
|
||||
// We then use this fully-qualified name to look up this node in the model (using "m_net.GetNodeFromName").
|
||||
|
||||
std::size_t firstDotPos = name.find_first_of(".");
|
||||
if (firstDotPos == std::string::npos)
|
||||
{
|
||||
Error("Logic Error: nodeParam of type \"ndlTypeDotParameter\" doesn't have a dot in its name: %s", name.c_str());
|
||||
}
|
||||
|
||||
std::string nameBeforeDot = name.substr(0, firstDotPos);
|
||||
std::string nameAfterDot = name.substr(firstDotPos + 1, name.size() - (firstDotPos + 1));
|
||||
|
||||
// look up if "nameBeforeDot" was a parameter to the macro.
|
||||
NDLNode<ElemType>* resolvedParam = nodeParam->GetParentScript()->FindSymbol(nameBeforeDot);
|
||||
if (resolvedParam != nullptr && resolvedParam->GetType() == ndlTypeMacroCall)
|
||||
{
|
||||
// if "nameBeforeDot" was a parameter to the macro, builds it's fully qualified name by
|
||||
// replacing "nameBeforeDot" with the fully qualified name of the node passed in as the parameter.
|
||||
NDLScript<ElemType>* parentScript = resolvedParam->GetParentScript();
|
||||
baseName = parentScript->GetBaseName();
|
||||
std::wstring resolvedParamName = msra::strfun::utf16(resolvedParam->GetName());
|
||||
wname = baseName.empty() ?
|
||||
resolvedParamName + L"." + msra::strfun::utf16(nameAfterDot) :
|
||||
baseName + L"." + resolvedParamName + L"." + msra::strfun::utf16(nameAfterDot);
|
||||
}
|
||||
else if (!baseName.empty())
|
||||
{
|
||||
// else, "nameBeforeDot" wasn't a parameter to the macro, so treat it as a local variable.
|
||||
wname = baseName + L"." + wname;
|
||||
}
|
||||
}
|
||||
else if (!baseName.empty())
|
||||
{
|
||||
wname = baseName + L"." + wname;
|
||||
}
|
||||
|
||||
// fully qualified names can be looked up in the model
|
||||
if (m_net.NodeNameExist(wname))
|
||||
{
|
||||
void* np = (void*)m_net.GetNodeFromName(wname);
|
||||
nodeParam->SetEvalValue(np);
|
||||
}
|
||||
// NOTE: there is a bug here, we allow an abbreviated node reference (i.e. L1.BFF) based on return values in NDL
|
||||
// when the actual full node reference that the computational network uses would be L1.BFF.FF.P, so that is what CN sees
|
||||
// can we do the normal find symbol here to allow abbreviated node references?
|
||||
|
||||
// if we still didn't get a value, throw an error
|
||||
if (nodeParam->GetEvalValue() == nullptr)
|
||||
{
|
||||
Error("Logic Error: Dot name could not be resolved '%s': should have a node named '%ls' in computational network\n", nodeParam->GetName().c_str(), name.c_str());
|
||||
}
|
||||
}
|
||||
return nodeParam;
|
||||
}
|
||||
#endif
|
||||
|
||||
// EvaluateParameter - Evaluate a parameter of a call
|
||||
// node - NDLNode of the script
|
||||
// nodeParam - NDLNode parameter we are evaluating
|
||||
|
@ -410,100 +530,46 @@ public:
|
|||
{
|
||||
// if the node is a parameter then look it up in the symbol table
|
||||
case ndlTypeUndetermined: // an undetermined parameter needs to be looked up again in the symbol table
|
||||
case ndlTypeParameter:
|
||||
nodeParam = script->FindSymbol(nodeParam->GetName());
|
||||
case ndlTypeParameter:
|
||||
{
|
||||
// lookup the parameter
|
||||
NDLNode<ElemType>* nodeResolve = script->FindSymbol(nodeParam->GetName());
|
||||
|
||||
// if the parmeter/undetermined results in a dotParameter we need to continue evaluation with a different base name
|
||||
if (nodeParam->GetType() == ndlTypeDotParameter)
|
||||
{
|
||||
baseName = nodeParam->GetParentScript()->GetBaseName();
|
||||
}
|
||||
// if we have resolved the name break; otherwise continue evaluation
|
||||
if (!(pass == ndlPassResolve && nodeParam->GetEvalValue() == nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ndlTypeDotParameter:
|
||||
if (pass > ndlPassInitial && evaluateNode)
|
||||
{
|
||||
std::string name = nodeParam->GetName();
|
||||
std::wstring wname = msra::strfun::utf16(name);
|
||||
if(nodeParam->GetType() == ndlTypeDotParameter)
|
||||
{
|
||||
// When we see a variable of the form "A.B" in a macro, we need to resolve it to an actual node, by first constructing it's
|
||||
// fully-qualified name. There are 2 possibilities:
|
||||
// 1) "A" was defined locally within the macro. In this case, we must find the fully-qualified name of the node that this macro
|
||||
// call is being assigned to (eg, "C" in the example "C=Macro(X)"), and concatenate it's name with "A.B" (eg, "C.A.B").
|
||||
// 2) "A" was passed in as a parameter to a macro. In this case, we must find the fully-qualified name of the node that
|
||||
// was passed in as "A", and replace the "A" and "A.B" with this name.
|
||||
// if we have resolved the name, no need to continue evaluation
|
||||
if (!(pass == ndlPassResolve && nodeResolve && nodeParam->GetEvalValue() == nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (pass > ndlPassInitial && evaluateNode && nodeResolve)
|
||||
{
|
||||
std::string name = nodeResolve->GetName();
|
||||
// we need to start from the parent script, because that is the namespace of the parameter being passed in
|
||||
NDLScript<ElemType>* parentScript = nodeResolve->GetParentScript();
|
||||
nodeResolve = parentScript->FindSymbol(name, true);
|
||||
|
||||
// Consider the following example:
|
||||
// NdlBLob=[
|
||||
// P=MacroCall1(...)
|
||||
// C=MacroCall2(P)
|
||||
// ]
|
||||
// # MacroDefinition
|
||||
// MacroCall2(X)
|
||||
// {
|
||||
// A=MacroCall3(...)
|
||||
// D=Times(A.B,X.B)}
|
||||
// }
|
||||
//
|
||||
|
||||
// In this example, in the call D=Times(A.B,X.B), we need to resolve A.B and X.B appropriately.
|
||||
// Specifically, "A.B" must be resolved to the fully qualified name "C.A.B", whereas "X.B" must be resolved to the fully qualified name "P.B".
|
||||
// We then use this fully-qualified name to look up this node in the model (using "m_net.GetNodeFromName").
|
||||
|
||||
std::size_t firstDotPos = name.find_first_of(".");
|
||||
if(firstDotPos == std::string::npos)
|
||||
{
|
||||
Error("Logic Error: nodeParam of type \"ndlTypeDotParameter\" doesn't have a dot in its name: %s", name.c_str());
|
||||
}
|
||||
|
||||
std::string nameBeforeDot = name.substr(0, firstDotPos);
|
||||
std::string nameAfterDot = name.substr(firstDotPos + 1, name.size() - (firstDotPos + 1));
|
||||
|
||||
// look up if "nameBeforeDot" was a parameter to the macro.
|
||||
NDLNode<ElemType>* resolvedParam = nodeParam->GetParentScript()->FindSymbol(nameBeforeDot);
|
||||
if (resolvedParam != nullptr && resolvedParam->GetType() == ndlTypeMacroCall)
|
||||
{
|
||||
// if "nameBeforeDot" was a parameter to the macro, builds it's fully qualified name by
|
||||
// replacing "nameBeforeDot" with the fully qualified name of the node passed in as the parameter.
|
||||
NDLScript<ElemType>* parentScript = resolvedParam->GetParentScript();
|
||||
baseName = parentScript->GetBaseName();
|
||||
std::wstring resolvedParamName = msra::strfun::utf16(resolvedParam->GetName());
|
||||
wname = baseName.empty() ?
|
||||
resolvedParamName + L"." + msra::strfun::utf16(nameAfterDot) :
|
||||
baseName + L"." + resolvedParamName + L"." + msra::strfun::utf16(nameAfterDot);
|
||||
}
|
||||
else if(!baseName.empty())
|
||||
{
|
||||
// else, "nameBeforeDot" wasn't a parameter to the macro, so treat it as a local variable.
|
||||
wname = baseName + L"." + wname;
|
||||
}
|
||||
}
|
||||
else if(!baseName.empty())
|
||||
// if we still didn't get a value
|
||||
if (nodeResolve == nullptr || nodeResolve->GetEvalValue() == nullptr)
|
||||
{
|
||||
wname = baseName + L"." + wname;
|
||||
// check for the fully quantified name in the computation network
|
||||
// this is needed for MEL processing, since CN nodes names can be used as parameters in MEL
|
||||
std::wstring wname = msra::strfun::utf16(name);
|
||||
if (m_net.NodeNameExist(wname))
|
||||
{
|
||||
void* np = (void*)m_net.GetNodeFromName(wname);
|
||||
// if we don't have a resolve node, it's because the name didn't exist in NDL
|
||||
if (!nodeResolve)
|
||||
nodeResolve = nodeParam;
|
||||
nodeResolve->SetEvalValue(np);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error("Parameter name could not be resolved '%s'\n", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// fully qualified names can be looked up in the model
|
||||
if (m_net.NodeNameExist(wname))
|
||||
{
|
||||
void* np = (void*)m_net.GetNodeFromName(wname);
|
||||
nodeParam->SetEvalValue(np);
|
||||
}
|
||||
// NOTE: there is a bug here, we allow an abbreviated node reference (i.e. L1.BFF) based on return values in NDL
|
||||
// when the actual full node reference that the computational network uses would be L1.BFF.FF.P, so that is what CN sees
|
||||
// can we do the normal find symbol here to allow abbreviated node references?
|
||||
|
||||
// if we still didn't get a value, throw an error
|
||||
if (nodeParam->GetEvalValue() == nullptr)
|
||||
{
|
||||
Error("Logic Error: Dot name could not be resolved '%s': should have a node named '%ls' in computational network\n", nodeParam->GetName().c_str(), name.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
nodeParam = nodeResolve;
|
||||
break;
|
||||
}
|
||||
case ndlTypeFunction:
|
||||
if (evaluateNode)
|
||||
Evaluate(nodeParam, baseName, pass);
|
||||
|
@ -565,6 +631,10 @@ public:
|
|||
assert(np != nullptr);
|
||||
inputs.push_back((void*)np);
|
||||
}
|
||||
else if (pass == ndlPassInitial) // for initial pass we are only interested in resolved nodes (to get constant values)
|
||||
{
|
||||
inputs.push_back((void*)nodeResult);
|
||||
}
|
||||
// NOTE: in final pass inputs are always NULL
|
||||
}
|
||||
|
||||
|
@ -580,7 +650,7 @@ public:
|
|||
std::string empty;
|
||||
|
||||
// loop through all the optional parameters processing them as necessary
|
||||
for each (NDLNode<ElemType>* param in params)
|
||||
for (NDLNode<ElemType>* param : params)
|
||||
{
|
||||
// make sure it's a "tag" optional parameter, that's all we process currently
|
||||
if (_strcmpi(param->GetName().c_str(), "tag"))
|
||||
|
@ -616,7 +686,7 @@ public:
|
|||
// compNode - computation node to add
|
||||
void SetOutputNode(std::vector<ComputationNode<ElemType>*>& nodeGroup, ComputationNode<ElemType>* compNode)
|
||||
{
|
||||
for each (ComputationNodePtr node in nodeGroup)
|
||||
for (ComputationNodePtr node : nodeGroup)
|
||||
{
|
||||
if (node == compNode)
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,11 @@ m1=[
|
|||
HDim=256
|
||||
LDim=10
|
||||
|
||||
macro(test)
|
||||
{
|
||||
local=test
|
||||
}
|
||||
|
||||
features=Input(SDim, tag=feature)
|
||||
labels=Input(LDim, tag=label)
|
||||
|
||||
|
@ -26,7 +31,7 @@ m1=[
|
|||
|
||||
SetDefaultModel(m1)
|
||||
Dump(m1, "c:\temp\dump1.txt", includeData = true)
|
||||
LoadNDLSnippet(m2, "NdlScript.txt")
|
||||
LoadNDLSnippet(m2, "C:\dev\CNTK\MachineLearning\cn\NdlScript.txt")
|
||||
Copy(L3.RL, L4.RL)
|
||||
#add a layer to a 3-layer network, copy all nodes in layer 3 to layer 4
|
||||
# all strings that start with L3* will be copied to L4* along with internal connections
|
||||
|
|
Загрузка…
Ссылка в новой задаче