/// <summary> /// Creates a new model with the specified parameters, outcome names, and predicate/feature labels. /// </summary> /// <param name="parameters">The parameters of the model.</param> /// <param name="predLabels">The names of the predicates used in this model.</param> /// <param name="outcomeNames">The names of the outcomes this model predicts.</param> /// <param name="correctionConstant">The maximum number of active features which occur in an event.</param> /// <param name="correctionParam">The parameter associated with the correction feature.</param> /// <param name="prior">The prior to be used with this model.</param> public GISModel( Context[] parameters, string[] predLabels, string[] outcomeNames, int correctionConstant, double correctionParam, IPrior prior) : base(parameters, predLabels, outcomeNames, correctionConstant, correctionParam) { this.prior = prior; this.prior.SetLabels(outcomeNames, predLabels); ModelType = ModelType.Maxent; }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="indexer">The object which will be used for event compilation.</param> /// <param name="smoothing">Defines whether the created trainer will use smoothing while training the model.</param> /// <param name="modelPrior">The prior distribution for the model.</param> /// <param name="cutoff">The number of times a predicate must occur to be used in a model.</param> /// <param name="threads">The number of threads to use during the training.</param> /// <returns>The newly trained model, which can be used immediately or saved to disk using a <see cref="GISModelWriter"/> object.</returns> public static GISModel TrainModel( int iterations, IDataIndexer indexer, bool smoothing, IPrior modelPrior, int cutoff, int threads) { var trainer = new GISTrainer { Smoothing = smoothing, SmoothingObservation = SmoothingObservation }; if (modelPrior == null) { modelPrior = new UniformPrior(); } return(trainer.TrainModel(iterations, indexer, modelPrior, cutoff, threads)); }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="indexer">The object which will be used for event compilation.</param> /// <param name="smoothing">Defines whether the created trainer will use smoothing while training the model.</param> /// <param name="modelPrior">The prior distribution for the model.</param> /// <param name="cutoff">The number of times a predicate must occur to be used in a model.</param> /// <returns>The newly trained model, which can be used immediately or saved to disk using a <see cref="GISModelWriter"/> object.</returns> public static GISModel TrainModel(int iterations, IDataIndexer indexer, bool smoothing, IPrior modelPrior, int cutoff) { return(TrainModel(iterations, indexer, smoothing, modelPrior, cutoff, 1)); }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="di">The data indexer used to compress events in memory.</param> /// <param name="modelPrior">The prior distribution used to train this model.</param> /// <param name="modelCutoff">The number of times a feature must occur to be included.</param> /// <param name="threads">The number of threads used to train this model.</param> /// <returns>The newly trained model, which can be used immediately or saved to disk using an <see cref="GISModelWriter"/> object.</returns> public GISModel TrainModel(int iterations, IDataIndexer di, IPrior modelPrior, int modelCutoff, int threads) { if (threads <= 0) throw new ArgumentOutOfRangeException("threads", threads, @"Threads must be at least one or greater."); modelExpects = new MutableContext[threads][]; info.Append("Trained using GIS algorithm.\n\n"); // Executes the data indexer di.Execute(); // Incorporate all of the needed info. Display("Incorporating indexed data for training..."); contexts = di.GetContexts(); values = di.Values; cutoff = modelCutoff; predicateCounts = di.GetPredCounts(); numTimesEventsSeen = di.GetNumTimesEventsSeen(); numUniqueEvents = contexts.Length; prior = modelPrior; // determine the correction constant and its inverse double correctionConstant = 0; for (int ci = 0; ci < contexts.Length; ci++) { if (values == null || values[ci] == null) { if (contexts[ci].Length > correctionConstant) { correctionConstant = contexts[ci].Length; } } else { var cl = values[ci][0]; for (var vi = 1; vi < values[ci].Length; vi++) { cl += values[ci][vi]; } if (cl > correctionConstant) { correctionConstant = cl; } } } Display("done."); outcomeLabels = di.GetOutcomeLabels(); outcomeList = di.GetOutcomeList(); numOutcomes = outcomeLabels.Length; predLabels = di.GetPredLabels(); prior.SetLabels(outcomeLabels, predLabels); numPreds = predLabels.Length; info.Append("Number of Event Tokens: {0}\n", numUniqueEvents); info.Append(" Number of Outcomes: {0}\n", numOutcomes); info.Append(" Number of Predicates: {0}\n", numPreds); Display("\tNumber of Event Tokens: " + numUniqueEvents); Display("\t Number of Outcomes: " + numOutcomes); Display("\t Number of Predicates: " + numPreds); // set up feature arrays //var predCount = new float[numPreds][numOutcomes]; var predCount = new float[numPreds][]; for (int ti = 0; ti < numUniqueEvents; ti++) { for (int j = 0; j < contexts[ti].Length; j++) { if (predCount[contexts[ti][j]] == null) { predCount[contexts[ti][j]] = new float[numOutcomes]; } if (values != null && values[ti] != null) { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti]*values[ti][j]; } else { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti]; } } } // ReSharper disable once RedundantAssignment di = null; // Get the observed expectations of the features. Strictly speaking, // we should divide the counts by the number of Tokens, but because of // the way the model's expectations are approximated in the // implementation, this is canceled out when we compute the next // iteration of a parameter, making the extra divisions wasteful. param = new MutableContext[numPreds]; for (var i = 0; i < modelExpects.Length; i++) modelExpects[i] = new MutableContext[numPreds]; observedExpects = new MutableContext[numPreds]; // The model does need the correction constant and the correction feature. The correction constant // is only needed during training, and the correction feature is not necessary. // For compatibility reasons the model contains form now on a correction constant of 1, // and a correction param 0. // ReSharper disable once CoVariantArrayConversion evalParams = new EvalParameters(param, 0, 1, numOutcomes); var activeOutcomes = new int[numOutcomes]; var allOutcomesPattern = new int[numOutcomes]; for (var oi = 0; oi < numOutcomes; oi++) { allOutcomesPattern[oi] = oi; } for (var pi = 0; pi < numPreds; pi++) { var numActiveOutcomes = 0; int[] outcomePattern; if (Smoothing) { numActiveOutcomes = numOutcomes; outcomePattern = allOutcomesPattern; } else { //determine active outcomes for (var oi = 0; oi < numOutcomes; oi++) { if (predCount[pi][oi] > 0 && predicateCounts[pi] >= cutoff) { activeOutcomes[numActiveOutcomes] = oi; numActiveOutcomes++; } } if (numActiveOutcomes == numOutcomes) { outcomePattern = allOutcomesPattern; } else { outcomePattern = new int[numActiveOutcomes]; for (var aoi = 0; aoi < numActiveOutcomes; aoi++) { outcomePattern[aoi] = activeOutcomes[aoi]; } } } param[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); foreach (MutableContext[] me in modelExpects) me[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); observedExpects[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); for (var aoi = 0; aoi < numActiveOutcomes; aoi++) { var oi = outcomePattern[aoi]; param[pi].SetParameter(aoi, 0.0); foreach (var modelExpect in modelExpects) { modelExpect[pi].SetParameter(aoi, 0.0); } if (predCount[pi][oi] > 0) { observedExpects[pi].SetParameter(aoi, predCount[pi][oi]); } else if (Smoothing) { observedExpects[pi].SetParameter(aoi, SmoothingObservation); } } } Display("...done."); /***************** Find the parameters ************************/ if (threads == 1) Display("Computing model parameters ..."); else Display("Computing model parameters in " + threads + " threads..."); FindParameters(iterations, correctionConstant); /*************** Create and return the model ******************/ // To be compatible with old models the correction constant is always 1 // ReSharper disable once CoVariantArrayConversion return new GISModel(param, predLabels, outcomeLabels, 1, evalParams.CorrectionParam) { info = TrainingInfo }; }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="di">The data indexer used to compress events in memory.</param> /// <param name="modelPrior">The prior distribution used to train this model.</param> /// <param name="modelCutoff">The number of times a feature must occur to be included.</param> /// <param name="threads">The number of threads used to train this model.</param> /// <returns>The newly trained model, which can be used immediately or saved to disk using an <see cref="GISModelWriter"/> object.</returns> public GISModel TrainModel(int iterations, IDataIndexer di, IPrior modelPrior, int modelCutoff, int threads) { if (threads <= 0) { throw new ArgumentOutOfRangeException("threads", threads, @"Threads must be at least one or greater."); } modelExpects = new MutableContext[threads][]; info.Append("Trained using GIS algorithm.\n\n"); // Executes the data indexer di.Execute(); // Incorporate all of the needed info. Display("Incorporating indexed data for training..."); contexts = di.GetContexts(); values = di.Values; cutoff = modelCutoff; predicateCounts = di.GetPredCounts(); numTimesEventsSeen = di.GetNumTimesEventsSeen(); numUniqueEvents = contexts.Length; prior = modelPrior; // determine the correction constant and its inverse double correctionConstant = 0; for (int ci = 0; ci < contexts.Length; ci++) { if (values == null || values[ci] == null) { if (contexts[ci].Length > correctionConstant) { correctionConstant = contexts[ci].Length; } } else { var cl = values[ci][0]; for (var vi = 1; vi < values[ci].Length; vi++) { cl += values[ci][vi]; } if (cl > correctionConstant) { correctionConstant = cl; } } } Display("done."); outcomeLabels = di.GetOutcomeLabels(); outcomeList = di.GetOutcomeList(); numOutcomes = outcomeLabels.Length; predLabels = di.GetPredLabels(); prior.SetLabels(outcomeLabels, predLabels); numPreds = predLabels.Length; info.Append("Number of Event Tokens: {0}\n", numUniqueEvents); info.Append(" Number of Outcomes: {0}\n", numOutcomes); info.Append(" Number of Predicates: {0}\n", numPreds); Display("\tNumber of Event Tokens: " + numUniqueEvents); Display("\t Number of Outcomes: " + numOutcomes); Display("\t Number of Predicates: " + numPreds); // set up feature arrays //var predCount = new float[numPreds][numOutcomes]; var predCount = new float[numPreds][]; for (int ti = 0; ti < numUniqueEvents; ti++) { for (int j = 0; j < contexts[ti].Length; j++) { if (predCount[contexts[ti][j]] == null) { predCount[contexts[ti][j]] = new float[numOutcomes]; } if (values != null && values[ti] != null) { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti] * values[ti][j]; } else { predCount[contexts[ti][j]][outcomeList[ti]] += numTimesEventsSeen[ti]; } } } // ReSharper disable once RedundantAssignment di = null; // Get the observed expectations of the features. Strictly speaking, // we should divide the counts by the number of Tokens, but because of // the way the model's expectations are approximated in the // implementation, this is canceled out when we compute the next // iteration of a parameter, making the extra divisions wasteful. param = new MutableContext[numPreds]; for (var i = 0; i < modelExpects.Length; i++) { modelExpects[i] = new MutableContext[numPreds]; } observedExpects = new MutableContext[numPreds]; // The model does need the correction constant and the correction feature. The correction constant // is only needed during training, and the correction feature is not necessary. // For compatibility reasons the model contains form now on a correction constant of 1, // and a correction param 0. // ReSharper disable once CoVariantArrayConversion evalParams = new EvalParameters(param, 0, 1, numOutcomes); var activeOutcomes = new int[numOutcomes]; var allOutcomesPattern = new int[numOutcomes]; for (var oi = 0; oi < numOutcomes; oi++) { allOutcomesPattern[oi] = oi; } for (var pi = 0; pi < numPreds; pi++) { var numActiveOutcomes = 0; int[] outcomePattern; if (Smoothing) { numActiveOutcomes = numOutcomes; outcomePattern = allOutcomesPattern; } else { //determine active outcomes for (var oi = 0; oi < numOutcomes; oi++) { if (predCount[pi][oi] > 0 && predicateCounts[pi] >= cutoff) { activeOutcomes[numActiveOutcomes] = oi; numActiveOutcomes++; } } if (numActiveOutcomes == numOutcomes) { outcomePattern = allOutcomesPattern; } else { outcomePattern = new int[numActiveOutcomes]; for (var aoi = 0; aoi < numActiveOutcomes; aoi++) { outcomePattern[aoi] = activeOutcomes[aoi]; } } } param[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); foreach (MutableContext[] me in modelExpects) { me[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); } observedExpects[pi] = new MutableContext(outcomePattern, new double[numActiveOutcomes]); for (var aoi = 0; aoi < numActiveOutcomes; aoi++) { var oi = outcomePattern[aoi]; param[pi].SetParameter(aoi, 0.0); foreach (var modelExpect in modelExpects) { modelExpect[pi].SetParameter(aoi, 0.0); } if (predCount[pi][oi] > 0) { observedExpects[pi].SetParameter(aoi, predCount[pi][oi]); } else if (Smoothing) { observedExpects[pi].SetParameter(aoi, SmoothingObservation); } } } Display("...done."); /***************** Find the parameters ************************/ if (threads == 1) { Display("Computing model parameters ..."); } else { Display("Computing model parameters in " + threads + " threads..."); } FindParameters(iterations, correctionConstant); /*************** Create and return the model ******************/ // To be compatible with old models the correction constant is always 1 // ReSharper disable once CoVariantArrayConversion return(new GISModel(param, predLabels, outcomeLabels, 1, evalParams.CorrectionParam) { info = TrainingInfo }); }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="indexer">The object which will be used for event compilation.</param> /// <param name="smoothing">Defines whether the created trainer will use smoothing while training the model.</param> /// <param name="modelPrior">The prior distribution for the model.</param> /// <param name="cutoff">The number of times a predicate must occur to be used in a model.</param> /// <param name="threads">The number of threads to use during the training.</param> /// <param name="monitor"> /// A evaluation monitor that can be used to listen the messages during the training or it can cancel the training operation. /// This argument can be a <c>null</c> value. /// </param> /// <returns>The newly trained model, which can be used immediately or saved to disk using a <see cref="GISModelWriter"/> object.</returns> public static GISModel TrainModel(int iterations, IDataIndexer indexer, bool smoothing, IPrior modelPrior, int cutoff, int threads, Monitor monitor) { var trainer = new GISTrainer(monitor) { Smoothing = smoothing, SmoothingObservation = SmoothingObservation }; if (modelPrior == null) { modelPrior = new UniformPrior(); } return trainer.TrainModel(iterations, indexer, modelPrior, cutoff, threads); }
/// <summary> /// Train a model using the GIS algorithm. /// </summary> /// <param name="iterations">The number of GIS iterations to perform.</param> /// <param name="indexer">The object which will be used for event compilation.</param> /// <param name="smoothing">Defines whether the created trainer will use smoothing while training the model.</param> /// <param name="modelPrior">The prior distribution for the model.</param> /// <param name="cutoff">The number of times a predicate must occur to be used in a model.</param> /// <returns>The newly trained model, which can be used immediately or saved to disk using a <see cref="GISModelWriter"/> object.</returns> public static GISModel TrainModel(int iterations, IDataIndexer indexer, bool smoothing, IPrior modelPrior, int cutoff) { return TrainModel(iterations, indexer, smoothing, modelPrior, cutoff, 1); }