{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/CNTK/issues/462","repository_url":"https://api.github.com/repos/Microsoft/CNTK","labels_url":"https://api.github.com/repos/Microsoft/CNTK/issues/462/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/CNTK/issues/462/comments","events_url":"https://api.github.com/repos/Microsoft/CNTK/issues/462/events","html_url":"https://github.com/Microsoft/CNTK/issues/462","id":154065194,"number":462,"title":"Issue with ReconcileDynamicAxis in evaluating a sequence after training the model","user":{"login":"raminia","id":2532252,"avatar_url":"https://avatars.githubusercontent.com/u/2532252?v=3","gravatar_id":"","url":"https://api.github.com/users/raminia","html_url":"https://github.com/raminia","followers_url":"https://api.github.com/users/raminia/followers","following_url":"https://api.github.com/users/raminia/following{/other_user}","gists_url":"https://api.github.com/users/raminia/gists{/gist_id}","starred_url":"https://api.github.com/users/raminia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raminia/subscriptions","organizations_url":"https://api.github.com/users/raminia/orgs","repos_url":"https://api.github.com/users/raminia/repos","events_url":"https://api.github.com/users/raminia/events{/privacy}","received_events_url":"https://api.github.com/users/raminia/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-05-10T17:41:34Z","updated_at":"2016-05-10T23:58:20Z","closed_at":"2016-05-10T23:58:20Z","body":"I followed an example in sequence classification in Tests\\EndToEndTests\\Text\\SequenceClassification\\Config\\seqcla.cntk and modified it for my own data [n sequence of 26 inputs (features), 1 binary label (output)]\r\n\r\nI trained the network usingthe configFile below. However, I faced an issue with evaluating the trained LSTM network against the train or test samples when running the _Write _block. It seems like the shape of the input and output does not match. The error is not very helpful and I'm not sure how to fix it. I have doubts about the structure of the network. Could this be because I defined the network improperly?\r\n\r\n```\r\nEXCEPTION occurred: l3p ReconcileDynamicAxis operation discovered that l3.act Sigmoid operation produced an MB layout that is incompatible with that of labels InputValue.\r\n\r\n[CALL STACK]\r\n    > Microsoft::MSR::CNTK::ComputationNetwork::PARTraversalFlowControlNode::  ForwardProp\r\n    - Microsoft::MSR::CNTK::ComputationNetwork::  ForwardProp\r\n    - Microsoft::MSR::CNTK::ComputationNetwork::ForwardProp<std::vector<std::shared_ptr<Microsoft::MSR::CNTK::ComputationNodeBase>,std::allocator<std::shared_ptr<Microsoft::MSR::CNTK::ComputationNodeBase>>>>\r\n    - Microsoft::MSR::CNTK::SimpleEvaluator<float>::  Evaluate\r\n    - DoEvalBase<float>\r\n    - DoEval<float>\r\n    - DoCommands<float>\r\n    - wmainOldCNTKConfig\r\n    - wmain1\r\n    - wmain\r\n    - __tmainCRTStartup\r\n    - BaseThreadInitThunk\r\n    - RtlUserThreadStart\r\n\r\n~MPIWrapper\r\n```\r\n\r\n\r\nI have a very similar structure working in Tensorflow without issues but I need it to run under CNTK.\r\n![image](https://cloud.githubusercontent.com/assets/2532252/15156229/e6b8c64c-169a-11e6-8d98-5fac588782b4.png)\r\n\r\n\r\nAny ideas?\r\n\r\nConfig File:\r\n```javascript\r\n\r\nRootDir = \"E:\\cntk\"\r\nmyDataDir = \"E:\\cntk\"\r\n\r\nConfigDir = \"$RootDir$\"\r\nDataDir = \"$myDataDir$\"\r\nOutputDir = \"$RootDir$/Output\"\r\nModelDir = \"$OutputDir$/Models\"\r\n\r\n\r\n# deviceId = -1 for CPU, >=0 for GPU devices, \"auto\" chooses the best GPU, or CPU if no usable GPU is available\r\ndeviceId = \"auto\"\r\n\r\ncommand = Write #:train #: #:Write\r\n\r\nprecision = \"float\"\r\ntraceLevel = 1\r\nmodelPath = \"$ModelDir$/cntkLSTM.dnn\"\r\nparallelTrain = true\r\n\r\nTrain=[\r\n    action=\"train\"\r\n    run=BrainScriptNetworkBuilder\r\n    \r\n    BrainScriptNetworkBuilder=[\r\n        \r\n        Macros = [\r\n            // define \"last hidden state of sequence\" in the LSTM (really for any sequence though)\r\n            TakeRight (N, x) = BS.Sequences._Take(FutureValue, N, x)\r\n            Last(x) = TakeRight(1, x)\r\n\r\n        ]\r\n        Layers = [\r\n            EmbeddingLayer(input, vocabSize, embeddingDim, embeddingPath) = [\r\n                embedding = Transpose(LearnableParameter(vocabSize, embeddingDim, learningRateMultiplier = 0.0, init = 'fromFile', initFromFilePath = embeddingPath))          \r\n                lookup = GatherPacked(features, embedding)\r\n            ].lookup\r\n            # TODO: suggested change of parameter order: output dims first, inputDim=input.dim\r\n            DenseLayer(input, inputSize, outputSize, activation) = [\r\n               z = BFF(input, outputSize, inputSize).z\r\n               act = activation(z)\r\n            ].act\r\n            # TODO: suggested change of parameter order: output dims first, inputDim=input.Dim optional, cellDim=outputDim optional\r\n            LSTMLayer(input, inputSize, outputSize, cellSize) = [ \r\n               h = BS.RNNs.RecurrentLSTMP2 (outputSize, cellDim=cellSize, input, inputDim=inputSize).h\r\n               #result = selector(lstm)\r\n            ].h\r\n        ]        \r\n        \r\n        // LSTM params\r\n        lstmDim = 5\r\n        cellDim = 5\r\n        \r\n        // model\r\n        numLabels = 1        \r\n        featureDim = 26     \r\n                \r\n        // set up features and labels\r\n        t = DynamicAxis()\r\n        features = Input(featureDim,dynamicAxis=t)   # Input has shape (1,t)\r\n        labels   = Input(numLabels)          # Input has shape (numLabels,*) where all sequences in *=1\r\n        \r\n        // normalize features\r\n        featNorm = MeanVarNorm(features)\r\n        \r\n        // use multiple layers of LSTM\r\n        l1 = Layers.LSTMLayer(featNorm, featureDim, lstmDim, cellDim)\r\n        l2 = Layers.LSTMLayer(l1, lstmDim, lstmDim, cellDim)\r\n        l3 = Layers.DenseLayer(l2, lstmDim, numLabels, Sigmoid)\r\n        out = Pass(l3, tag='output')   \r\n        \r\n        // Make sure the trainer understands that the time dimension of l3 is actually the same as that of labels. \r\n        # rearranging the data w.r.t. MBLayout or broadcasting across sequence items\r\n        l3p = ReconcileDynamicAxis(l3, labels)\r\n     \r\n        // training criteria\r\n        ce  = Logistic(labels, l3p, tag='criterion')  # Logistic(labels, Sigmoid(l3), tag='criterion') # CrossEntropyWithSoftmax(labels, l3p, tag='criterion')   // this is the training objective\r\n        wer = SquareError (labels,l3p,tag='evaluation') # ErrorPrediction        (labels, l3p, tag='evaluation') # SquareError(labels, Softmax(l3), tag='evaluation') # ErrorPrediction        (labels, l3p, tag='evaluation')  // this also gets tracked\r\n    \r\n    ]\r\n    \r\n   SGD = [\r\n    \r\n        epochSize = 0\r\n        #minibatchSize = 1000\r\n        maxEpochs = 5\r\n        momentumPerMB = 0:0.9\r\n        learningRatesPerMB = 0.1   \r\n        AutoAdjust=[\r\n            reduceLearnRateIfImproveLessThan=0\r\n            loadBestModel=true\r\n            increaseLearnRateIfImproveMoreThan=1000000000\r\n            learnRateDecreaseFactor=0.5\r\n            learnRateIncreaseFactor=1.382\r\n            autoAdjustLR=AdjustAfterEpoch\r\n        ]  \r\n\t  \r\n    ]\r\n    \r\n    reader = [\r\n        readerType = \"CNTKTextFormatReader\"\r\n        file = \"$DataDir$/train_10s2_lb1.txt\"            \r\n        randomize = \"none\"\r\n\t\t \r\n        input = [            \r\n            features=[\r\n                alias = \"F0\"                \r\n                dim = 26               \r\n                format = \"dense\"\r\n            ]\r\n            labels=[\r\n                alias = \"L\"                \r\n                dim = 1           \r\n                format = \"dense\"\r\n            ]\r\n        ]\r\n   ]    \r\n   outputPath = \"$OutputDir$/output.txt\"        # dump the output as text?\r\n]\r\n\r\nWrite=[\r\n    action=\"eval\"\r\n    run=BrainScriptNetworkBuilder\r\n    modelFile = \"$ModelDir$/cntkLSTM.dnn\"    \r\n    \r\n    reader = [\r\n\t\t\trandomize = \"none\"\r\n            readerType = \"CNTKTextFormatReader\"\r\n            file = \"$DataDir$/test_10s2_lb1.txt\"            \r\n            \r\n            input = [            \r\n                features=[\r\n                    alias = \"F0\"                \r\n                    dim = 26               \r\n                    format = \"dense\"\r\n                ]\r\n                labels=[\r\n                    alias = \"L\"                \r\n                    dim = 1           \r\n                    format = \"dense\"\r\n                ]\r\n            ]\r\n            \r\n   ]    \r\n   outputPath = \"$OutputDir$/output.txt\"        # dump the output as text\r\n]\r\n\r\n```\r\n\r\nThe network validation passes as\r\n```\r\nValidating --> l2.h.lstmState._privateInnards.ht = ElementTimes (l2.h.lstmState._privateInnards.ot, l2.h.lstmState._privateInnards.ht.ElementTimesArgs[1]) : [10 x t1], [10 x t1] -> [10 x t1]\r\nValidating --> l3.z.z.PlusArgs[0] = Times (l3.z.W, l2.h.lstmState._privateInnards.ht) : [1 x 10], [10 x t1] -> [1 x t1]\r\nValidating --> l3.z.B = LearnableParameter() :  -> [1 x 1]\r\nValidating --> l3.z.z = Plus (l3.z.z.PlusArgs[0], l3.z.B) : [1 x t1], [1 x 1] -> [1 x 1 x t1]\r\nValidating --> l3.act = Sigmoid (l3.z.z) : [1 x 1 x t1] -> [1 x 1 x t1]\r\nValidating --> l3p = ReconcileDynamicAxis (l3.act, labels) : [1 x 1 x t1], [1 x *] -> [1 x 1 x *]\r\nValidating --> ce = Logistic (labels, l3p) : [1 x *], [1 x 1 x *] -> [1]\r\nValidating --> out = Pass (l3p) : [1 x 1 x *] -> [1 x 1 x *]\r\nValidating --> t = DynamicAxis() :  -> [1 x 1 x t1]\r\nValidating --> wer = SquareError (labels, l3p) : [1 x *], [1 x 1 x *] -> [1]\r\n\r\nValidating network. 76 nodes to process in pass 2.\r\n```"},"comment":{"url":"https://api.github.com/repos/Microsoft/CNTK/issues/comments/218326435","html_url":"https://github.com/Microsoft/CNTK/issues/462#issuecomment-218326435","issue_url":"https://api.github.com/repos/Microsoft/CNTK/issues/462","id":218326435,"user":{"login":"frankseide","id":16671126,"avatar_url":"https://avatars.githubusercontent.com/u/16671126?v=3","gravatar_id":"","url":"https://api.github.com/users/frankseide","html_url":"https://github.com/frankseide","followers_url":"https://api.github.com/users/frankseide/followers","following_url":"https://api.github.com/users/frankseide/following{/other_user}","gists_url":"https://api.github.com/users/frankseide/gists{/gist_id}","starred_url":"https://api.github.com/users/frankseide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frankseide/subscriptions","organizations_url":"https://api.github.com/users/frankseide/orgs","repos_url":"https://api.github.com/users/frankseide/repos","events_url":"https://api.github.com/users/frankseide/events{/privacy}","received_events_url":"https://api.github.com/users/frankseide/received_events","type":"User","site_admin":false},"created_at":"2016-05-10T23:58:20Z","updated_at":"2016-05-10T23:58:20Z","body":"A minibatch is a collection of sequences, where each sequence can have a different length. The CE criterion computes a sample-by-sample loss value which is them summed up over the training corpus. This means that each feature sequence must have the same length as the corresponding label sequence. This sequence length is referred to as a dynamic tensor dimension. In the Validation output it is shown as \"*\". The corresponding features and labels are matched internally by being organized in memory in the same way (same packing).\r\n\r\nHowever, there are scenarios where that is not the case, for example in sequence-to-sequence models or sequence classification. In those scenarios, users can explicitly declare dynamic time axes and give them names. The sample code you based your work off was such a case, where the input was a sequence, while the output was a single token. In this case, you must say something like\r\n```\r\nt = DynamicAxis()\r\n```\r\nand pass ```t``` as an optional argument ```dynamicAxis``` to the Input. This way, CNTK will know that these two representations are incompatible.\r\n\r\nNow, there are occasions where you end up with two dynamic axes that are the same. In the sequence-classification example, the reader provides a 1-sample label, and inside the network the Last() function extracts a 1-sample output from the end of a sequence. CNTK can currently not know that these two are actually the same time axis. Hence you can use ```ReconcileDynamicAxis()``` to let it know. This will take a dynamic axis from one input (labels in this example) and the data from a second input (last hidden LSTM state), and combine them. Its output is now known to CNTK to have a compatible dynamic axis, so that you now can apply the CE criterion to it.\r\n\r\nIn this reconcile process, sequence ids are indeed used to match inputs, using a descriptor structure that describes all sequences in a minibatch and how they are packed (including padding; cf. ```Sequences.h```, ```MBLayout::m_sequences[]```). They are used by the fact that all entries in the m_sequences[] array are sorted by sequence id; and that two minibatch layouts with the same sequence lengths always have the same, hence column-by-column compatible, storage.\r\n\r\nThat's all."}}