Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branch 170960975 #13484

Merged
merged 23 commits into from
Oct 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d0c76cd
Handle the absence of a fresh eval checkpoint in `run_local`.
isaprykin Oct 3, 2017
5123f29
Internal cleanup.
tensorflower-gardener Oct 3, 2017
d6e963b
SYCL: Fix build breakage introduced in
asimshankar Oct 3, 2017
6810566
Internal change to simplify prediction ops.
tensorflower-gardener Oct 3, 2017
94463f5
Preserve target function signature in custom_gradient decorator
akshayka Oct 3, 2017
b002c8b
[Grappler] Fold chains of reshapes.
Oct 3, 2017
08e266d
Pass activity_regularizer to __init__ instead of using the (now
tensorflower-gardener Oct 3, 2017
b925f85
Fast-path for EagerTensorBase.dtype
alextp Oct 3, 2017
ad37fa8
Refactor ExportStrategies into Exporters.
isaprykin Oct 3, 2017
0c8dbc1
matmul uses shape_tuple internally
alextp Oct 4, 2017
0068086
Introduce `tf.data` namespace.
tensorflower-gardener Oct 4, 2017
4cf6126
Improve TFGAN documentation.
tensorflower-gardener Oct 4, 2017
b959da9
Fixing CPU implementation of parallel_stack for tensors with non-zero…
jsimsa Oct 4, 2017
add6d2d
[tf-signal] Use tf.spectral.dct in mfccs_from_log_mel_spectrograms in…
rryan Oct 4, 2017
d4ea993
Removes unnecessary eager-mode call to convert_to_tensor in record_gr…
alextp Oct 4, 2017
de14fcb
Support evaluation in `_TrainingExecutor.run_master()`.
isaprykin Oct 4, 2017
b395257
Added comment re:behavior of listener in case of multiple saver hooks.
ispirmustafa Oct 4, 2017
93fa1af
Make graph_callable, defun tf_decorators
akshayka Oct 4, 2017
664dd08
Disable cluster_function_library_runtime_test on Mac OS as it is curr…
Oct 4, 2017
c31c118
Extend tf.contrib.bijector API to handle some non-injective transforms.
langmore Oct 4, 2017
bfaaefa
Update APIs for TPU Cluster Resolver to remove the custom API definit…
Oct 4, 2017
f9f037c
Bugfix to LSTMBlockCell and friends: clipping is off by default.
ebrevdo Oct 4, 2017
3dbe216
Merge commit for internal changes
Oct 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 31 additions & 17 deletions tensorflow/contrib/boosted_trees/kernels/prediction_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,27 @@ const char* kApplyDropoutAttributeName = "apply_dropout";
const char* kApplyAveragingAttributeName = "apply_averaging";
const char* kDropoutInfoOutputTensorName = "drop_out_tree_indices_weights";
const char* kPredictionsTensorName = "predictions";
const char* kNoDropoutPredictionsTensorName = "no_dropout_predictions";

void CalculateTreesToInclude(
const boosted_trees::trees::DecisionTreeEnsembleConfig& config,
const std::vector<int32>& trees_to_drop, const int32 num_trees,
const bool only_finalized, std::vector<int32>* trees_to_include) {
trees_to_include->reserve(num_trees - trees_to_drop.size());

int32 index = 0;
// This assumes that trees_to_drop is a sorted list of tree ids.
for (int32 tree = 0; tree < num_trees; ++tree) {
if ((!trees_to_drop.empty() && index < trees_to_drop.size() &&
trees_to_drop[index] == tree) ||
(only_finalized && config.tree_metadata_size() > 0 &&
!config.tree_metadata(tree).is_finalized())) {
++index;
continue;
}
trees_to_include->push_back(tree);
}
}
} // namespace

class GradientTreesPredictionOp : public OpKernel {
public:
Expand Down Expand Up @@ -226,6 +245,13 @@ class GradientTreesPredictionOp : public OpKernel {
weights, &dropped_trees, &original_weights));
}

// Prepare the list of trees to include in the prediction.
std::vector<int32> trees_to_include;
CalculateTreesToInclude(
ensemble_resource->decision_tree_ensemble(), dropped_trees,
ensemble_resource->decision_tree_ensemble().trees_size(),
only_finalized_trees_, &trees_to_include);

// Allocate output predictions matrix.
Tensor* output_predictions_t = nullptr;
OP_REQUIRES_OK(
Expand All @@ -234,44 +260,32 @@ class GradientTreesPredictionOp : public OpKernel {
&output_predictions_t));
auto output_predictions = output_predictions_t->matrix<float>();

