/// <summary>Applies the derivative of tanh to each of the elements in the vector.</summary> /// <remarks>Applies the derivative of tanh to each of the elements in the vector. Returns a new matrix.</remarks> public static SimpleMatrix ElementwiseApplyTanhDerivative(SimpleMatrix input) { SimpleMatrix output = new SimpleMatrix(input.NumRows(), input.NumCols()); output.Set(1.0); output = output.Minus(input.ElementMult(input)); return(output); }
private void BackpropDerivativesAndError(Tree tree, TwoDimensionalMap <string, string, SimpleMatrix> binaryTD, TwoDimensionalMap <string, string, SimpleMatrix> binaryCD, TwoDimensionalMap <string, string, SimpleTensor> binaryTensorTD, IDictionary <string, SimpleMatrix> unaryCD, IDictionary <string, SimpleMatrix> wordVectorD, SimpleMatrix deltaUp) { if (tree.IsLeaf()) { return; } SimpleMatrix currentVector = RNNCoreAnnotations.GetNodeVector(tree); string category = tree.Label().Value(); category = model.BasicCategory(category); // Build a vector that looks like 0,0,1,0,0 with an indicator for the correct class SimpleMatrix goldLabel = new SimpleMatrix(model.numClasses, 1); int goldClass = RNNCoreAnnotations.GetGoldClass(tree); if (goldClass >= 0) { goldLabel.Set(goldClass, 1.0); } double nodeWeight = model.op.trainOptions.GetClassWeight(goldClass); SimpleMatrix predictions = RNNCoreAnnotations.GetPredictions(tree); // If this is an unlabeled class, set deltaClass to 0. We could // make this more efficient by eliminating various of the below // calculations, but this would be the easiest way to handle the // unlabeled class SimpleMatrix deltaClass = goldClass >= 0 ? predictions.Minus(goldLabel).Scale(nodeWeight) : new SimpleMatrix(predictions.NumRows(), predictions.NumCols()); SimpleMatrix localCD = deltaClass.Mult(NeuralUtils.ConcatenateWithBias(currentVector).Transpose()); double error = -(NeuralUtils.ElementwiseApplyLog(predictions).ElementMult(goldLabel).ElementSum()); error = error * nodeWeight; RNNCoreAnnotations.SetPredictionError(tree, error); if (tree.IsPreTerminal()) { // below us is a word vector unaryCD[category] = unaryCD[category].Plus(localCD); string word = tree.Children()[0].Label().Value(); word = model.GetVocabWord(word); //SimpleMatrix currentVectorDerivative = NeuralUtils.elementwiseApplyTanhDerivative(currentVector); //SimpleMatrix deltaFromClass = model.getUnaryClassification(category).transpose().mult(deltaClass); //SimpleMatrix deltaFull = deltaFromClass.extractMatrix(0, model.op.numHid, 0, 1).plus(deltaUp); //SimpleMatrix wordDerivative = deltaFull.elementMult(currentVectorDerivative); //wordVectorD.put(word, wordVectorD.get(word).plus(wordDerivative)); SimpleMatrix currentVectorDerivative = NeuralUtils.ElementwiseApplyTanhDerivative(currentVector); SimpleMatrix deltaFromClass = model.GetUnaryClassification(category).Transpose().Mult(deltaClass); deltaFromClass = deltaFromClass.ExtractMatrix(0, model.op.numHid, 0, 1).ElementMult(currentVectorDerivative); SimpleMatrix deltaFull = deltaFromClass.Plus(deltaUp); SimpleMatrix oldWordVectorD = wordVectorD[word]; if (oldWordVectorD == null) { wordVectorD[word] = deltaFull; } else { wordVectorD[word] = oldWordVectorD.Plus(deltaFull); } } else { // Otherwise, this must be a binary node string leftCategory = model.BasicCategory(tree.Children()[0].Label().Value()); string rightCategory = model.BasicCategory(tree.Children()[1].Label().Value()); if (model.op.combineClassification) { unaryCD[string.Empty] = unaryCD[string.Empty].Plus(localCD); } else { binaryCD.Put(leftCategory, rightCategory, binaryCD.Get(leftCategory, rightCategory).Plus(localCD)); } SimpleMatrix currentVectorDerivative = NeuralUtils.ElementwiseApplyTanhDerivative(currentVector); SimpleMatrix deltaFromClass = model.GetBinaryClassification(leftCategory, rightCategory).Transpose().Mult(deltaClass); deltaFromClass = deltaFromClass.ExtractMatrix(0, model.op.numHid, 0, 1).ElementMult(currentVectorDerivative); SimpleMatrix deltaFull = deltaFromClass.Plus(deltaUp); SimpleMatrix leftVector = RNNCoreAnnotations.GetNodeVector(tree.Children()[0]); SimpleMatrix rightVector = RNNCoreAnnotations.GetNodeVector(tree.Children()[1]); SimpleMatrix childrenVector = NeuralUtils.ConcatenateWithBias(leftVector, rightVector); SimpleMatrix W_df = deltaFull.Mult(childrenVector.Transpose()); binaryTD.Put(leftCategory, rightCategory, binaryTD.Get(leftCategory, rightCategory).Plus(W_df)); SimpleMatrix deltaDown; if (model.op.useTensors) { SimpleTensor Wt_df = GetTensorGradient(deltaFull, leftVector, rightVector); binaryTensorTD.Put(leftCategory, rightCategory, binaryTensorTD.Get(leftCategory, rightCategory).Plus(Wt_df)); deltaDown = ComputeTensorDeltaDown(deltaFull, leftVector, rightVector, model.GetBinaryTransform(leftCategory, rightCategory), model.GetBinaryTensor(leftCategory, rightCategory)); } else { deltaDown = model.GetBinaryTransform(leftCategory, rightCategory).Transpose().Mult(deltaFull); } SimpleMatrix leftDerivative = NeuralUtils.ElementwiseApplyTanhDerivative(leftVector); SimpleMatrix rightDerivative = NeuralUtils.ElementwiseApplyTanhDerivative(rightVector); SimpleMatrix leftDeltaDown = deltaDown.ExtractMatrix(0, deltaFull.NumRows(), 0, 1); SimpleMatrix rightDeltaDown = deltaDown.ExtractMatrix(deltaFull.NumRows(), deltaFull.NumRows() * 2, 0, 1); BackpropDerivativesAndError(tree.Children()[0], binaryTD, binaryCD, binaryTensorTD, unaryCD, wordVectorD, leftDerivative.ElementMult(leftDeltaDown)); BackpropDerivativesAndError(tree.Children()[1], binaryTD, binaryCD, binaryTensorTD, unaryCD, wordVectorD, rightDerivative.ElementMult(rightDeltaDown)); } }