/// <summary> /// <inheritDoc/> /// /// </summary> public virtual int[] GetPossibleValues(int position) { if (models != null) { return(models[0].GetPossibleValues(position)); } return(model1.GetPossibleValues(position)); }
public static int[] GetRandomSequence(ISequenceModel model) { int[] result = new int[model.Length()]; for (int i = 0; i < result.Length; i++) { int[] classes = model.GetPossibleValues(i); result[i] = classes[random.NextInt(classes.Length)]; } return(result); }
public FactoredSequenceModel(ISequenceModel model1, ISequenceModel model2) { //if (model1.leftWindow() != model2.leftWindow()) throw new RuntimeException("Two models must have same window size"); if (model1.GetPossibleValues(0).Length != model2.GetPossibleValues(0).Length) { throw new Exception("Two models must have the same number of classes"); } if (model1.Length() != model2.Length()) { throw new Exception("Two models must have the same sequence length"); } this.model1 = model1; this.model2 = model2; }
/// <summary>Samples each label in turn from left to right.</summary> /// <returns>an array containing the int tags of the best sequence</returns> public virtual int[] BestSequence(ISequenceModel ts) { // Also allocate space for rightWindow, just in case sequence model uses // it, even though this implementation doesn't. Probably it shouldn't, // or the left-to-right sampling is invalid, but our test classes do. int[] sample = new int[ts.Length() + ts.LeftWindow() + ts.RightWindow()]; for (int pos = ts.LeftWindow(); pos < sample.Length - ts.RightWindow(); pos++) { double[] scores = ts.ScoresOf(sample, pos); for (int i = 0; i < scores.Length; i++) { scores[i] = Math.Exp(scores[i]); } ArrayMath.Normalize(scores); int l = ArrayMath.SampleFromDistribution(scores); sample[pos] = ts.GetPossibleValues(pos)[l]; } return(sample); }
public virtual int[] BestSequence(ISequenceModel ts, int size) { int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); int padLength = length + leftWindow + rightWindow; int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } var newBeam = new Beam<TagSeq>(beamSize, ScoredComparator.ASCENDING_COMPARATOR); TagSeq initSeq = new TagSeq(); newBeam.Add(initSeq); for (int pos = 0; pos < padLength; pos++) { var oldBeam = newBeam; if (pos < leftWindow + rightWindow && exhaustiveStart) { newBeam = new Beam<TagSeq>(100000, ScoredComparator.ASCENDING_COMPARATOR); } else { newBeam = new Beam<TagSeq>(beamSize, ScoredComparator.ASCENDING_COMPARATOR); } for (IEnumerator beamI = oldBeam.GetEnumerator(); beamI.MoveNext(); ) { Console.Out.Write(@"#"); Console.Out.Flush(); TagSeq tagSeq = (TagSeq)beamI.Current; for (int nextTagNum = 0; nextTagNum < tagNum[pos]; nextTagNum++) { TagSeq nextSeq = tagSeq.Tclone(); if (pos >= leftWindow + rightWindow) { nextSeq.ExtendWith(tags[pos][nextTagNum], ts, size); } else { nextSeq.ExtendWith(tags[pos][nextTagNum]); } newBeam.Add(nextSeq); } } Console.Out.WriteLine(@" done"); if (recenter) { double max = Double.NegativeInfinity; for (IEnumerator beamI = newBeam.GetEnumerator(); beamI.MoveNext(); ) { TagSeq tagSeq = (TagSeq)beamI.Current; if (tagSeq.score > max) { max = tagSeq.score; } } for (IEnumerator beamI = newBeam.GetEnumerator(); beamI.MoveNext(); ) { TagSeq tagSeq = (TagSeq)beamI.Current; tagSeq.score -= max; } } } try { var enumerator = newBeam.GetEnumerator(); if (enumerator.MoveNext()) { TagSeq bestSeq = enumerator.Current; int[] seq = bestSeq.Tags(); return seq; } else return null; } catch (Exception e) { Console.Error.WriteLine(@"Beam empty -- no best sequence."); return null; } }
/// <summary> /// Runs the Viterbi algorithm on the sequence model, and then proceeds to efficiently /// backwards decode the best k label sequence assignments. /// </summary> /// <remarks> /// Runs the Viterbi algorithm on the sequence model, and then proceeds to efficiently /// backwards decode the best k label sequence assignments. /// This sequence finder only works on SequenceModel's with rightWindow == 0. /// </remarks> /// <param name="ts">The SequenceModel to find the best k label sequence assignments of</param> /// <param name="k">The number of top-scoring assignments to find.</param> /// <returns>A Counter with k entries that map from a sequence assignment (int array) to a double score</returns> public virtual ICounter <int[]> KBestSequences(ISequenceModel ts, int k) { // Set up tag options int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); if (rightWindow != 0) { throw new ArgumentException("KBestSequenceFinder only works with rightWindow == 0 not " + rightWindow); } int padLength = length + leftWindow + rightWindow; int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } int[] tempTags = new int[padLength]; // Set up product space sizes int[] productSizes = new int[padLength]; int curProduct = 1; for (int i = 0; i < leftWindow; i++) { curProduct *= tagNum[i]; } for (int pos_1 = leftWindow; pos_1 < padLength; pos_1++) { if (pos_1 > leftWindow + rightWindow) { curProduct /= tagNum[pos_1 - leftWindow - rightWindow - 1]; } // shift off curProduct *= tagNum[pos_1]; // shift on productSizes[pos_1 - rightWindow] = curProduct; } double[][] windowScore = new double[padLength][]; // Score all of each window's options for (int pos_2 = leftWindow; pos_2 < leftWindow + length; pos_2++) { windowScore[pos_2] = new double[productSizes[pos_2]]; Arrays.Fill(tempTags, tags[0][0]); for (int product = 0; product < productSizes[pos_2]; product++) { int p = product; int shift = 1; for (int curPos = pos_2; curPos >= pos_2 - leftWindow; curPos--) { tempTags[curPos] = tags[curPos][p % tagNum[curPos]]; p /= tagNum[curPos]; if (curPos > pos_2) { shift *= tagNum[curPos]; } } if (tempTags[pos_2] == tags[pos_2][0]) { // get all tags at once double[] scores = ts.ScoresOf(tempTags, pos_2); // fill in the relevant windowScores for (int t = 0; t < tagNum[pos_2]; t++) { windowScore[pos_2][product + t * shift] = scores[t]; } } } } // Set up score and backtrace arrays double[][][] score = new double[padLength][][]; int[][][][] trace = new int[padLength][][][]; int[][] numWaysToMake = new int[padLength][]; for (int pos_3 = 0; pos_3 < padLength; pos_3++) { score[pos_3] = new double[productSizes[pos_3]][]; trace[pos_3] = new int[productSizes[pos_3]][][]; // the 2 is for backtrace, and which of the k best for that backtrace numWaysToMake[pos_3] = new int[productSizes[pos_3]]; Arrays.Fill(numWaysToMake[pos_3], 1); for (int product = 0; product < productSizes[pos_3]; product++) { if (pos_3 > leftWindow) { // loop over possible predecessor types int sharedProduct = product / tagNum[pos_3]; int factor = productSizes[pos_3] / tagNum[pos_3]; numWaysToMake[pos_3][product] = 0; for (int newTagNum = 0; newTagNum < tagNum[pos_3 - leftWindow - 1] && numWaysToMake[pos_3][product] < k; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; numWaysToMake[pos_3][product] += numWaysToMake[pos_3 - 1][predProduct]; } if (numWaysToMake[pos_3][product] > k) { numWaysToMake[pos_3][product] = k; } } score[pos_3][product] = new double[numWaysToMake[pos_3][product]]; Arrays.Fill(score[pos_3][product], double.NegativeInfinity); trace[pos_3][product] = new int[numWaysToMake[pos_3][product]][]; Arrays.Fill(trace[pos_3][product], new int[] { -1, -1 }); } } // Do forward Viterbi algorithm // this is the hottest loop, so cache loop control variables hoping for a little speed.... // loop over the classification spot for (int pos_4 = leftWindow; pos_4 < posMax; pos_4++) { // loop over window product types for (int product = 0; product < productMax; product++) { // check for initial spot double[] scorePos = score[pos_4][product]; int[][] tracePos = trace[pos_4][product]; if (pos_4 == leftWindow) { // no predecessor type scorePos[0] = windowScore[pos_4][product]; } else { // loop over possible predecessor types/k-best int sharedProduct = product / tagNum[pos_4 + rightWindow]; int factor = productSizes[pos_4] / tagNum[pos_4 + rightWindow]; for (int newTagNum = 0; newTagNum < maxTagNum; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; double[] scorePosPrev = score[pos_4 - 1][predProduct]; for (int k1 = 0; k1 < scorePosPrev.Length; k1++) { double predScore = scorePosPrev[k1] + windowScore[pos_4][product]; if (predScore > scorePos[0]) { // new value higher then lowest value we should keep int k2 = Arrays.BinarySearch(scorePos, predScore); k2 = k2 < 0 ? -k2 - 2 : k2 - 1; // open a spot at k2 by shifting off the lowest value System.Array.Copy(scorePos, 1, scorePos, 0, k2); System.Array.Copy(tracePos, 1, tracePos, 0, k2); scorePos[k2] = predScore; tracePos[k2] = new int[] { predProduct, k1 }; } } } } } } // Project the actual tag sequence int[] whichDerivation = new int[k]; int[] bestCurrentProducts = new int[k]; double[] bestFinalScores = new double[k]; Arrays.Fill(bestFinalScores, double.NegativeInfinity); // just the last guy for (int product_1 = 0; product_1 < productSizes[padLength - 1]; product_1++) { double[] scorePos = score[padLength - 1][product_1]; for (int k1 = scorePos.Length - 1; k1 >= 0 && scorePos[k1] > bestFinalScores[0]; k1--) { int k2 = Arrays.BinarySearch(bestFinalScores, scorePos[k1]); k2 = k2 < 0 ? -k2 - 2 : k2 - 1; // open a spot at k2 by shifting off the lowest value System.Array.Copy(bestFinalScores, 1, bestFinalScores, 0, k2); System.Array.Copy(whichDerivation, 1, whichDerivation, 0, k2); System.Array.Copy(bestCurrentProducts, 1, bestCurrentProducts, 0, k2); bestCurrentProducts[k2] = product_1; whichDerivation[k2] = k1; bestFinalScores[k2] = scorePos[k1]; } } ClassicCounter <int[]> kBestWithScores = new ClassicCounter <int[]>(); for (int k1_1 = k - 1; k1_1 >= 0 && bestFinalScores[k1_1] > double.NegativeInfinity; k1_1--) { int lastProduct = bestCurrentProducts[k1_1]; for (int last = padLength - 1; last >= length - 1 && last >= 0; last--) { tempTags[last] = tags[last][lastProduct % tagNum[last]]; lastProduct /= tagNum[last]; } for (int pos_5 = leftWindow + length - 2; pos_5 >= leftWindow; pos_5--) { int bestNextProduct = bestCurrentProducts[k1_1]; bestCurrentProducts[k1_1] = trace[pos_5 + 1][bestNextProduct][whichDerivation[k1_1]][0]; whichDerivation[k1_1] = trace[pos_5 + 1][bestNextProduct][whichDerivation[k1_1]][1]; tempTags[pos_5 - leftWindow] = tags[pos_5 - leftWindow][bestCurrentProducts[k1_1] / (productSizes[pos_5] / tagNum[pos_5 - leftWindow])]; } kBestWithScores.SetCount(Arrays.CopyOf(tempTags, tempTags.Length), bestFinalScores[k1_1]); } return(kBestWithScores); }
private static int[] BestSequenceOld(ISequenceModel ts) { int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); int padLength = length + leftWindow + rightWindow; int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } int[] tempTags = new int[padLength]; int[] productSizes = new int[padLength]; int curProduct = 1; for (int i = 0; i < leftWindow + rightWindow; i++) curProduct *= tagNum[i]; for (int pos = leftWindow + rightWindow; pos < padLength; pos++) { if (pos > leftWindow + rightWindow) curProduct /= tagNum[pos - leftWindow - rightWindow - 1]; curProduct *= tagNum[pos]; productSizes[pos - rightWindow] = curProduct; } double[][] windowScore = new double[padLength][]; for (int pos = leftWindow; pos < leftWindow + length; pos++) { windowScore[pos] = new double[productSizes[pos]]; Arrays.Fill(tempTags, tags[0][0]); for (int product = 0; product < productSizes[pos]; product++) { int p = product; for (int curPos = pos + rightWindow; curPos >= pos - leftWindow; curPos--) { tempTags[curPos] = tags[curPos][p % tagNum[curPos]]; p /= tagNum[curPos]; } windowScore[pos][product] = ts.ScoreOf(tempTags, pos); } } double[][] score = new double[padLength][]; int[][] trace = new int[padLength][]; for (int pos = 0; pos < padLength; pos++) { score[pos] = new double[productSizes[pos]]; trace[pos] = new int[productSizes[pos]]; } for (int pos = leftWindow; pos < length + leftWindow; pos++) { for (int product = 0; product < productSizes[pos]; product++) { if (pos == leftWindow) { score[pos][product] = windowScore[pos][product]; trace[pos][product] = -1; } else { score[pos][product] = Double.NegativeInfinity; trace[pos][product] = -1; int sharedProduct = product / tagNum[pos + rightWindow]; int factor = productSizes[pos] / tagNum[pos + rightWindow]; for (int newTagNum = 0; newTagNum < tagNum[pos - leftWindow - 1]; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; double predScore = score[pos - 1][predProduct] + windowScore[pos][product]; if (predScore > score[pos][product]) { score[pos][product] = predScore; trace[pos][product] = predProduct; } } } } } double bestFinalScore = Double.NegativeInfinity; int bestCurrentProduct = -1; for (int product = 0; product < productSizes[leftWindow + length - 1]; product++) { if (score[leftWindow + length - 1][product] > bestFinalScore) { bestCurrentProduct = product; bestFinalScore = score[leftWindow + length - 1][product]; } } int lastProduct = bestCurrentProduct; for (int last = padLength - 1; last >= length - 1; last--) { tempTags[last] = tags[last][lastProduct % tagNum[last]]; lastProduct /= tagNum[last]; } for (int pos = leftWindow + length - 2; pos >= leftWindow; pos--) { int bestNextProduct = bestCurrentProduct; bestCurrentProduct = trace[pos + 1][bestNextProduct]; tempTags[pos - leftWindow] = tags[pos - leftWindow][bestCurrentProduct / (productSizes[pos] / tagNum[pos - leftWindow])]; } return tempTags; }
private static Pair<int[], Double> BestSequenceNew(ISequenceModel ts, double[][] linearConstraints) { int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); int padLength = length + leftWindow + rightWindow; if (linearConstraints != null && linearConstraints.Length != padLength) throw new Exception(@"linearConstraints.length (" + linearConstraints.Length + @") does not match padLength (" + padLength + @") of SequenceModel" + @", length==" + length + @", leftW=" + leftWindow + @", rightW=" + rightWindow); int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; if (DEBUG) { Console.Error.WriteLine(@"Doing bestSequence length " + length + @"; leftWin " + leftWindow + @"; rightWin " + rightWindow + @"; padLength " + padLength); } for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; if (DEBUG) { Console.Error.WriteLine(@"There are " + tagNum[pos] + @" values at position " + pos + @": " + Arrays.ToString(tags[pos])); } } int[] tempTags = new int[padLength]; int[] productSizes = new int[padLength]; int curProduct = 1; for (int i = 0; i < leftWindow + rightWindow; i++) { curProduct *= tagNum[i]; } for (int pos = leftWindow + rightWindow; pos < padLength; pos++) { if (pos > leftWindow + rightWindow) { curProduct /= tagNum[pos - leftWindow - rightWindow - 1]; } curProduct *= tagNum[pos]; productSizes[pos - rightWindow] = curProduct; } double[][] windowScore = new double[padLength][]; for (int pos = leftWindow; pos < leftWindow + length; pos++) { if (DEBUG) { Console.Error.WriteLine(@"scoring word " + pos + @" / " + (leftWindow + length) + @", productSizes = " + productSizes[pos] + @", tagNum = " + tagNum[pos] + @"..."); } windowScore[pos] = new double[productSizes[pos]]; Arrays.Fill(tempTags, tags[0][0]); if (DEBUG) { Console.Error.WriteLine(@"windowScore[" + pos + @"] has size (productSizes[pos]) " + windowScore[pos].Length); } for (int product = 0; product < productSizes[pos]; product++) { int p = product; int shift = 1; for (int curPos = pos + rightWindow; curPos >= pos - leftWindow; curPos--) { tempTags[curPos] = tags[curPos][p % tagNum[curPos]]; p /= tagNum[curPos]; if (curPos > pos) { shift *= tagNum[curPos]; } } if (tempTags[pos] == tags[pos][0]) { double[] scores = ts.ScoresOf(tempTags, pos); if (DEBUG) { Console.Error.WriteLine(@"Matched at array index [product] " + product + @"; tempTags[pos] == tags[pos][0] == " + tempTags[pos]); } if (DEBUG) { Console.Error.WriteLine(@"For pos " + pos + @" scores.length is " + scores.Length + @"; tagNum[pos] = " + tagNum[pos] + @"; windowScore[pos].length = " + windowScore[pos].Length); } if (DEBUG) { Console.Error.WriteLine(@"scores: " + Arrays.ToString(scores)); } for (int t = 0; t < tagNum[pos]; t++) { if (DEBUG) { Console.Error.WriteLine(@"Setting value of windowScore[" + pos + @"][" + product + @"+" + t + @"*" + shift + @"] = " + scores[t]); } windowScore[pos][product + t * shift] = scores[t]; } } } } double[][] score = new double[padLength][]; int[][] trace = new int[padLength][]; for (int pos = 0; pos < padLength; pos++) { score[pos] = new double[productSizes[pos]]; trace[pos] = new int[productSizes[pos]]; } for (int pos = leftWindow; pos < length + leftWindow; pos++) { for (int product = 0; product < productSizes[pos]; product++) { if (pos == leftWindow) { score[pos][product] = windowScore[pos][product]; if (linearConstraints != null) { if (DEBUG && linearConstraints[pos][product % tagNum[pos]] != 0) Console.Error.WriteLine(@"Applying linear constraints=" + linearConstraints[pos][product % tagNum[pos]] + @" to preScore=" + windowScore[pos][product] + @" at pos=" + pos + @" for tag=" + (product % tagNum[pos])); score[pos][product] += linearConstraints[pos][product % tagNum[pos]]; } trace[pos][product] = -1; } else { score[pos][product] = Double.NegativeInfinity; trace[pos][product] = -1; int sharedProduct = product / tagNum[pos + rightWindow]; int factor = productSizes[pos] / tagNum[pos + rightWindow]; for (int newTagNum = 0; newTagNum < tagNum[pos - leftWindow - 1]; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; double predScore = score[pos - 1][predProduct] + windowScore[pos][product]; if (linearConstraints != null) { if (DEBUG && pos == 2 && linearConstraints[pos][product % tagNum[pos]] != 0) { Console.Error.WriteLine(@"Applying linear constraints=" + linearConstraints[pos][product % tagNum[pos]] + @" to preScore=" + predScore + @" at pos=" + pos + @" for tag=" + (product % tagNum[pos])); Console.Error.WriteLine(@"predScore:" + predScore + @" = score[" + (pos - 1) + @"][" + predProduct + @"]:" + score[pos - 1][predProduct] + @" + windowScore[" + pos + @"][" + product + @"]:" + windowScore[pos][product]); } predScore += linearConstraints[pos][product % tagNum[pos]]; } if (predScore > score[pos][product]) { score[pos][product] = predScore; trace[pos][product] = predProduct; } } } } } double bestFinalScore = Double.NegativeInfinity; int bestCurrentProduct = -1; for (int product = 0; product < productSizes[leftWindow + length - 1]; product++) { if (score[leftWindow + length - 1][product] > bestFinalScore) { bestCurrentProduct = product; bestFinalScore = score[leftWindow + length - 1][product]; } } int lastProduct = bestCurrentProduct; for (int last = padLength - 1; last >= length - 1 && last >= 0; last--) { tempTags[last] = tags[last][lastProduct % tagNum[last]]; lastProduct /= tagNum[last]; } for (int pos = leftWindow + length - 2; pos >= leftWindow; pos--) { int bestNextProduct = bestCurrentProduct; bestCurrentProduct = trace[pos + 1][bestNextProduct]; tempTags[pos - leftWindow] = tags[pos - leftWindow][bestCurrentProduct / (productSizes[pos] / tagNum[pos - leftWindow])]; } return new Pair<int[], Double>(tempTags, bestFinalScore); }
public virtual int[] BestSequence(ISequenceModel ts, int size) { // Set up tag options int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); int padLength = length + leftWindow + rightWindow; int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } Beam newBeam = new Beam(beamSize, ScoredComparator.AscendingComparator); BeamBestSequenceFinder.TagSeq initSeq = new BeamBestSequenceFinder.TagSeq(); newBeam.Add(initSeq); for (int pos_1 = 0; pos_1 < padLength; pos_1++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } //System.out.println("scoring word " + pos + " / " + (leftWindow + length) + ", tagNum = " + tagNum[pos] + "..."); //System.out.flush(); Beam oldBeam = newBeam; if (pos_1 < leftWindow + rightWindow && exhaustiveStart) { newBeam = new Beam(100000, ScoredComparator.AscendingComparator); } else { newBeam = new Beam(beamSize, ScoredComparator.AscendingComparator); } // each hypothesis gets extended and beamed foreach (object anOldBeam in oldBeam) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } // System.out.print("#"); System.out.flush(); BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)anOldBeam; for (int nextTagNum = 0; nextTagNum < tagNum[pos_1]; nextTagNum++) { BeamBestSequenceFinder.TagSeq nextSeq = tagSeq.Tclone(); if (pos_1 >= leftWindow + rightWindow) { nextSeq.ExtendWith(tags[pos_1][nextTagNum], ts, size); } else { nextSeq.ExtendWith(tags[pos_1][nextTagNum]); } //System.out.println("Created: "+nextSeq.score()+" %% "+arrayToString(nextSeq.tags(), nextSeq.size())); newBeam.Add(nextSeq); } } // System.out.println("Beam size: "+newBeam.size()+" of "+beamSize); //System.out.println("Best is: "+((Scored)newBeam.iterator().next()).score()); // System.out.println(" done"); if (recenter) { double max = double.NegativeInfinity; foreach (object aNewBeam1 in newBeam) { BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)aNewBeam1; if (tagSeq.score > max) { max = tagSeq.score; } } foreach (object aNewBeam in newBeam) { BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)aNewBeam; tagSeq.score -= max; } } } try { BeamBestSequenceFinder.TagSeq bestSeq = (BeamBestSequenceFinder.TagSeq)newBeam.GetEnumerator().Current; int[] seq = bestSeq.Tags(); return(seq); } catch (NoSuchElementException) { log.Info("Beam empty -- no best sequence."); return(null); } }
public static DFSA <string, int> GetGraph(ISequenceModel ts, IIndex <string> classIndex) { DFSA <string, int> viterbiSearchGraph = new DFSA <string, int>(null); // Set up tag options int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); System.Diagnostics.Debug.Assert((rightWindow == 0)); int padLength = length + leftWindow + rightWindow; // NOTE: tags[i][j] : i is index into pos, and j into product int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } // Set up Viterbi search graph: DFSAState <string, int>[][] graphStates = null; DFSAState <string, int> startState = null; DFSAState <string, int> endState = null; if (viterbiSearchGraph != null) { int stateId = -1; startState = new DFSAState <string, int>(++stateId, viterbiSearchGraph, 0.0); viterbiSearchGraph.SetInitialState(startState); graphStates = new DFSAState[length][]; for (int pos_1 = 0; pos_1 < length; ++pos_1) { //System.err.printf("%d states at pos %d\n",tags[pos].length,pos); graphStates[pos_1] = new DFSAState[tags[pos_1].Length]; for (int product = 0; product < tags[pos_1].Length; ++product) { graphStates[pos_1][product] = new DFSAState <string, int>(++stateId, viterbiSearchGraph); } } // Accepting state: endState = new DFSAState <string, int>(++stateId, viterbiSearchGraph, 0.0); endState.SetAccepting(true); } int[] tempTags = new int[padLength]; // Set up product space sizes int[] productSizes = new int[padLength]; int curProduct = 1; for (int i = 0; i < leftWindow; i++) { curProduct *= tagNum[i]; } for (int pos_2 = leftWindow; pos_2 < padLength; pos_2++) { if (pos_2 > leftWindow + rightWindow) { curProduct /= tagNum[pos_2 - leftWindow - rightWindow - 1]; } // shift off curProduct *= tagNum[pos_2]; // shift on productSizes[pos_2 - rightWindow] = curProduct; } double[][] windowScore = new double[padLength][]; // Score all of each window's options for (int pos_3 = leftWindow; pos_3 < leftWindow + length; pos_3++) { windowScore[pos_3] = new double[productSizes[pos_3]]; Arrays.Fill(tempTags, tags[0][0]); for (int product = 0; product < productSizes[pos_3]; product++) { int p = product; int shift = 1; for (int curPos = pos_3; curPos >= pos_3 - leftWindow; curPos--) { tempTags[curPos] = tags[curPos][p % tagNum[curPos]]; p /= tagNum[curPos]; if (curPos > pos_3) { shift *= tagNum[curPos]; } } if (tempTags[pos_3] == tags[pos_3][0]) { // get all tags at once double[] scores = ts.ScoresOf(tempTags, pos_3); // fill in the relevant windowScores for (int t = 0; t < tagNum[pos_3]; t++) { windowScore[pos_3][product + t * shift] = scores[t]; } } } } // loop over the classification spot for (int pos_4 = leftWindow; pos_4 < length + leftWindow; pos_4++) { // loop over window product types for (int product = 0; product < productSizes[pos_4]; product++) { if (pos_4 == leftWindow) { // all nodes in the first spot link to startState: int curTag = tags[pos_4][product % tagNum[pos_4]]; //System.err.printf("pos=%d, product=%d, tag=%d score=%.3f\n",pos,product,curTag,windowScore[pos][product]); DFSATransition <string, int> tr = new DFSATransition <string, int>(string.Empty, startState, graphStates[pos_4][product], classIndex.Get(curTag), string.Empty, -windowScore[pos_4][product]); startState.AddTransition(tr); } else { int sharedProduct = product / tagNum[pos_4 + rightWindow]; int factor = productSizes[pos_4] / tagNum[pos_4 + rightWindow]; for (int newTagNum = 0; newTagNum < tagNum[pos_4 - leftWindow - 1]; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; int predTag = tags[pos_4 - 1][predProduct % tagNum[pos_4 - 1]]; int curTag = tags[pos_4][product % tagNum[pos_4]]; //log.info("pos: "+pos); //log.info("product: "+product); //System.err.printf("pos=%d-%d, product=%d-%d, tag=%d-%d score=%.3f\n",pos-1,pos,predProduct,product,predTag,curTag, // windowScore[pos][product]); DFSAState <string, int> sourceState = graphStates[pos_4 - leftWindow][predTag]; DFSAState <string, int> destState = (pos_4 - leftWindow + 1 == graphStates.Length) ? endState : graphStates[pos_4 - leftWindow + 1][curTag]; DFSATransition <string, int> tr = new DFSATransition <string, int>(string.Empty, sourceState, destState, classIndex.Get(curTag), string.Empty, -windowScore[pos_4][product]); graphStates[pos_4 - leftWindow][predTag].AddTransition(tr); } } } } return(viterbiSearchGraph); }
private static Pair <int[], double> BestSequence(ISequenceModel ts, double[][] linearConstraints) { // Set up tag options int length = ts.Length(); int leftWindow = ts.LeftWindow(); int rightWindow = ts.RightWindow(); int padLength = length + leftWindow + rightWindow; if (linearConstraints != null && linearConstraints.Length != padLength) { throw new Exception("linearConstraints.length (" + linearConstraints.Length + ") does not match padLength (" + padLength + ") of SequenceModel" + ", length==" + length + ", leftW=" + leftWindow + ", rightW=" + rightWindow); } int[][] tags = new int[padLength][]; int[] tagNum = new int[padLength]; for (int pos = 0; pos < padLength; pos++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } tags[pos] = ts.GetPossibleValues(pos); tagNum[pos] = tags[pos].Length; } int[] tempTags = new int[padLength]; // Set up product space sizes int[] productSizes = new int[padLength]; int curProduct = 1; for (int i = 0; i < leftWindow + rightWindow; i++) { curProduct *= tagNum[i]; } for (int pos_1 = leftWindow + rightWindow; pos_1 < padLength; pos_1++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } if (pos_1 > leftWindow + rightWindow) { curProduct /= tagNum[pos_1 - leftWindow - rightWindow - 1]; } // shift off curProduct *= tagNum[pos_1]; // shift on productSizes[pos_1 - rightWindow] = curProduct; } // Score all of each window's options double[][] windowScore = new double[padLength][]; for (int pos_2 = leftWindow; pos_2 < leftWindow + length; pos_2++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } windowScore[pos_2] = new double[productSizes[pos_2]]; Arrays.Fill(tempTags, tags[0][0]); for (int product = 0; product < productSizes[pos_2]; product++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } int p = product; int shift = 1; for (int curPos = pos_2 + rightWindow; curPos >= pos_2 - leftWindow; curPos--) { tempTags[curPos] = tags[curPos][p % tagNum[curPos]]; p /= tagNum[curPos]; if (curPos > pos_2) { shift *= tagNum[curPos]; } } // Here now you get ts.scoresOf() for all classifications at a position at once, whereas the old code called ts.scoreOf() on each item. // CDM May 2007: The way this is done gives incorrect results if there are repeated values in the values of ts.getPossibleValues(pos) -- in particular if the first value of the array is repeated later. I tried replacing it with the modulo version, but that only worked for left-to-right, not bidirectional inference, but I still think that if you sorted things out, you should be able to do it with modulos and the result would be conceptually simpler and robust to repeated values. But in the meantime, I fixed the POS tagger to not give repeated values (which was a bug in the tagger). if (tempTags[pos_2] == tags[pos_2][0]) { // get all tags at once double[] scores = ts.ScoresOf(tempTags, pos_2); // fill in the relevant windowScores for (int t = 0; t < tagNum[pos_2]; t++) { windowScore[pos_2][product + t * shift] = scores[t]; } } } } // Set up score and backtrace arrays double[][] score = new double[padLength][]; int[][] trace = new int[padLength][]; for (int pos_3 = 0; pos_3 < padLength; pos_3++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } score[pos_3] = new double[productSizes[pos_3]]; trace[pos_3] = new int[productSizes[pos_3]]; } // Do forward Viterbi algorithm // loop over the classification spot //log.info(); for (int pos_4 = leftWindow; pos_4 < length + leftWindow; pos_4++) { //log.info("."); // loop over window product types for (int product = 0; product < productSizes[pos_4]; product++) { if (Thread.Interrupted()) { // Allow interrupting throw new RuntimeInterruptedException(); } // check for initial spot if (pos_4 == leftWindow) { // no predecessor type score[pos_4][product] = windowScore[pos_4][product]; if (linearConstraints != null) { score[pos_4][product] += linearConstraints[pos_4][product % tagNum[pos_4]]; } trace[pos_4][product] = -1; } else { // loop over possible predecessor types score[pos_4][product] = double.NegativeInfinity; trace[pos_4][product] = -1; int sharedProduct = product / tagNum[pos_4 + rightWindow]; int factor = productSizes[pos_4] / tagNum[pos_4 + rightWindow]; for (int newTagNum = 0; newTagNum < tagNum[pos_4 - leftWindow - 1]; newTagNum++) { int predProduct = newTagNum * factor + sharedProduct; double predScore = score[pos_4 - 1][predProduct] + windowScore[pos_4][product]; if (linearConstraints != null) { predScore += linearConstraints[pos_4][product % tagNum[pos_4]]; } if (predScore > score[pos_4][product]) { score[pos_4][product] = predScore; trace[pos_4][product] = predProduct; } } } } } // Project the actual tag sequence double bestFinalScore = double.NegativeInfinity; int bestCurrentProduct = -1; for (int product_1 = 0; product_1 < productSizes[leftWindow + length - 1]; product_1++) { if (score[leftWindow + length - 1][product_1] > bestFinalScore) { bestCurrentProduct = product_1; bestFinalScore = score[leftWindow + length - 1][product_1]; } } int lastProduct = bestCurrentProduct; for (int last = padLength - 1; last >= length - 1 && last >= 0; last--) { tempTags[last] = tags[last][lastProduct % tagNum[last]]; lastProduct /= tagNum[last]; } for (int pos_5 = leftWindow + length - 2; pos_5 >= leftWindow; pos_5--) { int bestNextProduct = bestCurrentProduct; bestCurrentProduct = trace[pos_5 + 1][bestNextProduct]; tempTags[pos_5 - leftWindow] = tags[pos_5 - leftWindow][bestCurrentProduct / (productSizes[pos_5] / tagNum[pos_5 - leftWindow])]; } return(new Pair <int[], double>(tempTags, bestFinalScore)); }