use of org.knime.base.node.mine.treeensemble2.model.MultiClassGradientBoostedTreesModel in project knime-core by knime.
the class LKGradientBoostedTreesLearner method learn.
/**
* {@inheritDoc}
*
* @throws ExecutionException
* @throws InterruptedException
*/
@Override
public MultiClassGradientBoostedTreesModel learn(final ExecutionMonitor exec) throws CanceledExecutionException, InterruptedException, ExecutionException {
final TreeData data = getData();
final TreeTargetNominalColumnData target = (TreeTargetNominalColumnData) data.getTargetColumn();
final NominalValueRepresentation[] classNomVals = target.getMetaData().getValues();
final int numClasses = classNomVals.length;
final String[] classLabels = new String[numClasses];
final int nrModels = getConfig().getNrModels();
final int nrRows = target.getNrRows();
final TreeModelRegression[][] models = new TreeModelRegression[nrModels][numClasses];
final ArrayList<ArrayList<Map<TreeNodeSignature, Double>>> coefficientMaps = new ArrayList<ArrayList<Map<TreeNodeSignature, Double>>>(nrModels);
// variables for parallelization
final ThreadPool tp = KNIMEConstants.GLOBAL_THREAD_POOL;
final AtomicReference<Throwable> learnThrowableRef = new AtomicReference<Throwable>();
final int procCount = 3 * Runtime.getRuntime().availableProcessors() / 2;
exec.setMessage("Transforming problem");
// transform the original k class classification problem into k regression problems
final TreeData[] actual = new TreeData[numClasses];
for (int i = 0; i < numClasses; i++) {
final double[] newTarget = calculateNewTarget(target, i);
actual[i] = createNumericDataFromArray(newTarget);
classLabels[i] = classNomVals[i].getNominalValue();
}
final RandomData rd = getConfig().createRandomData();
final double[][] previousFunctions = new double[numClasses][nrRows];
TreeNodeSignatureFactory signatureFactory = null;
final int maxLevels = getConfig().getMaxLevels();
if (maxLevels < TreeEnsembleLearnerConfiguration.MAX_LEVEL_INFINITE) {
int capacity = IntMath.pow(2, maxLevels - 1);
signatureFactory = new TreeNodeSignatureFactory(capacity);
} else {
signatureFactory = new TreeNodeSignatureFactory();
}
exec.setMessage("Learn trees");
for (int i = 0; i < nrModels; i++) {
final Semaphore semaphore = new Semaphore(procCount);
final ArrayList<Map<TreeNodeSignature, Double>> classCoefficientMaps = new ArrayList<Map<TreeNodeSignature, Double>>(numClasses);
// prepare calculation of pseudoResiduals
final double[][] probs = new double[numClasses][nrRows];
for (int r = 0; r < nrRows; r++) {
double sumExpF = 0;
for (int j = 0; j < numClasses; j++) {
sumExpF += Math.exp(previousFunctions[j][r]);
}
for (int j = 0; j < numClasses; j++) {
probs[j][r] = Math.exp(previousFunctions[j][r]) / sumExpF;
}
}
final Future<?>[] treeCoefficientMapPairs = new Future<?>[numClasses];
for (int j = 0; j < numClasses; j++) {
checkThrowable(learnThrowableRef);
final RandomData rdSingle = TreeEnsembleLearnerConfiguration.createRandomData(rd.nextLong(Long.MIN_VALUE, Long.MAX_VALUE));
final ExecutionMonitor subExec = exec.createSubProgress(0.0);
semaphore.acquire();
treeCoefficientMapPairs[j] = tp.enqueue(new TreeLearnerCallable(rdSingle, probs[j], actual[j], subExec, numClasses, previousFunctions[j], semaphore, learnThrowableRef, signatureFactory));
}
for (int j = 0; j < numClasses; j++) {
checkThrowable(learnThrowableRef);
semaphore.acquire();
final Pair<TreeModelRegression, Map<TreeNodeSignature, Double>> pair = (Pair<TreeModelRegression, Map<TreeNodeSignature, Double>>) treeCoefficientMapPairs[j].get();
models[i][j] = pair.getFirst();
classCoefficientMaps.add(pair.getSecond());
semaphore.release();
}
checkThrowable(learnThrowableRef);
coefficientMaps.add(classCoefficientMaps);
exec.setProgress((double) i / nrModels, "Finished level " + i + "/" + nrModels);
}
return MultiClassGradientBoostedTreesModel.createMultiClassGradientBoostedTreesModel(getConfig(), data.getMetaData(), models, data.getTreeType(), 0, numClasses, coefficientMaps, classLabels);
}
use of org.knime.base.node.mine.treeensemble2.model.MultiClassGradientBoostedTreesModel in project knime-core by knime.
the class TreeEnsembleModel method load.
public static TreeEnsembleModel load(final InputStream in) throws IOException {
// wrapping the argument (zip input) stream in a buffered stream
// reduces read operation from, e.g. 42s to 2s
TreeModelDataInputStream input = new TreeModelDataInputStream(new BufferedInputStream(new NonClosableInputStream(in)));
int version = input.readInt();
if (version > 20160114) {
throw new IOException("Tree Ensemble version " + version + " not supported");
}
byte ensembleType;
if (version == 20160114) {
ensembleType = input.readByte();
} else {
ensembleType = 'r';
}
TreeType type = TreeType.load(input);
TreeMetaData metaData = TreeMetaData.load(input);
int nrModels = input.readInt();
boolean containsClassDistribution;
if (version == 20121019) {
containsClassDistribution = true;
} else {
containsClassDistribution = input.readBoolean();
}
input.setContainsClassDistribution(containsClassDistribution);
AbstractTreeModel[] models = new AbstractTreeModel[nrModels];
boolean isRegression = metaData.isRegression();
if (ensembleType != 'r') {
isRegression = true;
}
final TreeBuildingInterner treeBuildingInterner = new TreeBuildingInterner();
for (int i = 0; i < nrModels; i++) {
AbstractTreeModel singleModel;
try {
singleModel = isRegression ? TreeModelRegression.load(input, metaData, treeBuildingInterner) : TreeModelClassification.load(input, metaData, treeBuildingInterner);
if (input.readByte() != 0) {
throw new IOException("Model not terminated by 0 byte");
}
} catch (IOException e) {
throw new IOException("Can't read tree model " + (i + 1) + "/" + nrModels + ": " + e.getMessage(), e);
}
models[i] = singleModel;
}
TreeEnsembleModel result;
switch(ensembleType) {
case 'r':
result = new TreeEnsembleModel(metaData, models, type, containsClassDistribution);
break;
case 'g':
result = new GradientBoostingModel(metaData, models, type, containsClassDistribution);
break;
case 't':
result = new GradientBoostedTreesModel(metaData, models, type, containsClassDistribution);
break;
case 'm':
result = new MultiClassGradientBoostedTreesModel(metaData, models, type, containsClassDistribution);
break;
default:
throw new IllegalStateException("Unknown ensemble type: '" + (char) ensembleType + "'");
}
result.loadData(input);
// does not close the method argument stream!!
input.close();
return result;
}
use of org.knime.base.node.mine.treeensemble2.model.MultiClassGradientBoostedTreesModel in project knime-core by knime.
the class ClassificationGBTModelImporter method importFromPMMLInternal.
/**
* {@inheritDoc}
*/
@Override
protected MultiClassGradientBoostedTreesModel importFromPMMLInternal(final MiningModel miningModel) {
Segmentation modelChain = miningModel.getSegmentation();
CheckUtils.checkArgument(modelChain.getMultipleModelMethod() == MULTIPLEMODELMETHOD.MODEL_CHAIN, "The top level segmentation should have multiple model method '%s' but has '%s'", MULTIPLEMODELMETHOD.MODEL_CHAIN, modelChain.getMultipleModelMethod());
List<List<TreeModelRegression>> trees = new ArrayList<>();
List<List<Map<TreeNodeSignature, Double>>> coefficientMaps = new ArrayList<>();
List<String> classLabels = new ArrayList<>();
List<Segment> segments = modelChain.getSegmentList();
for (int i = 0; i < segments.size() - 1; i++) {
Pair<List<TreeModelRegression>, List<Map<TreeNodeSignature, Double>>> gbtPair = processClassSegment(segments.get(i));
trees.add(gbtPair.getFirst());
coefficientMaps.add(gbtPair.getSecond());
classLabels.add(extractClassLabel(segments.get(i)));
}
double initialValue = extractInitialValue(segments.get(0));
return MultiClassGradientBoostedTreesModel.create(getMetaDataMapper().getTreeMetaData(), trees, coefficientMaps, initialValue, TreeType.Ordinary, classLabels);
}
use of org.knime.base.node.mine.treeensemble2.model.MultiClassGradientBoostedTreesModel in project knime-core by knime.
the class ClassificationGBTModelExporter method addSegmentation.
private void addSegmentation(final MiningModel miningModel, final int c) {
Segmentation seg = miningModel.addNewSegmentation();
MultiClassGradientBoostedTreesModel gbt = getGBTModel();
Collection<TreeModelRegression> trees = IntStream.range(0, gbt.getNrLevels()).mapToObj(i -> gbt.getModel(i, c)).collect(Collectors.toList());
Collection<Map<TreeNodeSignature, Double>> coefficientMaps = IntStream.range(0, gbt.getNrLevels()).mapToObj(i -> gbt.getCoefficientMap(i, c)).collect(Collectors.toList());
writeSumSegmentation(seg, trees, coefficientMaps);
}
use of org.knime.base.node.mine.treeensemble2.model.MultiClassGradientBoostedTreesModel in project knime-core by knime.
the class GradientBoostingClassificationPredictorNodeModel method configure.
/**
* {@inheritDoc}
*/
@Override
protected PortObjectSpec[] configure(final PortObjectSpec[] inSpecs) throws InvalidSettingsException {
TreeEnsembleModelPortObjectSpec modelSpec = (TreeEnsembleModelPortObjectSpec) inSpecs[0];
String targetColName = modelSpec.getTargetColumn().getName();
if (m_configuration == null) {
m_configuration = TreeEnsemblePredictorConfiguration.createDefault(false, targetColName);
} else if (!m_configuration.isChangePredictionColumnName()) {
m_configuration.setPredictionColumnName(TreeEnsemblePredictorConfiguration.getPredictColumnName(targetColName));
}
modelSpec.assertTargetTypeMatches(false);
DataTableSpec dataSpec = (DataTableSpec) inSpecs[1];
GradientBoostingPredictor<MultiClassGradientBoostedTreesModel> predictor = new GradientBoostingPredictor<>(null, modelSpec, dataSpec, m_configuration);
ColumnRearranger rearranger = predictor.getPredictionRearranger();
return new PortObjectSpec[] { rearranger.createSpec() };
}
Aggregations