/// <summary> /// Get the calibration summary in INI format /// </summary> private static string AddCalibrationToIni(IHost host, string ini, ICalibrator calibrator) { host.AssertValue(ini); host.AssertValueOrNull(calibrator); if (calibrator == null) { return(ini); } if (calibrator is PlattCalibrator) { string calibratorEvaluatorIni = IniFileUtils.GetCalibratorEvaluatorIni(ini, calibrator as PlattCalibrator); return(IniFileUtils.AddEvaluator(ini, calibratorEvaluatorIni)); } else { StringBuilder newSection = new StringBuilder(); newSection.AppendLine(); newSection.AppendLine(); newSection.AppendLine("[TLCCalibration]"); newSection.AppendLine("Type=" + calibrator.GetType().Name); return(ini + newSection); } }
/// <summary> /// Build a Bing TreeEnsemble .ini representation of the given predictor /// </summary> public static string LinearModelAsIni(ref VBuffer <Float> weights, Float bias, IPredictor predictor = null, RoleMappedSchema schema = null, PlattCalibrator calibrator = null) { // TODO: Might need to consider a max line length for the Weights list, requiring us to split it up into // multiple evaluators StringBuilder inputBuilder = new StringBuilder(); StringBuilder aggregatedNodesBuilder = new StringBuilder("Nodes="); StringBuilder weightsBuilder = new StringBuilder("Weights="); var featureNames = default(VBuffer <ReadOnlyMemory <char> >); MetadataUtils.GetSlotNames(schema, RoleMappedSchema.ColumnRole.Feature, weights.Length, ref featureNames); int numNonZeroWeights = 0; const string weightsSep = "\t"; VBufferUtils.ForEachDefined(ref weights, (idx, value) => { if (Math.Abs(value - 0) >= Epsilon) { numNonZeroWeights++; var name = featureNames.GetItemOrDefault(idx); inputBuilder.AppendLine("[Input:" + numNonZeroWeights + "]"); inputBuilder.AppendLine("Name=" + (featureNames.Count == 0 ? "Feature_" + idx : name.IsEmpty ? $"f{idx}" : name.ToString())); inputBuilder.AppendLine("Transform=linear"); inputBuilder.AppendLine("Slope=1"); inputBuilder.AppendLine("Intercept=0"); inputBuilder.AppendLine(); aggregatedNodesBuilder.Append("I:" + numNonZeroWeights + weightsSep); weightsBuilder.Append(value + weightsSep); } }); StringBuilder builder = new StringBuilder(); builder.AppendLine("[TreeEnsemble]"); builder.AppendLine("Inputs=" + numNonZeroWeights); builder.AppendLine("Evaluators=1"); builder.AppendLine(); builder.AppendLine(inputBuilder.ToString()); builder.AppendLine("[Evaluator:1]"); builder.AppendLine("EvaluatorType=Aggregator"); builder.AppendLine("Type=Linear"); builder.AppendLine("Bias=" + bias); builder.AppendLine("NumNodes=" + numNonZeroWeights); builder.AppendLine(aggregatedNodesBuilder.ToString().Trim()); builder.AppendLine(weightsBuilder.ToString().Trim()); #if false // REVIEW: This should be done by the caller using the actual training args! builder.AppendLine(); builder.AppendLine("[Comments]"); builder.Append("Trained by TLC"); if (predictor != null) { builder.Append(" as /cl " + predictor.GetType().Name); if (predictor is IInitializable) { string settings = string.Join(";", (predictor as IInitializable).GetSettings()); if (!string.IsNullOrEmpty(settings)) { builder.Append(" /cls " + settings); } } } #endif string ini = builder.ToString(); // Add the calibration if the model was trained with calibration if (calibrator != null) { string calibratorEvaluatorIni = IniFileUtils.GetCalibratorEvaluatorIni(ini, calibrator); ini = IniFileUtils.AddEvaluator(ini, calibratorEvaluatorIni); } return(ini); }