/// <summary> /// Gets the negative log-likelihood at the given input vector. /// </summary> /// <param name="x">The input vector.</param> /// <returns>The negative log-likelihood.</returns> /// <exception cref="ArgumentException">The <paramref name="x"/> is invalid, its dimension is not equal to domain dimension.</exception> public virtual double ValueAt(double[] x) { if (x.Length != dimension) { throw new ArgumentException("x is invalid, its dimension is not equal to domain dimension.", nameof(x)); } int ci; double negLogLikelihood = 0; for (ci = 0; ci < numContexts; ci++) { int oi; for (oi = 0; oi < numOutcomes; oi++) { tempSums[oi] = 0; int ai; for (ai = 0; ai < contexts[ci].Length; ai++) { var vectorIndex = IndexOf(oi, contexts[ci][ai]); var predValue = values != null ? values[ci][ai] : 1.0; tempSums[oi] += predValue * x[vectorIndex]; } } var logSumOfExps = ArrayMath.LogSumOfExps(tempSums); negLogLikelihood -= (tempSums[outcomeList[ci]] - logSumOfExps) * numTimesEventsSeen[ci]; } return(negLogLikelihood); }
private void NegLLCompute(int threadIndex, int startIndex, int length, double[] x) { negLogLikelihoodThread[threadIndex] = 0; // Knuppe: In parallel we can't use the tempSums variable ;) var temp = new double[numOutcomes]; for (var ci = startIndex; ci < startIndex + length; ci++) { for (var oi = 0; oi < numOutcomes; oi++) { temp[oi] = 0; for (var ai = 0; ai < contexts[ci].Length; ai++) { var vectorIndex = IndexOf(oi, contexts[ci][ai]); var predValue = values != null ? values[ci][ai] : 1.0; temp[oi] += predValue * x[vectorIndex]; } } var logSumOfExps = ArrayMath.LogSumOfExps(temp); var outcome = outcomeList[ci]; negLogLikelihoodThread[threadIndex] -= (temp[outcome] - logSumOfExps) * numTimesEventsSeen[ci]; } }
/// <summary> /// Gets the gradient at the given input vector. /// </summary> /// <param name="x">The input vector.</param> /// <returns>The gradient value.</returns> /// <exception cref="System.ArgumentException">x is invalid, its dimension is not equal to domain dimension.;x</exception> /// <exception cref="ArgumentException">The <paramref name="x" /> is invalid, its dimension is not equal to domain dimension.</exception> public virtual double[] GradientAt(double[] x) { if (x.Length != dimension) { throw new ArgumentException("x is invalid, its dimension is not equal to domain dimension.", nameof(x)); } int ci; // Reset gradient for (var i = 0; i < gradient.Length; i++) { gradient[i] = 0; } for (ci = 0; ci < numContexts; ci++) { int oi; double predValue; int vectorIndex; int ai; for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = 0; for (ai = 0; ai < contexts[ci].Length; ai++) { vectorIndex = IndexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; expectation[oi] += predValue * x[vectorIndex]; } } var logSumOfExps = ArrayMath.LogSumOfExps(expectation); for (oi = 0; oi < numOutcomes; oi++) { expectation[oi] = Math.Exp(expectation[oi] - logSumOfExps); } for (oi = 0; oi < numOutcomes; oi++) { var empirical = outcomeList[ci] == oi ? 1 : 0; for (ai = 0; ai < contexts[ci].Length; ai++) { vectorIndex = IndexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; gradient[vectorIndex] += predValue * (expectation[oi] - empirical) * numTimesEventsSeen[ci]; } } } return(gradient); }
private void GradientCompute(int threadIndex, int startIndex, int length, double[] x) { var exp = new double[numOutcomes]; // Reset gradientThread Array.Clear(gradientThread[threadIndex], 0, gradientThread[threadIndex].Length); for (var ci = startIndex; ci < startIndex + length; ci++) { double predValue; int vectorIndex; for (var oi = 0; oi < numOutcomes; oi++) { exp[oi] = 0; for (var ai = 0; ai < contexts[ci].Length; ai++) { vectorIndex = IndexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; exp[oi] += predValue * x[vectorIndex]; } } var logSumOfExps = ArrayMath.LogSumOfExps(exp); for (var oi = 0; oi < numOutcomes; oi++) { exp[oi] = Math.Exp(exp[oi] - logSumOfExps); } for (var oi = 0; oi < numOutcomes; oi++) { var empirical = outcomeList[ci] == oi ? 1 : 0; for (var ai = 0; ai < contexts[ci].Length; ai++) { vectorIndex = IndexOf(oi, contexts[ci][ai]); predValue = values != null ? values[ci][ai] : 1.0; gradientThread[threadIndex][vectorIndex] += predValue * (exp[oi] - empirical) * numTimesEventsSeen[ci]; } } } }
/// <summary> /// Model evaluation which should be used during training to report model accuracy. /// </summary> /// <param name="context">Indices of the predicates which have been observed at the present decision point.</param> /// <param name="values">The weights of the predicates which have been observed at the present decision point.</param> /// <param name="probs">The probability for outcomes.</param> /// <param name="nOutcomes">The number of outcomes.</param> /// <param name="nPredLabels">The number of unique predicates.</param> /// <param name="parameters">The model parameters.</param> /// <returns>The normalized probabilities for the outcomes given the context.</returns> public static double[] Eval(int[] context, float[] values, double[] probs, int nOutcomes, int nPredLabels, double[] parameters) { for (var i = 0; i < context.Length; i++) { var predIdx = context[i]; var predValue = values != null ? values[i] : 1d; for (var oi = 0; oi < nOutcomes; oi++) { probs[oi] += predValue * parameters[oi * nPredLabels + predIdx]; } } var logSumExp = ArrayMath.LogSumOfExps(probs); for (var oi = 0; oi < nOutcomes; oi++) { probs[oi] = Math.Exp(probs[oi] - logSumExp); } return(probs); }
/// <summary> /// Model evaluation which should be used during inference. /// </summary> /// <param name="context">The predicates which have been observed at the present decision point.</param> /// <param name="values">The weights of the predicates which have been observed at the present decision point.</param> /// <param name="probs">The probability for outcomes.</param> /// <returns>The normalized probabilities for the outcomes given the context.</returns> public double[] Eval(string[] context, float[] values, double[] probs) { var ep = evalParameters.Parameters; for (var ci = 0; ci < context.Length; ci++) { var predIdx = GetPredIndex(context[ci]); if (predIdx < 0) { continue; } var predValue = 1d; if (values != null) { predValue = values[ci]; } var outcomes = ep[predIdx].Outcomes; var parameters = ep[predIdx].Parameters; for (var i = 0; i < outcomes.Length; i++) { probs[outcomes[i]] += predValue * parameters[i]; } } var logSumExp = ArrayMath.LogSumOfExps(probs); for (var oi = 0; oi < outcomeNames.Length; oi++) { probs[oi] = Math.Exp(probs[oi] - logSumExp); } return(probs); }