Tensor* output_no_dropout_predictions_t = nullptr;
OP_REQUIRES_OK(
context, context->allocate_output(kNoDropoutPredictionsTensorName,
{batch_size, prediction_vector_size_},
&output_no_dropout_predictions_t));
auto output_no_dropout_predictions =
output_no_dropout_predictions_t->matrix<float>();

// Run predictor.
thread::ThreadPool* const worker_threads =
context->device()->tensorflow_cpu_worker_threads()->workers;

if (apply_averaging_) {
DecisionTreeEnsembleConfig adjusted =
ensemble_resource->decision_tree_ensemble();

const int start_averaging = std::max(
0.0,
averaging_config_.config_case() ==
AveragingConfig::kAverageLastNTreesFieldNumber
? adjusted.trees_size() - averaging_config_.average_last_n_trees()
: adjusted.trees_size() *
(1.0 - averaging_config_.average_last_percent_trees()));

const int num_ensembles = adjusted.trees_size() - start_averaging;
for (int i = start_averaging; i < adjusted.trees_size(); ++i) {
float weight = adjusted.tree_weights(i);
adjusted.mutable_tree_weights()->Set(
i, weight * (num_ensembles - i + start_averaging) / num_ensembles);
}
MultipleAdditiveTrees::Predict(
adjusted, only_finalized_trees_, dropped_trees, batch_features,
worker_threads, output_predictions, output_no_dropout_predictions);
MultipleAdditiveTrees::Predict(adjusted, trees_to_include, batch_features,
worker_threads, output_predictions);
} else {
MultipleAdditiveTrees::Predict(
ensemble_resource->decision_tree_ensemble(), only_finalized_trees_,
dropped_trees, batch_features, worker_threads, output_predictions,
output_no_dropout_predictions);
ensemble_resource->decision_tree_ensemble(), trees_to_include,
batch_features, worker_threads, output_predictions);
}

