// change the node associated with nodeName to newNode; used in the KL-reg based adaptation to reduce feature copy // need to update all the mappings as well childrens void ComputationNetwork::ChangeNode(wstring nodeName, ComputationNodeBasePtr newNode) { InvalidateCompiledNetwork(); ComputationNodeBasePtr oldNode = GetNodeFromName(nodeName); if (oldNode->OperationName() != newNode->OperationName()) InvalidArgument("newNode must have the same type as the old node."); // change children for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); nodeIter++) { ComputationNodeBasePtr node = nodeIter->second; for (int i = 0; i < node->GetNumInputs(); i++) if (node->GetInputs()[i] == oldNode) node->SetInput(i, newNode); } // change name map m_nameToNodeMap[nodeName] = newNode; for (int i = 0; i < oldNode->GetNumInputs(); i++) newNode->SetInput(i, oldNode->GetInputs()[i]); // change other maps for (auto groupIter : GetAllNodeGroups()) { auto& group = *groupIter; for (int i = 0; i < group.size(); i++) if (group[i] == oldNode) group[i] = newNode; } }
// only copy a complete independent tree // when node name exists void ComputationNetwork::CopySubTree(const ComputationNetwork& fromNet, const std::wstring fromName, std::wstring toNamePrefix, const CopyNodeFlags flags) { InvalidateCompiledNetwork(); if (!(flags & CopyNodeFlags::copyNodeValue)) LogicError("CopySubTree: you cannot copy a tree without copying the node values."); ComputationNodeBasePtr fromRoot = fromNet.GetNodeFromName(fromName); for (const auto& fromNode : GetEvalOrder(fromRoot)) { wstring fromNodeName = fromNode->NodeName(); wstring toNodeName = toNamePrefix + fromNodeName; ComputationNodeBasePtr toNode = CopyNode(fromNet, fromNodeName, toNodeName, CopyNodeFlags::copyNodeValue); if (flags & CopyNodeFlags::copyNodeChildren) { // copy the children structure but use the new nodes generated for (int i = 0; i < fromNode->GetNumInputs(); i++) toNode->SetInput(i, GetNodeFromName(toNamePrefix + fromNode->GetInputs()[i]->NodeName())); } } }
// We only remove the node, not delete it. void ComputationNetwork::RemoveFeatureNode(ComputationNodeBasePtr featureNode) { InvalidateCompiledNetwork(); wstring nodeName = featureNode->NodeName(); if (!NodeNameExists(nodeName)) RuntimeError("RemoveFeatureNode: feature node does not exist."); // Removes links. for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); ++nodeIter) { ComputationNodeBasePtr node = nodeIter->second; for (size_t i = 0; i < node->GetNumInputs(); ++i) { ComputationNodeBasePtr child = node->GetInputs()[i]; if (child == featureNode) { node->SetInput(i, NULL); break; } } } // Removes from feature list. auto search = std::find(m_features.begin(), m_features.end(), featureNode); if (search != m_features.end()) m_features.erase(search); m_nameToNodeMap.erase(nodeName); }
void ComputationNetwork::ReplaceFinalCriterionNode(wstring oldNodeName, ComputationNodeBasePtr newNode) { InvalidateCompiledNetwork(); // Checks if the node is a criterion node. int index = -1; for (int i = 0; i < m_finalCriteria.size(); ++i) { if (m_finalCriteria[i]->NodeName() == oldNodeName) { index = i; break; } } if (index == -1) RuntimeError("ReplaceFinalCriterionNode: the node to be replaced is not a criterion node."); // Replaces children. for (int i = 0; i < newNode->GetNumInputs(); ++i) { if (m_nameToNodeMap.find(newNode->GetInputs()[i]->NodeName()) == m_nameToNodeMap.end()) RuntimeError("Child node does not exist."); newNode->SetInput(i, m_nameToNodeMap[newNode->GetInputs()[i]->NodeName()]); } // Addes it to criterion node list. m_finalCriteria[index] = newNode; m_nameToNodeMap[newNode->NodeName()] = newNode; }
// only copy a complete independent tree // when node name exists void ComputationNetwork::CopySubTree(const ComputationNetwork& fromNet, const std::wstring fromName, std::wstring toNamePrefix, const CopyNodeFlags flags) { InvalidateCompiledNetwork(); if (!(flags & CopyNodeFlags::copyNodeValue)) LogicError("CopySubTree: you cannot copy a tree without copying the node values."); ComputationNodeBasePtr fromRoot = fromNet.GetNodeFromName(fromName); if (!fromNet.EvalOrderExists(fromRoot)) const_cast<ComputationNetwork&>(fromNet).FormEvalOrder(fromRoot); for (const auto& fromNode : fromNet.GetEvalOrder(fromRoot)) // BUGBUG: This probably will fail because the precomputed eval orders are invalid at this point. { wstring fromNodeName = fromNode->NodeName(); wstring toNodeName = toNamePrefix + fromNodeName; ComputationNodeBasePtr toNode = CopyNode(fromNet, fromNodeName, toNodeName, CopyNodeFlags::copyNodeValue); if (flags & CopyNodeFlags::copyNodeInputLinks) { // copy the children structure but use the new nodes generated for (int i = 0; i < fromNode->GetNumInputs(); i++) toNode->SetInput(i, GetNodeFromName(toNamePrefix + fromNode->GetInputs()[i]->NodeName())); } } }
// add a new criterion node and at the same time orphan the previous one (it won't be removed) // The newNode can have the same name and come with pre-connected inputs, which will be used to connect to existing nodes of the same name. // BUGBUG: Can this operate on both new and existing nodes? void ComputationNetwork::ReplaceFinalCriterionNode(wstring oldNodeName, ComputationNodeBasePtr newNode) { InvalidateCompiledNetwork(); // remove old criterion node // BUGBUG: The old node is not removed from the network. Seems strangely inconsistent. bool wasThere = RemoveFromNodeGroup(L"criterion", GetNodeFromName(oldNodeName)); if (!wasThere) RuntimeError("ReplaceFinalCriterionNode: The node to be replaced is not a criterion node."); // replace children // This looks for nodes in the network that have the same name as its current inputs, and then relinks its inputs to those. // I.e. this allows to move a node from network to another and reconnect by the names if its inputs. for (int i = 0; i < newNode->GetNumInputs(); ++i) { if (m_nameToNodeMap.find(newNode->GetInputs()[i]->NodeName()) == m_nameToNodeMap.end()) RuntimeError("Child node %ls is not part of the network.", newNode->GetInputs()[i]->NodeName().c_str()); newNode->SetInput(i, m_nameToNodeMap[newNode->GetInputs()[i]->NodeName()]); } // add it to the network AddNodeToNetIfNotYet(newNode); // add new node to criterion node group AddToNodeGroup(L"criterion", newNode); }
// replace a named node by newNode of the same type under the same name, including moving over all network links // This is used in // 1. Update nodes to quantized versions. // 2. The KL-reg based adaptation to reduce feature copy (deprecated) // need to update all the mappings as well childrens. void ComputationNetwork::ReplaceNode(wstring nodeName, ComputationNodeBasePtr newNode) { ComputationNodeBasePtr oldNode = GetNodeFromName(nodeName); if (newNode->NodeName() != nodeName) // TODO: This was not tested for earlier; I hope no code depends on this. InvalidArgument("ChangeNode: newNode must have the same name as the old node."); InvalidateCompiledNetwork(); // change all nodes that have old node as input to point to the new node instead ChangeNodeInputs(oldNode, newNode); // change all inputs of this new node to share the old one's inputs for (int i = 0; i < oldNode->GetNumInputs(); i++) { newNode->SetInput(i, oldNode->GetInputs()[i]); // TODO: use AttachInput()? //oldNode->SetInput(i, nullptr); // BUGBUG: old node should no longer point into the network } // replace the node in the network RemoveNodeFromNet(oldNode); AddNodeToNet(newNode); // also update node groups for (auto groupIter : GetAllNodeGroups()) { auto& group = *groupIter; for (int i = 0; i < group.size(); i++) if (group[i] == oldNode) group[i] = newNode; } }
// change all nodes that have fromNode as input to have toNode as input instead void ComputationNetwork::ChangeNodeInputs(ComputationNodeBasePtr fromNode, ComputationNodeBasePtr toNode) { for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); nodeIter++) { ComputationNodeBasePtr node = nodeIter->second; for (int i = 0; i < node->GetNumInputs(); i++) if (node->GetInputs()[i] == fromNode) node->SetInput(i, toNode); } }
// replace the old node with the current node, assuming the old node is a leaf node // need to update those nodes who use oldNode as their child // TODO: Can this be called with a node that's already part of the network? This is currently allowed, but should it? // BUGBUG: Seems ReplaceNode() also updates node groups. Why doesn't this function? // BUGBUG: What if newNode is the one referenced by oldNodeName? // BUGBUG: Or what if an unrelated node of the same name exists? void ComputationNetwork::ReplaceLeafNode(wstring oldNodeName, ComputationNodeBasePtr newNode) { InvalidateCompiledNetwork(); ComputationNodeBasePtr oldNode = GetNodeFromName(oldNodeName); // relink the input of those nodes whose child is oldNode to point to the new one instead for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); nodeIter++) { ComputationNodeBasePtr node = nodeIter->second; for (int i = 0; i < node->GetNumInputs(); i++) if (node->GetInputs()[i] == oldNode) node->SetInput(i, newNode); } // add the new, remove the old AddNodeToNetIfNotYet(newNode); DeleteNode(oldNodeName); // TODO: can this just be RemoveNodeFromNet()? }
// replace the old node with the current node, assuming the old node is a leaf node // need to update those nodes who use oldNode as their child void ComputationNetwork::ReplaceLeafNode(wstring oldNodeName, ComputationNodeBasePtr newNode) { InvalidateCompiledNetwork(); ComputationNodeBasePtr oldNode = GetNodeFromName(oldNodeName); // change the input of those nodes whose child is oldNode for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); nodeIter++) { ComputationNodeBasePtr node = nodeIter->second; for (int i = 0; i < node->GetNumInputs(); i++) if (node->GetInputs()[i] == oldNode) node->SetInput(i, newNode); } m_nameToNodeMap[newNode->GetName()] = newNode; // now the old node becomes a orphan node , remove it DeleteNode(oldNodeName); // RemoveOrphanNode(oldNode); }
void ComputationNetwork::DeleteNode(const std::wstring& nodeName) { InvalidateCompiledNetwork(); ComputationNodeBasePtr nodeToDelete = GetNodeFromName(nodeName); // first delete links, if this node is involved, the whole connection will be removed for (auto nodeIter = m_nameToNodeMap.begin(); nodeIter != m_nameToNodeMap.end(); nodeIter++) { ComputationNodeBasePtr node = nodeIter->second; for (size_t i = 0; i < node->GetNumInputs(); i++) { ComputationNodeBasePtr child = node->GetInputs()[i]; // nodeToDelete is a child if (child == nodeToDelete) { // this used to call DetatchInputs(), but it's better for MEL to retain other inputs node->SetInput(i, nullptr); break; } } } // nodeToDelete is a parent nodeToDelete->DetachInputs(); // deref all its inputs; if we don't do that, we might end up with a mem leak due to a circular reference // unlink from all node-group sets for (auto groupIter : GetAllNodeGroups()) { auto search = std::find(groupIter->begin(), groupIter->end(), nodeToDelete); if (search != groupIter->end()) groupIter->erase(search); } // Note: the necessary update of m_allSEQNodes is hanlded by the InvalidateCompiledNetwork() call above // delete the node itself m_nameToNodeMap.erase(nodeName); // this will deref the node and possibly deallocate it }