private double trainingStats(EvalParameters evalParams) { int numCorrect = 0; for (int ei = 0; ei < numUniqueEvents; ei++) { for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { double[] modelDistribution = new double[numOutcomes]; if (values != null) { PerceptronModel.eval(contexts[ei], values[ei], modelDistribution, evalParams, false); } else { PerceptronModel.eval(contexts[ei], null, modelDistribution, evalParams, false); } int max = maxIndex(modelDistribution); if (max == outcomeList[ei]) { numCorrect++; } } } double trainingAccuracy = (double)numCorrect / numEvents; display("Stats: (" + numCorrect + "/" + numEvents + ") " + trainingAccuracy + "\n"); return(trainingAccuracy); }
private MutableContext[] findParameters(int iterations, bool useAverage) { display("Performing " + iterations + " iterations.\n"); int[] allOutcomesPattern = new int[numOutcomes]; for (int oi = 0; oi < numOutcomes; oi++) { allOutcomesPattern[oi] = oi; } /// <summary> /// Stores the estimated parameter value of each predicate during iteration. </summary> MutableContext[] parameters = new MutableContext[numPreds]; for (int pi = 0; pi < numPreds; pi++) { parameters[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]); for (int aoi = 0; aoi < numOutcomes; aoi++) { parameters[pi].setParameter(aoi, 0.0); } } EvalParameters evalParams = new EvalParameters(parameters, numOutcomes); /// <summary> /// Stores the sum of parameter values of each predicate over many iterations. </summary> MutableContext[] summedParams = new MutableContext[numPreds]; if (useAverage) { for (int pi = 0; pi < numPreds; pi++) { summedParams[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]); for (int aoi = 0; aoi < numOutcomes; aoi++) { summedParams[pi].setParameter(aoi, 0.0); } } } // Keep track of the previous three accuracies. The difference of // the mean of these and the current training set accuracy is used // with tolerance to decide whether to stop. double prevAccuracy1 = 0.0; double prevAccuracy2 = 0.0; double prevAccuracy3 = 0.0; // A counter for the denominator for averaging. int numTimesSummed = 0; double stepsize = 1; for (int i = 1; i <= iterations; i++) { // Decrease the stepsize by a small amount. if (stepSizeDecrease != null) { stepsize *= 1 - stepSizeDecrease.GetValueOrDefault(); } displayIteration(i); int numCorrect = 0; for (int ei = 0; ei < numUniqueEvents; ei++) { int targetOutcome = outcomeList[ei]; for (int ni = 0; ni < this.numTimesEventsSeen[ei]; ni++) { // Compute the model's prediction according to the current parameters. double[] modelDistribution = new double[numOutcomes]; if (values != null) { PerceptronModel.eval(contexts[ei], values[ei], modelDistribution, evalParams, false); } else { PerceptronModel.eval(contexts[ei], null, modelDistribution, evalParams, false); } int maxOutcome = maxIndex(modelDistribution); // If the predicted outcome is different from the target // outcome, do the standard update: boost the parameters // associated with the target and reduce those associated // with the incorrect predicted outcome. if (maxOutcome != targetOutcome) { for (int ci = 0; ci < contexts[ei].Length; ci++) { int pi = contexts[ei][ci]; if (values == null) { parameters[pi].updateParameter(targetOutcome, stepsize); parameters[pi].updateParameter(maxOutcome, -stepsize); } else { parameters[pi].updateParameter(targetOutcome, stepsize * values[ei][ci]); parameters[pi].updateParameter(maxOutcome, -stepsize * values[ei][ci]); } } } // Update the counts for accuracy. if (maxOutcome == targetOutcome) { numCorrect++; } } } // Calculate the training accuracy and display. double trainingAccuracy = (double)numCorrect / numEvents; if (i < 10 || (i % 10) == 0) { display(". (" + numCorrect + "/" + numEvents + ") " + trainingAccuracy + "\n"); } // TODO: Make averaging configurable !!! bool doAveraging; if (useAverage && useSkippedlAveraging && (i < 20 || isPerfectSquare(i))) { doAveraging = true; } else if (useAverage) { doAveraging = true; } else { doAveraging = false; } if (doAveraging) { numTimesSummed++; for (int pi = 0; pi < numPreds; pi++) { for (int aoi = 0; aoi < numOutcomes; aoi++) { summedParams[pi].updateParameter(aoi, parameters[pi].Parameters[aoi]); } } } // If the tolerance is greater than the difference between the // current training accuracy and all of the previous three // training accuracies, stop training. if (Math.Abs(prevAccuracy1 - trainingAccuracy) < tolerance && Math.Abs(prevAccuracy2 - trainingAccuracy) < tolerance && Math.Abs(prevAccuracy3 - trainingAccuracy) < tolerance) { display("Stopping: change in training set accuracy less than " + tolerance + "\n"); break; } // Update the previous training accuracies. prevAccuracy1 = prevAccuracy2; prevAccuracy2 = prevAccuracy3; prevAccuracy3 = trainingAccuracy; } // Output the final training stats. trainingStats(evalParams); // Create averaged parameters if (useAverage) { for (int pi = 0; pi < numPreds; pi++) { for (int aoi = 0; aoi < numOutcomes; aoi++) { summedParams[pi].setParameter(aoi, summedParams[pi].Parameters[aoi] / numTimesSummed); } } return(summedParams); } else { return(parameters); } }