// Output dropped trees and original weights.
Expand Down
120 changes: 31 additions & 89 deletions tensorflow/contrib/boosted_trees/lib/models/multiple_additive_trees.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,110 +21,52 @@ namespace tensorflow {
namespace boosted_trees {
namespace models {

namespace {
void CalculateTreesToKeep(
const boosted_trees::trees::DecisionTreeEnsembleConfig& config,
const std::vector<int32>& trees_to_drop, const int32 num_trees,
const bool only_finalized, std::vector<int32>* trees_to_keep) {
trees_to_keep->reserve(num_trees - trees_to_drop.size());

int32 index = 0;
// This assumes that trees_to_drop is a sorted list of tree ids.
for (int32 tree = 0; tree < num_trees; ++tree) {
if ((!trees_to_drop.empty() && index < trees_to_drop.size() &&
trees_to_drop[index] == tree) ||
(only_finalized && config.tree_metadata_size() > 0 &&
!config.tree_metadata(tree).is_finalized())) {
++index;
continue;
}
trees_to_keep->push_back(tree);
}
}

void UpdatePredictions(
const int32 index_1, const int32 index_2, const float value,
tensorflow::TTypes<float>::Matrix* output_predictions,
tensorflow::TTypes<float>::Matrix* additional_output_predictions) {
(*output_predictions)(index_1, index_2) += value;

if (additional_output_predictions != nullptr) {
(*additional_output_predictions)(index_1, index_2) += value;
}
}

void UpdatePredictionsBasedOnTree(
const boosted_trees::trees::DecisionTreeEnsembleConfig& config,
const int32 tree_idx, const boosted_trees::utils::Example& example,
tensorflow::TTypes<float>::Matrix* output_predictions,
tensorflow::TTypes<float>::Matrix* additional_output_predictions) {
const boosted_trees::trees::DecisionTreeConfig& tree = config.trees(tree_idx);
const float tree_weight = config.tree_weights(tree_idx);
const int leaf_idx = trees::DecisionTree::Traverse(tree, 0, example);
QCHECK(leaf_idx >= 0) << "Invalid tree: " << tree.DebugString();
const auto& leaf_node = tree.nodes(leaf_idx);
QCHECK(leaf_node.has_leaf())
<< "Invalid leaf node: " << leaf_node.DebugString();
if (leaf_node.leaf().has_sparse_vector()) {
const auto& leaf = leaf_node.leaf().sparse_vector();
QCHECK_EQ(leaf.index_size(), leaf.value_size());
for (size_t class_idx = 0; class_idx < leaf.index_size(); ++class_idx) {
const float value = tree_weight * leaf.value(class_idx);

UpdatePredictions(example.example_idx, leaf.index(class_idx), value,
output_predictions, additional_output_predictions);
}
} else {
QCHECK(leaf_node.leaf().has_vector()) << "Unknown leaf type";
const auto& leaf = leaf_node.leaf().vector();
for (size_t i = 0; i < leaf.value_size(); ++i) {
const float value = tree_weight * leaf.value(i);
UpdatePredictions(example.example_idx, i, value, output_predictions,
additional_output_predictions);
}
}
}

} // namespace

void MultipleAdditiveTrees::Predict(
const boosted_trees::trees::DecisionTreeEnsembleConfig& config,
const bool only_finalized_trees, const std::vector<int32>& trees_to_drop,
const std::vector<int32>& trees_to_include,
const boosted_trees::utils::BatchFeatures& features,
tensorflow::thread::ThreadPool* worker_threads,
tensorflow::TTypes<float>::Matrix output_predictions,
tensorflow::TTypes<float>::Matrix no_dropout_predictions) {
tensorflow::thread::ThreadPool* const worker_threads,
tensorflow::TTypes<float>::Matrix output_predictions) {
// Zero out predictions as the model is additive.
output_predictions.setZero();
no_dropout_predictions.setZero();

// Get batch size.
const int64 batch_size = features.batch_size();
if (batch_size <= 0) {
return;
}

// Prepare the list of trees to keep.
std::vector<int32> trees_to_keep;
CalculateTreesToKeep(config, trees_to_drop, config.trees_size(),
only_finalized_trees, &trees_to_keep);

// Lambda for doing a block of work.
auto update_predictions = [&config, &features, &trees_to_keep, &trees_to_drop,
&output_predictions,
&no_dropout_predictions](int64 start, int64 end) {
auto update_predictions = [&config, &features, &trees_to_include,
&output_predictions](int64 start, int64 end) {
auto examples_iterable = features.examples_iterable(start, end);
for (const auto& example : examples_iterable) {
for (const int32 tree_idx : trees_to_keep) {
UpdatePredictionsBasedOnTree(config, tree_idx, example,
&output_predictions,
&no_dropout_predictions);
}

// Now do predictions for dropped trees
for (const int32 tree_idx : trees_to_drop) {
UpdatePredictionsBasedOnTree(config, tree_idx, example,
&no_dropout_predictions, nullptr);
for (const int32 tree_idx : trees_to_include) {
const boosted_trees::trees::DecisionTreeConfig& tree =
config.trees(tree_idx);
const float tree_weight = config.tree_weights(tree_idx);
const int leaf_idx = trees::DecisionTree::Traverse(tree, 0, example);
QCHECK(leaf_idx >= 0) << "Invalid tree: " << tree.DebugString();
const auto& leaf_node = tree.nodes(leaf_idx);
QCHECK(leaf_node.has_leaf())
<< "Invalid leaf node: " << leaf_node.DebugString();
if (leaf_node.leaf().has_sparse_vector()) {
const auto& leaf = leaf_node.leaf().sparse_vector();
QCHECK_EQ(leaf.index_size(), leaf.value_size());
for (size_t logit_dim = 0; logit_dim < leaf.index_size();
++logit_dim) {
const float value = tree_weight * leaf.value(logit_dim);
output_predictions(example.example_idx, leaf.index(logit_dim)) +=
value;
}
} else {
QCHECK(leaf_node.leaf().has_vector()) << "Unknown leaf type";
const auto& leaf = leaf_node.leaf().vector();
for (size_t i = 0; i < leaf.value_size(); ++i) {
const float value = tree_weight * leaf.value(i);
output_predictions(example.example_idx, i) += value;
}
}
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ namespace models {
class MultipleAdditiveTrees {
public:
// Predict runs tree ensemble on the given batch and updates
// output predictions accordingly. The method also returns predictions that
// we would get if no dropout was applied.
// output predictions accordingly, for the given list of trees.
static void Predict(
const boosted_trees::trees::DecisionTreeEnsembleConfig& config,
const bool only_finalized_trees, const std::vector<int32>& trees_to_drop,
const std::vector<int32>& trees_to_include,
const boosted_trees::utils::BatchFeatures& features,
thread::ThreadPool* const thread_pool,
TTypes<float>::Matrix output_predictions,
TTypes<float>::Matrix no_dropout_predictions);
tensorflow::thread::ThreadPool* const worker_threads,
tensorflow::TTypes<float>::Matrix output_predictions);
};

} // namespace models
Expand Down