renamed RowSlice() to Slice() and changed parameter from 'num' to 'end' with back compat with old models and NDL/BS, but otherwise no new functionality yet

This commit is contained in:
Frank Seide 2016-03-23 14:01:59 -07:00
Родитель 6d616b7d19
Коммит a6408cc8cd
7 изменённых файлов: 39 добавлений и 44 удалений

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

@ -185,7 +185,7 @@ void NDLNodeEvaluatorImpl<ElemType>::Evaluate(NDLNode<ElemType>* node, const wst
nodePtr->Value().SetValue(val);
}
}
else if (cnNodeType == OperationNameOf(RowSliceNode))
else if (cnNodeType == L"RowSlice") // Note: This now maps onto SliceNode which specifies the end differently.
{
if (parameter.size() != 3)
RuntimeError("RowSlice should have three parameters. Usage: RowSlice(startRowIndex, numRows, origNodeName.");

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

@ -196,7 +196,6 @@ bool CheckFunction(std::string& p_nodeType, bool* allowUndeterminedVariable)
else if (EqualInsensitive(nodeType, OperationNameOf(RectifiedLinearNode), L"ReLU")) ret = true;
else if (EqualInsensitive(nodeType, OperationNameOf(ReshapeNode))) ret = true;
else if (EqualInsensitive(nodeType, OperationNameOf(RowRepeatNode))) ret = true;
else if (EqualInsensitive(nodeType, OperationNameOf(RowSliceNode))) ret = true;
else if (EqualInsensitive(nodeType, OperationNameOf(RowStackNode))) ret = true;
#ifdef COMING_SOON
else if (EqualInsensitive(nodeType, OperationNameOf(SequenceDecoderNode), L"SEWithSM")) ret = true;
@ -219,6 +218,7 @@ bool CheckFunction(std::string& p_nodeType, bool* allowUndeterminedVariable)
else if (EqualInsensitive(nodeType, L"ImageInput", L"Image")) ret = true;
else if (EqualInsensitive(nodeType, L"ImageParameter")) ret = true;
else if (EqualInsensitive(nodeType, L"RowElementTimes")) ret = true;
else if (EqualInsensitive(nodeType, L"RowSlice")) ret = true;
else if (EqualInsensitive(nodeType, L"Scale")) ret = true;
else if (EqualInsensitive(nodeType, L"SparseImageInput", L"SparseImage")) ret = true;
else if (EqualInsensitive(nodeType, L"Transpose")) ret = true;

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

@ -41,13 +41,14 @@ Constant(val, rows = 1, cols = 1, tag='') = Parameter(rows, cols, learningRateMu
PastValue(dims, input, timeStep = 1, defaultHiddenActivation = 0.1, tag='') = new ComputationNode [ operation = 'PastValue' ; inputs = input ; shape = new TensorShape [ /*dims*/ ] /*plus the function args*/ ]
FutureValue(dims, input, timeStep = 1, defaultHiddenActivation = 0.1, tag='') = new ComputationNode [ operation = 'FutureValue' ; inputs = input ; shape = new TensorShape [ /*dims*/ ] /*plus the function args*/ ]
Shift(input, fromOffset, boundaryValue, boundaryMode=-1/*context*/, dim=-1, tag='') = new ComputationNode [ operation = 'Shift' ; inputs = (input : boundaryValue) /*plus the function args*/ ]
RowSlice(startIndex, numRows, input, tag='') = new ComputationNode [ operation = 'RowSlice' ; inputs = input /*plus the function args*/ ]
RowSlice(beginIndex, numRows, input, tag='') = new ComputationNode [ operation = 'Slice' ; endIndex = beginIndex + numRows; axis = 1/*row*/; inputs = input /*plus the function args*/ ]
RowRepeat(input, numRepeats, tag='') = new ComputationNode [ operation = 'RowRepeat' ; inputs = input /*plus the function args*/ ]
RowStack(inputs, tag='') = new ComputationNode [ operation = 'RowStack' /*plus the function args*/ ]
Reshape(input, numRows, imageWidth = 0, imageHeight = 0, imageChannels = 0, tag='') = new ComputationNode [ operation = 'LegacyReshape' ; inputs = input /*plus the function args*/ ]
NewReshape(input, dims, beginDim=0, endDim=0, tag='') = new ComputationNode [ operation = 'Reshape' ; inputs = input ; shape = new TensorShape [ /*dims*/ ] /*plus the function args*/ ]
ReshapeDimension(x, dim, tensorShape) = NewReshape(x, tensorShape, beginDim=dim, endDim=dim + 1)
FlattenDimensions(x, dim, num) = NewReshape(x, 0, beginDim=dim, endDim=dim + num)
#Slice(beginIndex, endIndex, input, axis=1, tag='') = new ComputationNode [ operation = 'Slice' ; endIndex = beginIndex + numRows; inputs = input /*plus the function args*/ ]
SplitDimension(x, dim, N) = ReshapeDimension(x, dim, 0:N)
TransposeDimensions(input, dim1, dim2, tag='') = new ComputationNode [ operation = 'TransposeDimensions' ; inputs = input /*plus the function args*/ ]
Transpose(x) = TransposeDimensions(x, 1, 2)

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

@ -455,11 +455,6 @@ public:
return false;
return true;
}
// legacy helper function for RowSliceNode. Will go away.
bool IsVectorStoredAsImage() const
{
return GetRank() == 3 && m_dims[0] == 1 && m_dims[1] == 1;
}
// indexing
// Determines the offset into the underlying element array for a given multi-dimensional index.

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

@ -80,7 +80,6 @@ static shared_ptr<ComputationNode<ElemType>> CreateStandardNode(const std::wstri
else if (nodeType == OperationNameOf(RectifiedLinearNode)) return New<RectifiedLinearNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(ReshapeNode)) return New<ReshapeNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(RowRepeatNode)) return New<RowRepeatNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(RowSliceNode)) return New<RowSliceNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(RowStackNode)) return New<RowStackNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(ScatterPackedNode)) return New<ScatterPackedNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(SequenceWithSoftmaxNode)) return New<SequenceWithSoftmaxNode<ElemType>>(forward<_Types>(_Args)...);
@ -91,6 +90,7 @@ static shared_ptr<ComputationNode<ElemType>> CreateStandardNode(const std::wstri
else if (nodeType == OperationNameOf(ShiftNode)) return New<ShiftNode<ElemType>>(forward<_Types>(_Args)...);
#endif
else if (nodeType == OperationNameOf(SigmoidNode)) return New<SigmoidNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(SliceNode)) return New<SliceNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(SoftmaxNode)) return New<SoftmaxNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(SqrtNode)) return New<SqrtNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == OperationNameOf(SquareErrorNode)) return New<SquareErrorNode<ElemType>>(forward<_Types>(_Args)...);
@ -109,6 +109,7 @@ static shared_ptr<ComputationNode<ElemType>> CreateStandardNode(const std::wstri
else if (nodeType == L"PerDimMeanVarNormalizationNode") return New<PerDimMeanVarNormalizationNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == L"PerDimMeanVarDeNormalizationNode") return New<PerDimMeanVarDeNormalizationNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == L"RowElementTimes") return New<ElementTimesNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == L"RowSlice") return New<SliceNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == L"Scale") return New<ElementTimesNode<ElemType>>(forward<_Types>(_Args)...);
else if (nodeType == L"Transpose") return New<TransposeDimensionsNode<ElemType>>(forward<_Types>(_Args)...);
#if 1
@ -595,7 +596,7 @@ shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::Futur
template <class ElemType>
shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::RowSlice(const ComputationNodePtr a, const size_t start_index, const size_t num_rows, const std::wstring nodeName)
{
return net.AddNodeToNetAndAttachInputs(New<RowSliceNode<ElemType>>(net.GetDeviceId(), nodeName, start_index, num_rows), { a });
return net.AddNodeToNetAndAttachInputs(New<SliceNode<ElemType>>(net.GetDeviceId(), nodeName, (int)start_index, (int)(start_index + num_rows)), { a });
}
template <class ElemType>

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

