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:
adame 2014-09-17 13:49:18 -07:00
Родитель 52eabc6e88
Коммит 3b21b530f3
18 изменённых файлов: 508 добавлений и 271 удалений

Просмотреть файл

@ -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