added imageLayout parameter to Convolution, MaxPooling, and AveragePooling (only Convolution had it, and BrainScrip only);

bug fix: LearnableParameter must also serialize m_sampleLayout
This commit is contained in:
Frank Seide 2016-01-01 15:05:19 -08:00
Родитель 50218cd031
Коммит 5ff5d685db
11 изменённых файлов: 92 добавлений и 117 удалений

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

@ -55,8 +55,8 @@ using namespace std;
L"WeightedLogistic(label, probability, instanceWeight, tag='') = new ComputationNode [ operation = 'Logistic' ; inputs = (label : probability : instanceWeight) /*plus the function args*/ ]\n"
L"ReconcileMBLayout(dataInput, layoutInput, tag='') = new ComputationNode [ operation = 'ReconcileMBLayout' ; inputs = (dataInput : layoutInput) /*plus the function args*/ ]\n"
L"Convolution(weightNode, inputValueNode, kernelWidth, kernelHeight, outputChannels, horizontalSubsample, verticalSubsample, zeroPadding = false, maxTempMemSizeInSamples = 0, imageLayout='CHW', tag='') = new ComputationNode [ operation = 'Convolution' ; inputs = (weightNode : inputValueNode) /*plus the function args*/ ]\n"
L"MaxPooling(input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, tag='') = new ComputationNode [ operation = 'MaxPooling' ; inputs = input /*plus the function args*/ ]\n"
L"AveragePooling(input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, tag='') = new ComputationNode [ operation = 'AveragePooling' ; inputs = input /*plus the function args*/ ]\n"
L"MaxPooling(input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayout='CHW', tag='') = new ComputationNode [ operation = 'MaxPooling' ; inputs = input /*plus the function args*/ ]\n"
L"AveragePooling(input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayout='CHW', tag='') = new ComputationNode [ operation = 'AveragePooling' ; inputs = input /*plus the function args*/ ]\n"
// TODO: define DelayedValue, with negative delay for future; cannot do this yet, need to be able to say something like delay = -(^.delay)
// aliases
L"ColumnwiseCrossProduct = KhatriRaoProduct // deprecated \n" // TODO: should it be deprecated? It is described as easier to understand in the CNTKBook.

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

@ -385,16 +385,15 @@ namespace Microsoft { namespace MSR { namespace CNTK {
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 == 5);
//optional
// optional
ImageLayoutKind imageLayoutKind = ImageLayoutKindFrom(node->GetOptionalParameter("imageLayout", "HWC"));
bool zeroPadding = node->GetOptionalParameter("zeroPadding", "false");
size_t maxTempMemSizeInSamples = node->GetOptionalParameter("maxTempMemSizeInSamples", "0");
nodePtr = builder.Convolution(NULL, NULL, kernelWidth, kernelHeight, outputChannels,
horizontalSubsample, verticalSubsample, zeroPadding, name, maxTempMemSizeInSamples);
horizontalSubsample, verticalSubsample, imageLayoutKind, zeroPadding, maxTempMemSizeInSamples, name);
}
}
else if (cnNodeType == OperationNameOf(MaxPoolingNode))
@ -417,11 +416,12 @@ namespace Microsoft { namespace MSR { namespace CNTK {
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);
ImageLayoutKind imageLayoutKind = ImageLayoutKindFrom(node->GetOptionalParameter("imageLayout", "HWC"));
nodePtr = builder.MaxPooling(NULL, /*inputWidth,inputHeight, channels,*/windowWidth, windowHeight,
horizontalSubsample, verticalSubsample, name);
horizontalSubsample, verticalSubsample, imageLayoutKind, name);
}
}
else if (cnNodeType == OperationNameOf(AveragePoolingNode))
@ -444,11 +444,12 @@ namespace Microsoft { namespace MSR { namespace CNTK {
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);
assert (id == 4);
ImageLayoutKind imageLayoutKind = ImageLayoutKindFrom(node->GetOptionalParameter("imageLayout", "HWC"));
nodePtr = builder.AveragePooling(NULL, /*inputWidth,inputHeight, channels,*/windowWidth, windowHeight,
horizontalSubsample, verticalSubsample, name);
horizontalSubsample, verticalSubsample, imageLayoutKind, name);
}
}
else if (cnNodeType == OperationNameOf(BatchNormalizationNode))

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