@ -30,9 +30,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
// -----------------------------------------------------------------------
// Convolutions (incl. pooling) support two different storage formats:
// BUGBUG: These are currently hard-selected depending on circumstances, without being reflected in TensoShape.
//
// * legacy mode (CPU and GPU without cudnn): Channels are tuples of scalars
// * legacy ("HWC") mode (CPU and GPU without cudnn): Channels are tuples of scalars
//
// This follows "high performance convolutional neural networks for document processing" by Kumar Chellapilla, Sidde Puri, and Patrice Simard.
// Each sample is stored as a column-major matrix (height, width) of float[numChannels] (r00, g00, b00, r10, g10, b10, r01, g01, b01, r11, g11, b11).
@ -41,7 +40,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
// - output : [C' x W' x H' x T] or ARRAY[1..T] OF ARRAY[1..H'] OF ARRAY[1..W'] OF ARRAY[1..C']
// - filter : [C' x W" x H" x C ] or ARRAY[1..C] OF ARRAY[1..H"] OF ARRAY[1..W"] OF ARRAY[1..C']
//
// * GPU with cudnn: Channels are planes
// * cudnn ("CHW") mode (GPU only): Channels are planes
//
// - input : [W x H x C x T] or ARRAY[1..T] OF ARRAY[1..C] OF ARRAY[1..H] OF ARRAY[1..W]
// - output : [W' x H' x C' x T] or ARRAY[1..T] OF ARRAY[1..C'] OF ARRAY[1..H'] OF ARRAY[1..W']
@ -58,12 +57,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
template <class ElemType>
class ConvolutionNode : public ComputationNode<ElemType>, public NumInputs<2>
{
typedef ComputationNode<ElemType> Base;
UsingComputationNodeMembersBoilerplate;
static const std::wstring TypeName()
{
return L"Convolution";
}
typedef ComputationNode<ElemType> Base; UsingComputationNodeMembersBoilerplate;
static const std::wstring TypeName() { return L"Convolution"; }
public:
ConvolutionNode(DEVICEID_TYPE deviceId, const wstring& name)

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

@ -231,25 +231,25 @@ template class ReconcileMBLayoutNode<float>;
template class ReconcileMBLayoutNode<double>;
// -----------------------------------------------------------------------
// RowSliceNode (input)
// SliceNode (input)
// This node extracts a slice of the first tensor dimension (row).
// TODO: Extend to specifying the axis. Time slicing would have to be done in BrainScript using Gather.
// TODO: Implement parametrizable m_axis. Time slicing would have to be done in BrainScript using Gather.
// -----------------------------------------------------------------------
template <class ElemType>
class RowSliceNode : public ComputationNode<ElemType>, public NumInputs<1>
class SliceNode : public ComputationNode<ElemType>, public NumInputs<1>
{
typedef ComputationNode<ElemType> Base; UsingComputationNodeMembersBoilerplate;
static const std::wstring TypeName() { return L"RowSlice"; }
static const std::wstring TypeName() { return L"Slice"; }
public:
RowSliceNode(DEVICEID_TYPE deviceId, const wstring& name, size_t startIndex = 0, size_t numRows = 0)
: Base(deviceId, name), m_startIndex(startIndex), m_sliceHeight(numRows)
SliceNode(DEVICEID_TYPE deviceId, const wstring& name, int beginIndex = 0, int endIndex = 0)
: Base(deviceId, name), m_beginIndex(beginIndex), m_endIndex(endIndex), m_axis(1)
{
}
RowSliceNode(const ScriptableObjects::IConfigRecordPtr configp)
: RowSliceNode(configp->Get(L"deviceId"), L"<placeholder>", configp->Get(L"startIndex"), configp->Get(L"numRows"))
SliceNode(const ScriptableObjects::IConfigRecordPtr configp)
: SliceNode(configp->Get(L"deviceId"), L"<placeholder>", configp->Get(L"beginIndex"), configp->Get(L"endIndex"))
{
AttachInputsFromConfig(configp, this->GetExpectedNumInputs());
}
@ -257,27 +257,29 @@ public:
virtual void CopyTo(ComputationNodeBasePtr nodeP, const std::wstring& newName, const CopyNodeFlags flags) const override
{
Base::CopyTo(nodeP, newName, flags);
auto node = dynamic_pointer_cast<RowSliceNode<ElemType>>(nodeP);
auto node = dynamic_pointer_cast<SliceNode<ElemType>>(nodeP);
node->m_startIndex = m_startIndex;
node->m_sliceHeight = m_sliceHeight;
node->m_beginIndex = m_beginIndex;
node->m_endIndex = m_endIndex;
node->m_axis = m_axis;
}
virtual void Load(File& fstream, size_t modelVersion) override
{
Base::Load(fstream, modelVersion);
fstream >> m_startIndex >> m_sliceHeight;
int dim; // preparation for future extension that stores a dimension along which we slice
ptrdiff_t beginIndex, height;
fstream >> beginIndex >> height; // legacy format stored end-begin
m_beginIndex = (int)beginIndex;
m_endIndex = (int)(beginIndex + height);
if (modelVersion >= CNTK_MODEL_VERSION_3)
fstream >> dim;
fstream >> m_axis;
}
virtual void Save(File& fstream) const override
{
Base::Save(fstream);
fstream << m_startIndex << m_sliceHeight;
int dim = 1; // preparation for future extension that stores a dimension along which we slice
fstream << dim;
fstream << (ptrdiff_t)m_beginIndex << (ptrdiff_t)(m_endIndex - m_beginIndex); // legacy file format stores end-begin
fstream << m_axis;
}
private:
@ -286,7 +288,7 @@ private:
TensorShape GetInputSlice(size_t rank, const FrameRange & fr) const
{
auto inputSlice = Input(0)->GetTensorSliceFor(rank, fr); // input must be narrowed down
inputSlice.NarrowTo(0, m_startIndex, m_startIndex + m_sliceHeight);
inputSlice.NarrowTo(0, m_beginIndex, m_endIndex);
return inputSlice;
}
@ -317,21 +319,22 @@ public:
InferMBLayoutFromInputsForStandardCase(isFinalValidationPass);
auto sampleLayout = Input(0)->GetSampleLayout();
if (isFinalValidationPass && sampleLayout[0] < m_startIndex + m_sliceHeight)
RuntimeError("%ls %ls operation: m_startIndex + m_sliceHeight (%d) exceeds number of rows in the input ([%s]).", NodeName().c_str(), OperationName().c_str(), (int)(m_startIndex + m_sliceHeight), string(sampleLayout).c_str());
if (isFinalValidationPass && sampleLayout[0] < m_endIndex)
RuntimeError("%ls %ls operation: m_endIndex (%d) exceeds number of rows in the input ([%s]).", NodeName().c_str(), OperationName().c_str(), m_endIndex, string(sampleLayout).c_str());
if (sampleLayout[0] >= m_startIndex + m_sliceHeight) // (this guards against failing an out-of-bounds error if not isFinalValidationPass)
sampleLayout.NarrowTo(0, m_startIndex, m_startIndex + m_sliceHeight);
if (sampleLayout[0] >= m_endIndex) // (this guards against failing an out-of-bounds error if not isFinalValidationPass)
sampleLayout.NarrowTo(0, m_beginIndex, m_endIndex);
SetDims(TensorShape(sampleLayout.GetDims()), HasMBLayout());
}
private:
size_t m_startIndex, m_sliceHeight;
int m_beginIndex, m_endIndex; // 'int' because negative indices are allowed, to index from end Python-style
int m_axis; // note: axes are 1-based
};
template class RowSliceNode<float>;
template class RowSliceNode<double>;
template class SliceNode<float>;
template class SliceNode<double>;
// -----------------------------------------------------------------------
// RowStack (input0, input1, ...)