@ -251,7 +251,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
Base::Load(fstream, modelVersion);
fstream >> m_hasComputed;
LoadValue(fstream);
}
// Note: This loses the sample layout, but that is recovered by Validate().
}
virtual void DumpNodeInfo(const bool printValues, File& fstream) const override
{

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

@ -215,37 +215,26 @@ namespace Microsoft { namespace MSR { namespace CNTK {
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::CreateConvolutionNode(const std::wstring & nodeName,
const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels,
const size_t horizontalSubsample, const size_t verticalSubsample,
const bool zeroPadding,
ImageLayoutKind imageLayoutKind, const bool zeroPadding,
const size_t maxTempMemSizeInSamples)
{
return net.AddNodeToNetWithElemType(New<ConvolutionNode<ElemType>>(net.GetDeviceId(), nodeName,
kernelWidth, kernelHeight,
outputChannels,
horizontalSubsample,
verticalSubsample, zeroPadding,
maxTempMemSizeInSamples));
kernelWidth, kernelHeight, outputChannels,
horizontalSubsample, verticalSubsample, imageLayoutKind,
zeroPadding,
maxTempMemSizeInSamples));
}
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::CreateMaxPoolingNode(const std::wstring & nodeName,
const size_t windowWidth,
const size_t windowHeight,
const size_t horizontalSubsample,
const size_t verticalSubsample)
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind)
{
return net.AddNodeToNetWithElemType(New<MaxPoolingNode<ElemType>>(net.GetDeviceId(), nodeName,
windowWidth, windowHeight,
horizontalSubsample,
verticalSubsample));
return net.AddNodeToNetWithElemType(New<MaxPoolingNode<ElemType>>(net.GetDeviceId(), nodeName, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind));
}
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::CreateAveragePoolingNode(const std::wstring & nodeName, const size_t windowWidth,
const size_t windowHeight, const size_t horizontalSubsample,
const size_t verticalSubsample)
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::CreateAveragePoolingNode(const std::wstring & nodeName,
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind)
{
return net.AddNodeToNetWithElemType(New<AveragePoolingNode<ElemType>>(net.GetDeviceId(), nodeName,
windowWidth, windowHeight,
horizontalSubsample,
verticalSubsample));
return net.AddNodeToNetWithElemType(New<AveragePoolingNode<ElemType>>(net.GetDeviceId(), nodeName, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind));
}
// this is the catch-all for all cases not covered as special cases above
@ -274,49 +263,30 @@ namespace Microsoft { namespace MSR { namespace CNTK {
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::Convolution(const ComputationNodePtr weight,
const ComputationNodePtr inputValues,
const size_t kernelWidth,
const size_t kernelHeight,
const size_t outputChannels,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const bool zeroPadding,
const std::wstring nodeName,
const size_t maxTempMemSizeInSamples)
const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind, const bool zeroPadding, const size_t maxTempMemSizeInSamples,
const std::wstring nodeName)
{
return net.AddNodeToNetAndAttachInputs(New<ConvolutionNode<ElemType>>(net.GetDeviceId(), nodeName,
kernelWidth, kernelHeight,
outputChannels,
horizontalSubsample,
verticalSubsample, zeroPadding,
kernelWidth, kernelHeight, outputChannels, horizontalSubsample, verticalSubsample, imageLayoutKind, zeroPadding,
maxTempMemSizeInSamples),
weight, inputValues);
}
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::MaxPooling(const ComputationNodePtr inputValues,
const size_t windowWidth,
const size_t windowHeight,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const std::wstring nodeName)
{
return net.AddNodeToNetAndAttachInputs(New<MaxPoolingNode<ElemType>>(net.GetDeviceId(), nodeName,
windowWidth, windowHeight,
horizontalSubsample,
verticalSubsample),
windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind),
inputValues);
}
template<class ElemType> shared_ptr<ComputationNode<ElemType>> ComputationNetworkBuilder<ElemType>::AveragePooling(const ComputationNodePtr inputValues,
const size_t windowWidth,
const size_t windowHeight,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const std::wstring nodeName)
{
return net.AddNodeToNetAndAttachInputs(New<AveragePoolingNode<ElemType>>(net.GetDeviceId(), nodeName,
windowWidth, windowHeight,
horizontalSubsample,
verticalSubsample),
windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind),
inputValues);
}

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

@ -46,9 +46,9 @@ namespace Microsoft { namespace MSR { namespace CNTK {
ComputationNodePtr CreateInputNode(const std::wstring & inputName, const TensorShape & imageLayout, const size_t numImages);
ComputationNodePtr CreateSparseInputNode(const std::wstring & inputName, const TensorShape & imageLayout, const size_t numImages);
ComputationNodePtr CreatePairNetworkNode(const std::wstring & inputName, const size_t rows, const size_t cols);
ComputationNodePtr CreateConvolutionNode(const std::wstring & nodeName, const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels, const size_t horizontalSubsample, const size_t verticalSubsample, const bool zeroPadding = false, const size_t maxTempMemSizeInSamples = 0);
ComputationNodePtr CreateMaxPoolingNode(const std::wstring & nodeName, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample);
ComputationNodePtr CreateAveragePoolingNode(const std::wstring & nodeName, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample);
ComputationNodePtr CreateConvolutionNode(const std::wstring & nodeName, const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind, const bool zeroPadding = false, const size_t maxTempMemSizeInSamples = 0);
ComputationNodePtr CreateMaxPoolingNode(const std::wstring & nodeName, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind);
ComputationNodePtr CreateAveragePoolingNode(const std::wstring & nodeName, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind);
// this is the catch-all for all cases not covered as special cases above
// Unlike the specialized ones above, this one creates nodes by type given as a string.
ComputationNodePtr CreateComputationNode(const std::wstring & nodeType, const std::wstring & nodeName);
@ -61,25 +61,15 @@ namespace Microsoft { namespace MSR { namespace CNTK {
ComputationNodePtr PairNetwork(const ComputationNodePtr & a, const std::wstring nodeName = L"");
ComputationNodePtr Convolution(const ComputationNodePtr weight,
const ComputationNodePtr inputValues,
const size_t kernelWidth,
const size_t kernelHeight,
const size_t outputChannels,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const bool zeroPadding = false,
const std::wstring nodeName = L"",
const size_t maxTempMemSizeInSamples = 0);
const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels,
const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const bool zeroPadding = false, const size_t maxTempMemSizeInSamples = 0,
const std::wstring nodeName = L"");
ComputationNodePtr MaxPooling(const ComputationNodePtr inputValues,
const size_t windowWidth,
const size_t windowHeight,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const std::wstring nodeName = L"");
ComputationNodePtr AveragePooling(const ComputationNodePtr inputValues,
const size_t windowWidth,
const size_t windowHeight,
const size_t horizontalSubsample,
const size_t verticalSubsample,
const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const std::wstring nodeName = L"");
ComputationNodePtr ErrorPrediction(const ComputationNodePtr a, const ComputationNodePtr b, const std::wstring nodeName = L"");
ComputationNodePtr PerDimMeanVarNormalization(const ComputationNodePtr feature, const ComputationNodePtr mean, const ComputationNodePtr InvStdDev, const std::wstring nodeName = L"");

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

@ -185,9 +185,6 @@ namespace Microsoft {
if (m_sampleLayout.GetDim(k) == 0 || m_sampleLayout.GetDim(k) == SIZE_MAX)
layoutPlausible = false;
}
// some code initializes it to (1,1,rowDim)
if (m_sampleLayout.GetRank() == 3 && m_sampleLayout.GetDim(0) == 1 && m_sampleLayout.GetDim(1) == 1)
layoutPlausible = false;
// check dimension
if (GetNumRows() != m_sampleLayout.GetNumElements())
layoutPlausible = false;

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

@ -504,7 +504,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
const char * mbSizeMark = child->m_pMBLayout ? "MBSize " : "";
if (child->m_sampleLayout.GetRank() == 3 && (child->m_sampleLayout[1] != 1 || child->m_sampleLayout[0] != 1)) // looks like an image: use WHC notation
fprintf(stderr, "%ls[%lu {W=%lu, H=%lu, C=%lu}, %s%lu]", child->NodeName().c_str(), child->GetNumRows(),
fprintf(stderr, "%ls[%lu [%s] {W=%lu, H=%lu, C=%lu}, %s%lu]", child->NodeName().c_str(), child->GetNumRows(), string(child->m_sampleLayout).c_str(),
child->m_sampleLayout[1], child->m_sampleLayout[2], child->m_sampleLayout[0], mbSizeMark, child->GetNumCols());
//BUGBUG: This ^^ will print based on the old legacy layout, and we have no way of knowing here whether that is correct.
else if (child->m_sampleLayout.GetRank() > 1) // tensor: output the tensor dimensions --TODO: there will be no numRows in the future, only the tensor
@ -820,7 +820,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
fstream >> Value();
// above reads dimensions, so we must update our own m_numRows/m_numCols
SetDims(TensorShape(Value().GetNumRows()), Value().GetNumCols());
// BUGBUG: This looses the sample layout (tensor shape). It should be serialized as well.
// BUGBUG: This looses the sample layout (tensor shape). The caller must know this and fix it up if needed (currently needed for LearnableParameterNode).
}
// reader updated m_functionValue--update our internal state, i.e. m_numCols

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

@ -72,8 +72,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
{
SetDims(ImageDimensions::AsTensorShape(1, 1, 0, m_imageLayoutKind), 0);
}
ConvolutionNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels, const size_t horizontalSubsample, const size_t verticalSubsample,
const bool zeroPadding = false, const size_t maxTempMemSizeInSamples = 0, ImageLayoutKind imageLayoutKind = ImageLayoutKind::HWC) :
ConvolutionNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t kernelWidth, const size_t kernelHeight, const size_t outputChannels, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind,
const bool zeroPadding = false, const size_t maxTempMemSizeInSamples = 0) :
Base(deviceId, name),
m_outputChannels(outputChannels),
m_kernelWidth(kernelWidth), m_kernelHeight(kernelHeight),
@ -86,8 +86,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
}
ConvolutionNode(const ScriptableObjects::IConfigRecordPtr configp) :
ConvolutionNode(configp->Get(L"deviceId"), L"<placeholder>", configp->Get(L"kernelWidth"), configp->Get(L"kernelHeight"), configp->Get(L"outputChannels"),
configp->Get(L"horizontalSubsample"), configp->Get(L"verticalSubsample"),
configp->Get(L"zeroPadding"), configp->Get(L"maxTempMemSizeInSamples"), ImageLayoutKindFrom(configp->Get(L"imageLayout")))
configp->Get(L"horizontalSubsample"), configp->Get(L"verticalSubsample"), ImageLayoutKindFrom(configp->Get(L"imageLayout")),
configp->Get(L"zeroPadding"), configp->Get(L"maxTempMemSizeInSamples"))
{
// weightNodeName, inputValueNodeName, kernelWidth, kernelHeight, outputChannels, horizontalSubsample, verticalSubsample, zeroPadding = false, maxTempMemSizeInSamples = 0
AttachInputs(configp, this->GetExpectedNumInputs());
@ -338,17 +338,19 @@ namespace Microsoft { namespace MSR { namespace CNTK {
PoolingNodeBase(DEVICEID_TYPE deviceId, const wstring & name) :
Base(deviceId, name),
m_windowWidth(SIZE_MAX), m_windowHeight(SIZE_MAX),
m_horizontalSubsample(SIZE_MAX), m_verticalSubsample(SIZE_MAX)
m_horizontalSubsample(SIZE_MAX), m_verticalSubsample(SIZE_MAX),
m_imageLayoutKind(ImageLayoutKind::HWC)
{ }
PoolingNodeBase(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample) :
PoolingNodeBase(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind) :
Base(deviceId, name),
m_windowWidth(windowWidth), m_windowHeight(windowHeight),
m_horizontalSubsample(horizontalSubsample), m_verticalSubsample(verticalSubsample)
m_horizontalSubsample(horizontalSubsample), m_verticalSubsample(verticalSubsample),
m_imageLayoutKind(imageLayoutKind)
{
m_factory = ConvolutionEngineFactory<ElemType>::Create(deviceId, ConvolutionEngineFactory<ElemType>::EngineType::Auto, ImageLayoutKind::HWC/*m_imageLayoutKind*/);
}
PoolingNodeBase(const ScriptableObjects::IConfigRecordPtr configp) :
PoolingNodeBase(configp->Get(L"deviceId"), L"<placeholder>", configp->Get(L"windowWidth"), configp->Get(L"windowHeight"), configp->Get(L"horizontalSubsample"), configp->Get(L"verticalSubsample"))
PoolingNodeBase(configp->Get(L"deviceId"), L"<placeholder>", configp->Get(L"windowWidth"), configp->Get(L"windowHeight"), configp->Get(L"horizontalSubsample"), configp->Get(L"verticalSubsample"), ImageLayoutKindFrom(configp->Get(L"imageLayout")))
{
// input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample
AttachInputs(configp, this->GetExpectedNumInputs());
@ -357,13 +359,18 @@ namespace Microsoft { namespace MSR { namespace CNTK {
void Save(File& fstream) const override
{
Base::Save(fstream);
fstream << m_windowWidth << m_windowHeight << m_horizontalSubsample << m_verticalSubsample;
uint32_t imageLayoutKind = (uint32_t)m_imageLayoutKind;
uint32_t windowWidth = (uint32_t)m_windowWidth;
fstream << imageLayoutKind << windowWidth << m_windowHeight << m_horizontalSubsample << m_verticalSubsample;
}
void Load(File& fstream, size_t modelVersion) override
{
Base::Load(fstream, modelVersion);
fstream >> m_windowWidth >> m_windowHeight >> m_horizontalSubsample >> m_verticalSubsample;
uint32_t imageLayoutKind, windowWidth;
fstream >> imageLayoutKind >> windowWidth >> m_windowHeight >> m_horizontalSubsample >> m_verticalSubsample;
m_windowWidth = windowWidth;
m_imageLayoutKind = (ImageLayoutKind)imageLayoutKind;
}
void CopyTo(ComputationNodeBasePtr nodeP, const std::wstring& newName, const CopyNodeFlags flags) const override
@ -381,6 +388,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
node->m_inputSizePerSample = m_inputSizePerSample;
node->m_outputSizePerSample = m_outputSizePerSample;
node->m_imageLayoutKind = m_imageLayoutKind;
}
}
@ -419,7 +428,6 @@ namespace Microsoft { namespace MSR { namespace CNTK {
InferMBLayoutFromInputsForStandardCase();
// get input tensor shape and interpret as image dimensions
const auto m_imageLayoutKind = ImageLayoutKind::HWC; // BUGBUG: Finish this. Must be serialized.
auto inDims = ImageDimensions(GetInputSampleLayout(0), m_imageLayoutKind);
if (inDims.m_width < m_windowWidth || inDims.m_height < m_windowHeight)
@ -450,7 +458,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
if (m_inT == nullptr)
m_inT = m_factory->CreateTensor(inDims.m_width, inDims.m_height, inDims.m_numChannels, 1);
if (m_outT == nullptr)
m_outT = m_factory->CreateTensor(m_sampleLayout[1], m_sampleLayout[2], m_sampleLayout[0], 1);
m_outT = m_factory->CreateTensor(outDims.m_width, outDims.m_height, outDims.m_numChannels, 1);
}
void DumpNodeInfo(const bool printValues, File& fstream) const override
@ -471,16 +479,18 @@ namespace Microsoft { namespace MSR { namespace CNTK {
}
protected:
size_t m_windowWidth, m_windowHeight;
size_t m_horizontalSubsample, m_verticalSubsample;
size_t m_inputSizePerSample, m_outputSizePerSample;
ImageLayoutKind m_imageLayoutKind; // how to interpret the tensor (which dimensions are X/Y and C)
std::unique_ptr<ConvolutionEngineFactory<ElemType>> m_factory;
std::unique_ptr<PoolingEngine<ElemType>> m_poolEng;
std::unique_ptr<ConvolutionTensor4D> m_inT;
std::unique_ptr<ConvolutionTensor4D> m_outT;
std::unique_ptr<PoolingDescriptor> m_poolDesc;
size_t m_windowWidth, m_windowHeight;
size_t m_horizontalSubsample, m_verticalSubsample;
size_t m_inputSizePerSample, m_outputSizePerSample;
};
// add this at the start of each derived class, to get access to the members of ComputationNode
@ -501,8 +511,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
static const std::wstring TypeName() { return L"MaxPooling"; }
public:
MaxPoolingNode(DEVICEID_TYPE deviceId, const wstring & name) : Base(deviceId, name) { }
MaxPoolingNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample) :
Base(deviceId, name, windowWidth, windowHeight, horizontalSubsample, verticalSubsample)
MaxPoolingNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind) :
Base(deviceId, name, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind)
{ }
MaxPoolingNode(const ScriptableObjects::IConfigRecordPtr configp) :
Base(configp)
@ -530,8 +540,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
static const std::wstring TypeName() { return L"AveragePooling"; }
public:
AveragePoolingNode(DEVICEID_TYPE deviceId, const wstring & name) : Base(deviceId, name) { }
AveragePoolingNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample) :
Base(deviceId, name, windowWidth, windowHeight, horizontalSubsample, verticalSubsample)
AveragePoolingNode(DEVICEID_TYPE deviceId, const wstring & name, const size_t windowWidth, const size_t windowHeight, const size_t horizontalSubsample, const size_t verticalSubsample, ImageLayoutKind imageLayoutKind) :
Base(deviceId, name, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayoutKind)
{ }
AveragePoolingNode(const ScriptableObjects::IConfigRecordPtr configp) :
Base(configp)

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

@ -28,6 +28,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
// -----------------------------------------------------------------------
// LearnableParameter (/*no input*/)
// represents weight matrices and biases
// TODO: add -Node to the class name
// -----------------------------------------------------------------------
template<class ElemType>
@ -96,7 +97,8 @@ namespace Microsoft { namespace MSR { namespace CNTK {
{
Base::Save(fstream);
fstream << m_parameterUpdateRequired;
fstream << GetNumRows() << GetNumCols();
fstream << (size_t)0/*#rows in a legacy file format*/ << GetNumCols();
m_sampleLayout.Save(fstream);
fstream << Value();
}
@ -108,8 +110,13 @@ namespace Microsoft { namespace MSR { namespace CNTK {
fstream >> m_parameterUpdateRequired;
fstream >> rows >> cols;
SetDims(TensorShape(rows), cols);
TensorShape sampleLayout;
if (rows != 0) // legacy file format
sampleLayout = TensorShape(rows);
else
sampleLayout.Load(fstream);
LoadValue(fstream);
SetDims(sampleLayout, cols); // note: call this after LoadValue() since LoadValue() overwrites m_sampleLayout
}
// initialize with random numbers
@ -235,6 +242,7 @@ namespace Microsoft { namespace MSR { namespace CNTK {
// InputValueBase (/*no input*/)
// Base class for InputValue and SparseInputValue (typically fed by a DataReader)
// this covers four types: (regular vs. image) x (non-sparse vs. sparse)
// TODO: add -Node to the class names
// -----------------------------------------------------------------------
template<class ElemType>

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

@ -70,7 +70,6 @@ train = [
hStride1 = 1
vStride1 = 1
# weight[cMap1, kW1 * kH1 * inputChannels]
# ConvReLULayer is defined in Macros.ndl
conv1_act = ConvReLULayer(featScaled, cMap1, 25, kW1, kH1, hStride1, vStride1, 10, 1).out
# pool1
@ -78,7 +77,7 @@ train = [
pool1H = 2
pool1hStride = 2
pool1vStride = 2
pool1 = MaxPooling(conv1_act, pool1W, pool1H, pool1hStride, pool1vStride)
pool1 = MaxPooling(conv1_act, pool1W, pool1H, pool1hStride, pool1vStride, imageLayout=if useCuDnn then "cudnn" else "legacy")
# conv2
kW2 = 5
@ -95,7 +94,7 @@ train = [
pool2H = 2
pool2hStride = 2
pool2vStride = 2
pool2 = AveragePooling(conv2_act, pool2W, pool2H, pool2hStride, pool2vStride)
pool2 = AveragePooling(conv2_act, pool2W, pool2H, pool2hStride, pool2vStride, imageLayout=if useCuDnn then "cudnn" else "legacy")
h1Dim = 128
# DNNSigmoidLayer and DNNLayer are defined in Macros.ndl

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

@ -60,7 +60,6 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
for (int deviceId : { 0 })
{
// BUGBUG: These will fail depending on whether we built with cuDNN or not. Without cuDNN we should use HWC
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto fact = ConvFact::Create(deviceId, ConvFact::EngineType::Auto, ImageLayoutKind::CHW);
auto tt = typeid(fact).name();
UNUSED(tt);
@ -71,14 +70,12 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto convT = fact->CreateConvDescriptor(*inT, *filtT, sW, sH, false);
auto biasT = fact->CreateTensor(1, 1, cmapOut, 1);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
vec buf(inW * inH * cmapIn * n);
int seed = 0;
// Create input, cmapIn feature maps, inW x inH each (NCHW format).
std::generate(buf.begin(), buf.end(), [=, &seed]{ return seed++ % (inW * inH * cmapIn); });
SingleMatrix in(inW * inH * cmapIn, n, buf.data(), matrixFlagNormal, deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
seed = 0;
buf.resize(kW * kH * cmapIn * cmapOut);
// Create cmapOut filters, each kW x kH x cmapIn (NCHW format).
@ -88,9 +85,7 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
SingleMatrix out(outW * outH * cmapOut, n, deviceId);
SingleMatrix temp(deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
eng->Forward(*inT, in, *filtT, filt, *convT, *outT, out, temp);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
// Output is in NCHW format.
std::array<float, 4 * 2 * 2> expBuf = {
@ -100,24 +95,19 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
15219.0f, 15921.0f, 18729.0f, 19431.0f
};
SingleMatrix exp(outW * outH * cmapOut, n, expBuf.data(), matrixFlagNormal, deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
BOOST_CHECK_MESSAGE(out.IsEqualTo(exp), "Unexpected convolution output.");
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
float b[] = { 1.0f, 2.0f };
SingleMatrix bias(cmapOut, 1, b, matrixFlagNormal, deviceId);
SingleMatrix plusB(outW * outH * cmapOut, n, expBuf.data(), matrixFlagNormal, deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
eng->AddBias(*outT, out, *biasT, bias, plusB);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
// Bias is per-channel.
seed = 0;
std::transform(expBuf.begin(), expBuf.end(), expBuf.begin(),
[=, &seed, &b](const float& a) { return a + b[(seed++ % (outW * outH * cmapOut)) / (outW * outH)]; });
SingleMatrix expPlusB(outW * outH * cmapOut, n, expBuf.data(), matrixFlagNormal, deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
BOOST_CHECK_MESSAGE(plusB.IsEqualTo(expPlusB), "Unexpected (convolution + bias) output.");
}
}
@ -144,13 +134,20 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
for (int deviceId : { -1, 0 })
{
auto fact = ConvFact::Create(deviceId, ConvFact::EngineType::Auto, ImageLayoutKind::CHW);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto eng = fact->CreateConvEngine(deviceId, 0);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto inT = fact->CreateTensor(inW, inH, cmapIn, n);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto filtT = fact->CreateFilter(kW, kH, cmapIn, cmapOut);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto outT = fact->CreateTensor(outW, outH, cmapOut, n);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
auto convT = fact->CreateConvDescriptor(*inT, *filtT, sW, sH, pad);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
// Input in NCHW format.
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
SingleMatrix in(inW * inH * cmapIn, n, vec(inW * inH * cmapIn * n, 1.0f).data(), matrixFlagNormal, deviceId);
// Create cmapOut filters, each kW x kH x cmapIn (NCHW format).
SingleMatrix filt(cmapOut, kW * kH * cmapIn, vec(kW * kH * cmapIn * cmapOut, 1.0f).data(), matrixFlagNormal, deviceId);
@ -158,7 +155,9 @@ fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
SingleMatrix out(outW * outH * cmapOut, n, deviceId);
SingleMatrix temp(deviceId);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
eng->Forward(*inT, in, *filtT, filt, *convT, *outT, out, temp);
fprintf(stderr, "ConvolutionEngineTests.cpp %d\n", __LINE__);
// Output is in NCHW format.
float expBuf[] = {