Compare commits
21 Commits
rei/fork-r
...
r0.8
Author | SHA1 | Date | |
---|---|---|---|
|
9b69ec3960 | ||
|
4b7bc3174e | ||
|
dc19800ee1 | ||
|
ac3c683651 | ||
|
a074dca846 | ||
|
f7ec1ed5fc | ||
|
44a6b91ce8 | ||
|
d118d1d31c | ||
|
846e0121e7 | ||
|
93625a8a79 | ||
|
6408038938 | ||
|
1933eb61ac | ||
|
9fd4a1dd9e | ||
|
7a4e0bf9aa | ||
|
0e61baf4ea | ||
|
50cb176ba9 | ||
|
9e1b37e4ce | ||
|
fb301a9848 | ||
|
35cd6a3011 | ||
|
09d7d91ef0 | ||
|
6bda8aa907 |
@ -31,9 +31,9 @@ and discussion.**
|
|||||||
|
|
||||||
People who are a little bit adventurous can also try our nightly binaries:
|
People who are a little bit adventurous can also try our nightly binaries:
|
||||||
|
|
||||||
* Linux CPU only: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/))
|
* Linux CPU only: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp27-none-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/))
|
||||||
* Linux GPU: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-working/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-working/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-working/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-working/))
|
* Linux GPU: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-working/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp27-none-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-working/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-working/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-working/))
|
||||||
* Mac CPU only: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-py2-none-any.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-py3-none-any.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/))
|
* Mac CPU only: [Python 2](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-py2-none-any.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/)) / [Python 3](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-py3-none-any.whl) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/))
|
||||||
* [Android](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/lastSuccessfulBuild/artifact/bazel-out/local_linux/bin/tensorflow/examples/android/tensorflow_demo.apk) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/))
|
* [Android](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/lastSuccessfulBuild/artifact/bazel-out/local_linux/bin/tensorflow/examples/android/tensorflow_demo.apk) ([build history](http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/))
|
||||||
|
|
||||||
#### *Try your first TensorFlow program*
|
#### *Try your first TensorFlow program*
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
This release contains contributions from many people at Google, as well as:
|
This release contains contributions from many people at Google, as well as:
|
||||||
|
|
||||||
Abhinav Upadhyay, Aggelos Avgerinos, Alan Wu, Alexander G. de G. Matthews, Aleksandr Yahnev, @amchercashin, Andy Kitchen, Aurelien Geron, Awni Hannun, @BanditCat, Bas Veeling, Cameron Chen, @cg31, Cheng-Lung Sung, Christopher Bonnett, Dan Becker, Dan Van Boxel, Daniel Golden, Danijar Hafner, Danny Goodman, Dave Decker, David Dao, David Kretch, Dongjoon Hyun, Dustin Dorroh, @e-lin, Eurico Doirado, Erik Erwitt, Fabrizio Milo, @gaohuazuo, Iblis Lin, Igor Babuschkin, Isaac Hodes, Isaac Turner, Iván Vallés, J Yegerlehner, Jack Zhang, James Wexler, Jan Zikes, Jay Young, Jeff Hodges, @jmtatsch, Johnny Lim, Jonas Meinertz Hansen, Kanit Wongsuphasawat, Kashif Rasul, Ken Shirriff, Kenneth Mitchner, Kenta Yonekura, Konrad Magnusson, Konstantin Lopuhin, @lahwran, @lekaha, @liyongsea, Lucas Adams, @makseq, Mandeep Singh, @manipopopo, Mark Amery, Memo Akten, Michael Heilman, Michael Peteuil, Nathan Daly, Nicolas Fauchereau, @ninotoshi, Olav Nymoen, @panmari, @papelita1234, Pedro Lopes, Pranav Sailesh Mani, RJ Ryan, Rob Culliton, Robert DiPietro, @ronrest, Sam Abrahams, Sarath Shekkizhar, Scott Graham, Sebastian Raschka, Sung Kim, Surya Bhupatiraju, Syed Ahmed, Till Hoffmann, @timsl, @urimend, @vesnica, Vlad Frolov, Vlad Zagorodniy, Wei-Ting Kuo, Wenjian Huang, William Dmitri Breaden Madden, Wladimir Schmidt, Yuwen Yan, Yuxin Wu, Yuya Kusakabe, @zhongzyd, @znah.
|
Abhinav Upadhyay, Aggelos Avgerinos, Alan Wu, Alexander G. de G. Matthews, Aleksandr Yahnev, @amchercashin, Andy Kitchen, Aurelien Geron, Awni Hannun, @BanditCat, Bas Veeling, Cameron Chen, @cg31, Cheng-Lung Sung, Christopher Bonnett, Dan Becker, Dan Van Boxel, Daniel Golden, Danijar Hafner, Danny Goodman, Dave Decker, David Dao, David Kretch, Dongjoon Hyun, Dustin Dorroh, @e-lin, Eurico Doirado, Erik Erwitt, Fabrizio Milo, @gaohuazuo, Iblis Lin, Igor Babuschkin, Isaac Hodes, Isaac Turner, Iván Vallés, J Yegerlehner, Jack Zhang, Jan Zikes, Jay Young, Jeff Hodges, @jmtatsch, Johnny Lim, Jonas Meinertz Hansen, Kanit Wongsuphasawat, Kashif Rasul, Ken Shirriff, Kenneth Mitchner, Kenta Yonekura, Konrad Magnusson, Konstantin Lopuhin, @lahwran, @lekaha, @liyongsea, Lucas Adams, @makseq, Mandeep Singh, @manipopopo, Mark Amery, Memo Akten, Michael Heilman, Michael Peteuil, Nathan Daly, Nicolas Fauchereau, @ninotoshi, Olav Nymoen, @panmari, @papelita1234, Pedro Lopes, Pranav Sailesh Mani, RJ Ryan, Rob Culliton, Robert DiPietro, @ronrest, Sam Abrahams, Sarath Shekkizhar, Scott Graham, Sebastian Raschka, Sung Kim, Surya Bhupatiraju, Syed Ahmed, Till Hoffmann, @timsl, @urimend, @vesnica, Vlad Frolov, Vlad Zagorodniy, Wei-Ting Kuo, Wenjian Huang, William Dmitri Breaden Madden, Wladimir Schmidt, Yuan Tang, Yuwen Yan, Yuxin Wu, Yuya Kusakabe, @zhongzyd, @znah.
|
||||||
|
|
||||||
We are also grateful to all who filed issues or helped resolve them, asked and
|
We are also grateful to all who filed issues or helped resolve them, asked and
|
||||||
answered questions, and were part of inspiring discussions.
|
answered questions, and were part of inspiring discussions.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// only op that involves tree traversal, and is constructed so that it can
|
// only op that involves tree traversal, and is constructed so that it can
|
||||||
// be run in parallel on separate batches of data.
|
// be run in parallel on separate batches of data.
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "tensorflow/contrib/tensor_forest/core/ops/tree_utils.h"
|
#include "tensorflow/contrib/tensor_forest/core/ops/tree_utils.h"
|
||||||
|
|
||||||
@ -25,10 +26,12 @@
|
|||||||
#include "tensorflow/core/framework/op_kernel.h"
|
#include "tensorflow/core/framework/op_kernel.h"
|
||||||
|
|
||||||
#include "tensorflow/core/lib/gtl/map_util.h"
|
#include "tensorflow/core/lib/gtl/map_util.h"
|
||||||
|
#include "tensorflow/core/util/work_sharder.h"
|
||||||
|
|
||||||
namespace tensorflow {
|
namespace tensorflow {
|
||||||
|
|
||||||
using std::get;
|
using std::get;
|
||||||
|
using std::make_pair;
|
||||||
using std::make_tuple;
|
using std::make_tuple;
|
||||||
using std::pair;
|
using std::pair;
|
||||||
using std::tuple;
|
using std::tuple;
|
||||||
@ -42,6 +45,71 @@ using tensorforest::DecideNode;
|
|||||||
using tensorforest::Initialize;
|
using tensorforest::Initialize;
|
||||||
using tensorforest::IsAllInitialized;
|
using tensorforest::IsAllInitialized;
|
||||||
|
|
||||||
|
// A data structure to store the results of parallel tree traversal.
|
||||||
|
struct InputDataResult {
|
||||||
|
// A list of each node that was visited.
|
||||||
|
std::vector<int32> node_indices;
|
||||||
|
// The accumulator of the leaf that a data point ended up at, or -1 if none.
|
||||||
|
int32 leaf_accumulator;
|
||||||
|
// The left-branch taken candidate splits.
|
||||||
|
std::vector<int32> split_adds;
|
||||||
|
// If the candidate splits for the leaf that a data point arrived at
|
||||||
|
// were initialized or not, which determines if we add this to total
|
||||||
|
// pcw counts or not.
|
||||||
|
bool splits_initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Evaluate(const Tensor& input_data, const Tensor& input_labels,
|
||||||
|
const Tensor& tree_tensor, const Tensor& tree_thresholds,
|
||||||
|
const Tensor& node_to_accumulator,
|
||||||
|
const Tensor& candidate_split_features,
|
||||||
|
const Tensor& candidate_split_thresholds,
|
||||||
|
InputDataResult* results, int64 start, int64 end) {
|
||||||
|
const auto tree = tree_tensor.tensor<int32, 2>();
|
||||||
|
const auto thresholds = tree_thresholds.unaligned_flat<float>();
|
||||||
|
const auto node_map = node_to_accumulator.unaligned_flat<int32>();
|
||||||
|
const auto split_features = candidate_split_features.tensor<int32, 2>();
|
||||||
|
const auto split_thresholds = candidate_split_thresholds.tensor<float, 2>();
|
||||||
|
|
||||||
|
const int32 num_splits = candidate_split_features.shape().dim_size(1);
|
||||||
|
|
||||||
|
for (int i = start; i < end; ++i) {
|
||||||
|
const Tensor point = input_data.Slice(i, i + 1);
|
||||||
|
int node_index = 0;
|
||||||
|
results[i].splits_initialized = false;
|
||||||
|
while (true) {
|
||||||
|
results[i].node_indices.push_back(node_index);
|
||||||
|
int32 left_child = tree(node_index, CHILDREN_INDEX);
|
||||||
|
if (left_child == LEAF_NODE) {
|
||||||
|
const int32 accumulator = node_map(node_index);
|
||||||
|
results[i].leaf_accumulator = accumulator;
|
||||||
|
// If the leaf is not fertile or is not yet initialized, we don't
|
||||||
|
// count it in the candidate/total split per-class-weights because
|
||||||
|
// it won't have any candidate splits yet.
|
||||||
|
if (accumulator >= 0 &&
|
||||||
|
IsAllInitialized(candidate_split_features.Slice(
|
||||||
|
accumulator, accumulator + 1))) {
|
||||||
|
results[i].splits_initialized = true;
|
||||||
|
for (int split = 0; split < num_splits; split++) {
|
||||||
|
if (!DecideNode(point, split_features(accumulator, split),
|
||||||
|
split_thresholds(accumulator, split))) {
|
||||||
|
results[i].split_adds.push_back(split);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (left_child == FREE_NODE) {
|
||||||
|
LOG(ERROR) << "Reached a free node, not good.";
|
||||||
|
results[i].node_indices.push_back(FREE_NODE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node_index =
|
||||||
|
left_child + DecideNode(point, tree(node_index, FEATURE_INDEX),
|
||||||
|
thresholds(node_index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_OP("CountExtremelyRandomStats")
|
REGISTER_OP("CountExtremelyRandomStats")
|
||||||
.Attr("num_classes: int32")
|
.Attr("num_classes: int32")
|
||||||
.Input("input_data: float")
|
.Input("input_data: float")
|
||||||
@ -79,9 +147,9 @@ REGISTER_OP("CountExtremelyRandomStats")
|
|||||||
gives the j-th feature of the i-th input.
|
gives the j-th feature of the i-th input.
|
||||||
input_labels: The training batch's labels; `input_labels[i]` is the class
|
input_labels: The training batch's labels; `input_labels[i]` is the class
|
||||||
of the i-th input.
|
of the i-th input.
|
||||||
tree:= A 2-d int32 tensor. `tree[0][i]` gives the index of the left child
|
tree:= A 2-d int32 tensor. `tree[i][0]` gives the index of the left child
|
||||||
of the i-th node, `tree[0][i] + 1` gives the index of the right child of
|
of the i-th node, `tree[i][0] + 1` gives the index of the right child of
|
||||||
the i-th node, and `tree[1][i]` gives the index of the feature used to
|
the i-th node, and `tree[i][1]` gives the index of the feature used to
|
||||||
split the i-th node.
|
split the i-th node.
|
||||||
tree_thresholds: `tree_thresholds[i]` is the value used to split the i-th
|
tree_thresholds: `tree_thresholds[i]` is the value used to split the i-th
|
||||||
node.
|
node.
|
||||||
@ -176,7 +244,31 @@ class CountExtremelyRandomStats : public OpKernel {
|
|||||||
"candidate_split_features and candidate_split_thresholds should be "
|
"candidate_split_features and candidate_split_thresholds should be "
|
||||||
"the same shape."));
|
"the same shape."));
|
||||||
|
|
||||||
const int32 num_splits = candidate_split_features.shape().dim_size(1);
|
// Evaluate input data in parallel.
|
||||||
|
const int64 num_data = input_data.shape().dim_size(0);
|
||||||
|
std::unique_ptr<InputDataResult[]> results(new InputDataResult[num_data]);
|
||||||
|
auto worker_threads = context->device()->tensorflow_cpu_worker_threads();
|
||||||
|
int num_threads = worker_threads->num_threads;
|
||||||
|
if (num_threads <= 1) {
|
||||||
|
Evaluate(input_data, input_labels, tree_tensor, tree_thresholds,
|
||||||
|
node_to_accumulator, candidate_split_features,
|
||||||
|
candidate_split_thresholds, results.get(), 0, num_data);
|
||||||
|
} else {
|
||||||
|
auto work = [&input_data, &input_labels, &tree_tensor, &tree_thresholds,
|
||||||
|
&node_to_accumulator, &candidate_split_features,
|
||||||
|
&candidate_split_thresholds, &num_data,
|
||||||
|
&results](int64 start, int64 end) {
|
||||||
|
CHECK(start <= end);
|
||||||
|
CHECK(end <= num_data);
|
||||||
|
Evaluate(input_data, input_labels, tree_tensor, tree_thresholds,
|
||||||
|
node_to_accumulator, candidate_split_features,
|
||||||
|
candidate_split_thresholds, results.get(), start, end);
|
||||||
|
};
|
||||||
|
Shard(num_threads, worker_threads->workers, num_data, 100, work);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set output tensors.
|
||||||
|
const auto labels = input_labels.unaligned_flat<int32>();
|
||||||
|
|
||||||
// node pcw delta
|
// node pcw delta
|
||||||
Tensor* output_node_pcw_delta = nullptr;
|
Tensor* output_node_pcw_delta = nullptr;
|
||||||
@ -196,58 +288,28 @@ class CountExtremelyRandomStats : public OpKernel {
|
|||||||
&output_leaves));
|
&output_leaves));
|
||||||
auto out_leaves = output_leaves->unaligned_flat<int32>();
|
auto out_leaves = output_leaves->unaligned_flat<int32>();
|
||||||
|
|
||||||
const auto tree = tree_tensor.tensor<int32, 2>();
|
|
||||||
const auto thresholds = tree_thresholds.unaligned_flat<float>();
|
|
||||||
const auto labels = input_labels.unaligned_flat<int32>();
|
|
||||||
const auto node_map = node_to_accumulator.unaligned_flat<int32>();
|
|
||||||
const auto split_features = candidate_split_features.tensor<int32, 2>();
|
|
||||||
const auto split_thresholds = candidate_split_thresholds.tensor<float, 2>();
|
|
||||||
|
|
||||||
const int32 num_data = input_data.shape().dim_size(0);
|
|
||||||
|
|
||||||
// <accumulator, class> -> count delta
|
// <accumulator, class> -> count delta
|
||||||
std::unordered_map<pair<int32, int32>, int32, PairIntHash> total_delta;
|
std::unordered_map<pair<int32, int32>, int32, PairIntHash> total_delta;
|
||||||
// <accumulator, split, class> -> count delta
|
// <accumulator, split, class> -> count delta
|
||||||
std::unordered_map<tuple<int32, int32, int32>,
|
std::unordered_map<tuple<int32, int32, int32>,
|
||||||
int32, TupleIntHash> split_delta;
|
int32, TupleIntHash> split_delta;
|
||||||
for (int i = 0; i < num_data; i++) {
|
|
||||||
const Tensor point = input_data.Slice(i, i+1);
|
for (int32 i = 0; i < num_data; ++i) {
|
||||||
int node_index = 0;
|
const int32 label = labels(i);
|
||||||
while (true) {
|
const int32 accumulator = results[i].leaf_accumulator;
|
||||||
const int32 label = labels(i);
|
for (const int32 node : results[i].node_indices) {
|
||||||
++out_node(node_index, label);
|
++out_node(node, label);
|
||||||
int32 left_child = tree(node_index, CHILDREN_INDEX);
|
}
|
||||||
if (left_child == LEAF_NODE) {
|
out_leaves(i) = results[i].node_indices.back();
|
||||||
out_leaves(i) = node_index;
|
if (accumulator >= 0 && results[i].splits_initialized) {
|
||||||
const int32 accumulator = node_map(node_index);
|
++total_delta[make_pair(accumulator, label)];
|
||||||
// If the leaf is not fertile or is not yet initialized, we don't
|
for (const int32 split : results[i].split_adds) {
|
||||||
// count it in the candidate/total split per-class-weights because
|
++split_delta[make_tuple(accumulator, split, label)];
|
||||||
// it won't have any candidate splits yet.
|
|
||||||
if (accumulator >= 0 &&
|
|
||||||
IsAllInitialized(
|
|
||||||
candidate_split_features.Slice(accumulator,
|
|
||||||
accumulator + 1))) {
|
|
||||||
++total_delta[std::make_pair(accumulator, label)];
|
|
||||||
for (int split = 0; split < num_splits; split++) {
|
|
||||||
if (!DecideNode(point, split_features(accumulator, split),
|
|
||||||
split_thresholds(accumulator, split))) {
|
|
||||||
++split_delta[make_tuple(accumulator, split, label)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else if (left_child == FREE_NODE) {
|
|
||||||
LOG(ERROR) << "Reached a free node, not good.";
|
|
||||||
out_leaves(i) = FREE_NODE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
node_index = left_child +
|
|
||||||
DecideNode(point, tree(node_index, FEATURE_INDEX),
|
|
||||||
thresholds(node_index));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidate splits pcw indices
|
// candidate splits pcw indices
|
||||||
Tensor* output_candidate_pcw_indices = nullptr;
|
Tensor* output_candidate_pcw_indices = nullptr;
|
||||||
TensorShape candidate_pcw_shape;
|
TensorShape candidate_pcw_shape;
|
||||||
candidate_pcw_shape.AddDim(split_delta.size());
|
candidate_pcw_shape.AddDim(split_delta.size());
|
||||||
|
@ -94,7 +94,7 @@ class SampleInputs : public OpKernel {
|
|||||||
"split_sampling_random_seed", &split_sampling_random_seed_));
|
"split_sampling_random_seed", &split_sampling_random_seed_));
|
||||||
// Set up the random number generator.
|
// Set up the random number generator.
|
||||||
if (split_sampling_random_seed_ == 0) {
|
if (split_sampling_random_seed_ == 0) {
|
||||||
uint64 time_seed = static_cast<uint64>(std::time(NULL));
|
uint64 time_seed = static_cast<uint64>(std::clock());
|
||||||
single_rand_ = std::unique_ptr<random::PhiloxRandom>(
|
single_rand_ = std::unique_ptr<random::PhiloxRandom>(
|
||||||
new random::PhiloxRandom(time_seed));
|
new random::PhiloxRandom(time_seed));
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,9 +44,9 @@ REGISTER_OP("TreePredictions")
|
|||||||
|
|
||||||
input_data: The training batch's features as a 2-d tensor; `input_data[i][j]`
|
input_data: The training batch's features as a 2-d tensor; `input_data[i][j]`
|
||||||
gives the j-th feature of the i-th input.
|
gives the j-th feature of the i-th input.
|
||||||
tree:= A 2-d int32 tensor. `tree[0][i]` gives the index of the left child
|
tree:= A 2-d int32 tensor. `tree[i][0]` gives the index of the left child
|
||||||
of the i-th node, `tree[0][i] + 1` gives the index of the right child of
|
of the i-th node, `tree[i][0] + 1` gives the index of the right child of
|
||||||
the i-th node, and `tree[1][i]` gives the index of the feature used to
|
the i-th node, and `tree[i][1]` gives the index of the feature used to
|
||||||
split the i-th node.
|
split the i-th node.
|
||||||
tree_thresholds: `tree_thresholds[i]` is the value used to split the i-th
|
tree_thresholds: `tree_thresholds[i]` is the value used to split the i-th
|
||||||
node.
|
node.
|
||||||
|
@ -17,7 +17,7 @@ from __future__ import absolute_import
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import tensorflow # pylint: disable=unused-import
|
import tensorflow as tf
|
||||||
|
|
||||||
from tensorflow.contrib.tensor_forest.python.ops import training_ops
|
from tensorflow.contrib.tensor_forest.python.ops import training_ops
|
||||||
|
|
||||||
@ -47,6 +47,29 @@ class CountExtremelyRandomStatsTest(test_util.TensorFlowTestCase):
|
|||||||
self.tree_thresholds, self.node_map,
|
self.tree_thresholds, self.node_map,
|
||||||
self.split_features, self.split_thresholds, num_classes=4))
|
self.split_features, self.split_thresholds, num_classes=4))
|
||||||
|
|
||||||
|
self.assertAllEqual(
|
||||||
|
[[1., 1., 1., 1.], [1., 1., 0., 0.], [0., 0., 1., 1.]],
|
||||||
|
pcw_node.eval())
|
||||||
|
self.assertAllEqual([[0, 0, 0]], pcw_splits_indices.eval())
|
||||||
|
self.assertAllEqual([1.], pcw_splits_delta.eval())
|
||||||
|
self.assertAllEqual([[0, 1], [0, 0]], pcw_totals_indices.eval())
|
||||||
|
self.assertAllEqual([1., 1.], pcw_totals_delta.eval())
|
||||||
|
self.assertAllEqual([1, 1, 2, 2], leaves.eval())
|
||||||
|
|
||||||
|
def testThreaded(self):
|
||||||
|
with self.test_session(
|
||||||
|
config=tf.ConfigProto(intra_op_parallelism_threads=2)):
|
||||||
|
(pcw_node, pcw_splits_indices, pcw_splits_delta, pcw_totals_indices,
|
||||||
|
pcw_totals_delta,
|
||||||
|
leaves) = (self.ops.count_extremely_random_stats(self.input_data,
|
||||||
|
self.input_labels,
|
||||||
|
self.tree,
|
||||||
|
self.tree_thresholds,
|
||||||
|
self.node_map,
|
||||||
|
self.split_features,
|
||||||
|
self.split_thresholds,
|
||||||
|
num_classes=4))
|
||||||
|
|
||||||
self.assertAllEqual([[1., 1., 1., 1.], [1., 1., 0., 0.],
|
self.assertAllEqual([[1., 1., 1., 1.], [1., 1., 0., 0.],
|
||||||
[0., 0., 1., 1.]],
|
[0., 0., 1., 1.]],
|
||||||
pcw_node.eval())
|
pcw_node.eval())
|
||||||
|
@ -49,12 +49,13 @@ def TreePredictions(op):
|
|||||||
# there's not yet any guarantee that the shared object exists.
|
# there's not yet any guarantee that the shared object exists.
|
||||||
# In which case, "import tensorflow" will always crash, even for users that
|
# In which case, "import tensorflow" will always crash, even for users that
|
||||||
# never use contrib.
|
# never use contrib.
|
||||||
def Load():
|
def Load(library_base_dir=''):
|
||||||
"""Load the inference ops library and return the loaded module."""
|
"""Load the inference ops library and return the loaded module."""
|
||||||
with _ops_lock:
|
with _ops_lock:
|
||||||
global _inference_ops
|
global _inference_ops
|
||||||
if not _inference_ops:
|
if not _inference_ops:
|
||||||
data_files_path = tf.resource_loader.get_data_files_path()
|
data_files_path = os.path.join(library_base_dir,
|
||||||
|
tf.resource_loader.get_data_files_path())
|
||||||
tf.logging.info('data path: %s', data_files_path)
|
tf.logging.info('data path: %s', data_files_path)
|
||||||
_inference_ops = tf.load_op_library(os.path.join(
|
_inference_ops = tf.load_op_library(os.path.join(
|
||||||
data_files_path, INFERENCE_OPS_FILE))
|
data_files_path, INFERENCE_OPS_FILE))
|
||||||
|
@ -25,6 +25,7 @@ import tensorflow as tf
|
|||||||
from tensorflow.python.framework import ops
|
from tensorflow.python.framework import ops
|
||||||
from tensorflow.python.framework import tensor_shape
|
from tensorflow.python.framework import tensor_shape
|
||||||
|
|
||||||
|
|
||||||
TRAINING_OPS_FILE = '_training_ops.so'
|
TRAINING_OPS_FILE = '_training_ops.so'
|
||||||
|
|
||||||
_training_ops = None
|
_training_ops = None
|
||||||
@ -96,12 +97,13 @@ def _UpdateFertileSlotsShape(unused_op):
|
|||||||
# there's not yet any guarantee that the shared object exists.
|
# there's not yet any guarantee that the shared object exists.
|
||||||
# In which case, "import tensorflow" will always crash, even for users that
|
# In which case, "import tensorflow" will always crash, even for users that
|
||||||
# never use contrib.
|
# never use contrib.
|
||||||
def Load():
|
def Load(library_base_dir=''):
|
||||||
"""Load training ops library and return the loaded module."""
|
"""Load training ops library and return the loaded module."""
|
||||||
with _ops_lock:
|
with _ops_lock:
|
||||||
global _training_ops
|
global _training_ops
|
||||||
if not _training_ops:
|
if not _training_ops:
|
||||||
data_files_path = tf.resource_loader.get_data_files_path()
|
data_files_path = os.path.join(library_base_dir,
|
||||||
|
tf.resource_loader.get_data_files_path())
|
||||||
tf.logging.info('data path: %s', data_files_path)
|
tf.logging.info('data path: %s', data_files_path)
|
||||||
_training_ops = tf.load_op_library(os.path.join(
|
_training_ops = tf.load_op_library(os.path.join(
|
||||||
data_files_path, TRAINING_OPS_FILE))
|
data_files_path, TRAINING_OPS_FILE))
|
||||||
|
@ -25,19 +25,6 @@ from tensorflow.contrib.tensor_forest.python.ops import inference_ops
|
|||||||
from tensorflow.contrib.tensor_forest.python.ops import training_ops
|
from tensorflow.contrib.tensor_forest.python.ops import training_ops
|
||||||
|
|
||||||
|
|
||||||
flags = tf.app.flags
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
|
|
||||||
|
|
||||||
# Default parameter values. These are all only used if the corresponding
|
|
||||||
# parameter is not specified when constructing the ForestHParams.
|
|
||||||
flags.DEFINE_integer('num_trees', 100, 'Number of trees in forest')
|
|
||||||
flags.DEFINE_integer('max_nodes', 10000, 'Maxmimum number of tree nodes.')
|
|
||||||
flags.DEFINE_float(
|
|
||||||
'samples_to_decide', 25.0,
|
|
||||||
'Only decide on a split, or only fully use a leaf, after this many '
|
|
||||||
'training samples have been seen.')
|
|
||||||
|
|
||||||
# If tree[i][0] equals this value, then i is a leaf node.
|
# If tree[i][0] equals this value, then i is a leaf node.
|
||||||
LEAF_NODE = -1
|
LEAF_NODE = -1
|
||||||
|
|
||||||
@ -57,7 +44,20 @@ LEAF_NODE = -1
|
|||||||
class ForestHParams(object):
|
class ForestHParams(object):
|
||||||
"""A base class for holding hyperparameters and calculating good defaults."""
|
"""A base class for holding hyperparameters and calculating good defaults."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, num_trees=100, max_nodes=10000, bagging_fraction=1.0,
|
||||||
|
samples_to_decide=25, max_depth=0, num_splits_to_consider=0,
|
||||||
|
max_fertile_nodes=0, split_after_samples=0,
|
||||||
|
valid_leaf_threshold=0, **kwargs):
|
||||||
|
self.num_trees = num_trees
|
||||||
|
self.max_nodes = max_nodes
|
||||||
|
self.bagging_fraction = bagging_fraction
|
||||||
|
self.samples_to_decide = samples_to_decide
|
||||||
|
self.max_depth = max_depth
|
||||||
|
self.num_splits_to_consider = num_splits_to_consider
|
||||||
|
self.max_fertile_nodes = max_fertile_nodes
|
||||||
|
self.split_after_samples = split_after_samples
|
||||||
|
self.valid_leaf_threshold = valid_leaf_threshold
|
||||||
|
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
@ -69,19 +69,21 @@ class ForestHParams(object):
|
|||||||
# Fail fast if num_classes isn't set.
|
# Fail fast if num_classes isn't set.
|
||||||
_ = getattr(self, 'num_classes')
|
_ = getattr(self, 'num_classes')
|
||||||
|
|
||||||
self.num_trees = getattr(self, 'num_trees', FLAGS.num_trees)
|
self.training_library_base_dir = getattr(
|
||||||
self.max_nodes = getattr(self, 'max_nodes', FLAGS.max_nodes)
|
self, 'training_library_base_dir', '')
|
||||||
|
self.inference_library_base_dir = getattr(
|
||||||
|
self, 'inference_library_base_dir', '')
|
||||||
|
|
||||||
# Allow each tree to be unbalanced by up to a factor of 2.
|
# Allow each tree to be unbalanced by up to a factor of 2.
|
||||||
self.max_depth = getattr(self, 'max_depth',
|
self.max_depth = (self.max_depth or
|
||||||
int(2 * math.ceil(math.log(self.max_nodes, 2))))
|
int(2 * math.ceil(math.log(self.max_nodes, 2))))
|
||||||
|
|
||||||
# The Random Forest literature recommends sqrt(# features) for
|
# The Random Forest literature recommends sqrt(# features) for
|
||||||
# classification problems, and p/3 for regression problems.
|
# classification problems, and p/3 for regression problems.
|
||||||
# TODO(thomaswc): Consider capping this for large number of features.
|
# TODO(thomaswc): Consider capping this for large number of features.
|
||||||
if not getattr(self, 'num_splits_to_consider', None):
|
self.num_splits_to_consider = (
|
||||||
self.num_splits_to_consider = max(10, int(
|
self.num_splits_to_consider or
|
||||||
math.ceil(math.sqrt(self.num_features))))
|
max(10, int(math.ceil(math.sqrt(self.num_features)))))
|
||||||
|
|
||||||
# max_fertile_nodes doesn't effect performance, only training speed.
|
# max_fertile_nodes doesn't effect performance, only training speed.
|
||||||
# We therefore set it primarily based upon space considerations.
|
# We therefore set it primarily based upon space considerations.
|
||||||
@ -91,22 +93,19 @@ class ForestHParams(object):
|
|||||||
num_fertile = int(math.ceil(self.max_nodes / self.num_splits_to_consider))
|
num_fertile = int(math.ceil(self.max_nodes / self.num_splits_to_consider))
|
||||||
# But always use at least 1000 accumulate slots.
|
# But always use at least 1000 accumulate slots.
|
||||||
num_fertile = max(num_fertile, 1000)
|
num_fertile = max(num_fertile, 1000)
|
||||||
self.max_fertile_nodes = getattr(self, 'max_fertile_nodes', num_fertile)
|
self.max_fertile_nodes = self.max_fertile_nodes or num_fertile
|
||||||
# But it also never needs to be larger than the number of leaves,
|
# But it also never needs to be larger than the number of leaves,
|
||||||
# which is max_nodes / 2.
|
# which is max_nodes / 2.
|
||||||
self.max_fertile_nodes = min(self.max_nodes,
|
self.max_fertile_nodes = min(self.max_fertile_nodes,
|
||||||
int(math.ceil(self.max_fertile_nodes / 2.0)))
|
int(math.ceil(self.max_nodes / 2.0)))
|
||||||
|
|
||||||
# split_after_samples and valid_leaf_threshold should be about the same.
|
# split_after_samples and valid_leaf_threshold should be about the same.
|
||||||
# Therefore, if either is set, use it to set the other. Otherwise, fall
|
# Therefore, if either is set, use it to set the other. Otherwise, fall
|
||||||
# back on FLAGS.samples_to_decide.
|
# back on samples_to_decide.
|
||||||
samples_to_decide = (
|
samples_to_decide = self.split_after_samples or self.samples_to_decide
|
||||||
getattr(self, 'split_after_samples',
|
|
||||||
getattr(self, 'valid_leaf_threshold', FLAGS.samples_to_decide)))
|
self.split_after_samples = self.split_after_samples or samples_to_decide
|
||||||
self.split_after_samples = getattr(self, 'split_after_samples',
|
self.valid_leaf_threshold = self.valid_leaf_threshold or samples_to_decide
|
||||||
samples_to_decide)
|
|
||||||
self.valid_leaf_threshold = getattr(self, 'valid_leaf_threshold',
|
|
||||||
samples_to_decide)
|
|
||||||
|
|
||||||
# We have num_splits_to_consider slots to fill, and we want to spend
|
# We have num_splits_to_consider slots to fill, and we want to spend
|
||||||
# approximately split_after_samples samples initializing them.
|
# approximately split_after_samples samples initializing them.
|
||||||
@ -184,23 +183,6 @@ class TreeStats(object):
|
|||||||
self.num_leaves = num_leaves
|
self.num_leaves = num_leaves
|
||||||
|
|
||||||
|
|
||||||
def get_tree_stats(variables, unused_params, session):
|
|
||||||
num_nodes = variables.end_of_tree.eval(session=session) - 1
|
|
||||||
num_leaves = tf.where(
|
|
||||||
tf.equal(tf.squeeze(tf.slice(variables.tree, [0, 0], [-1, 1])),
|
|
||||||
LEAF_NODE)).eval(session=session).shape[0]
|
|
||||||
return TreeStats(num_nodes, num_leaves)
|
|
||||||
|
|
||||||
|
|
||||||
def get_forest_stats(variables, params, session):
|
|
||||||
|
|
||||||
tree_stats = []
|
|
||||||
for i in range(params.num_trees):
|
|
||||||
tree_stats.append(get_tree_stats(variables[i], params, session))
|
|
||||||
|
|
||||||
return ForestStats(tree_stats, params)
|
|
||||||
|
|
||||||
|
|
||||||
class ForestTrainingVariables(object):
|
class ForestTrainingVariables(object):
|
||||||
"""A container for a forests training data, consisting of multiple trees.
|
"""A container for a forests training data, consisting of multiple trees.
|
||||||
|
|
||||||
@ -212,9 +194,11 @@ class ForestTrainingVariables(object):
|
|||||||
... forest_variables.tree ...
|
... forest_variables.tree ...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, params):
|
def __init__(self, params, device_assigner):
|
||||||
self.variables = [TreeTrainingVariables(params)
|
self.variables = []
|
||||||
for _ in range(params.num_trees)]
|
for i in range(params.num_trees):
|
||||||
|
with tf.device(device_assigner.get_device(i)):
|
||||||
|
self.variables.append(TreeTrainingVariables(params))
|
||||||
|
|
||||||
def __setitem__(self, t, val):
|
def __setitem__(self, t, val):
|
||||||
self.variables[t] = val
|
self.variables[t] = val
|
||||||
@ -223,15 +207,41 @@ class ForestTrainingVariables(object):
|
|||||||
return self.variables[t]
|
return self.variables[t]
|
||||||
|
|
||||||
|
|
||||||
|
class RandomForestDeviceAssigner(object):
|
||||||
|
"""A device assigner that uses the default device.
|
||||||
|
|
||||||
|
Write subclasses that implement get_device for control over how trees
|
||||||
|
get assigned to devices. This assumes that whole trees are assigned
|
||||||
|
to a device.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.cached = None
|
||||||
|
|
||||||
|
def get_device(self, unused_tree_num):
|
||||||
|
if not self.cached:
|
||||||
|
dummy = tf.constant(0)
|
||||||
|
self.cached = dummy.device
|
||||||
|
|
||||||
|
return self.cached
|
||||||
|
|
||||||
|
|
||||||
class RandomForestGraphs(object):
|
class RandomForestGraphs(object):
|
||||||
"""Builds TF graphs for random forest training and inference."""
|
"""Builds TF graphs for random forest training and inference."""
|
||||||
|
|
||||||
def __init__(self, params):
|
def __init__(self, params, device_assigner=None, variables=None):
|
||||||
self.params = params
|
self.params = params
|
||||||
self.variables = ForestTrainingVariables(self.params)
|
self.device_assigner = device_assigner or RandomForestDeviceAssigner()
|
||||||
self.trees = [RandomTreeGraphs(self.variables[i], self.params,
|
tf.logging.info('Constructing forest with params = ')
|
||||||
training_ops.Load(), inference_ops.Load())
|
tf.logging.info(self.params.__dict__)
|
||||||
for i in range(self.params.num_trees)]
|
self.variables = variables or ForestTrainingVariables(
|
||||||
|
self.params, device_assigner=self.device_assigner)
|
||||||
|
self.trees = [
|
||||||
|
RandomTreeGraphs(
|
||||||
|
self.variables[i], self.params,
|
||||||
|
training_ops.Load(self.params.training_library_base_dir),
|
||||||
|
inference_ops.Load(self.params.inference_library_base_dir))
|
||||||
|
for i in range(self.params.num_trees)]
|
||||||
|
|
||||||
def training_graph(self, input_data, input_labels):
|
def training_graph(self, input_data, input_labels):
|
||||||
"""Constructs a TF graph for training a random forest.
|
"""Constructs a TF graph for training a random forest.
|
||||||
@ -246,12 +256,26 @@ class RandomForestGraphs(object):
|
|||||||
"""
|
"""
|
||||||
tree_graphs = []
|
tree_graphs = []
|
||||||
for i in range(self.params.num_trees):
|
for i in range(self.params.num_trees):
|
||||||
tf.logging.info('Constructing tree %d', i)
|
with tf.device(self.device_assigner.get_device(i)):
|
||||||
seed = self.params.base_random_seed
|
seed = self.params.base_random_seed
|
||||||
if seed != 0:
|
if seed != 0:
|
||||||
seed += i
|
seed += i
|
||||||
tree_graphs.append(self.trees[i].training_graph(
|
# If using bagging, randomly select some of the input.
|
||||||
input_data, input_labels, seed))
|
tree_data = input_data
|
||||||
|
tree_labels = input_labels
|
||||||
|
if self.params.bagging_fraction < 1.0:
|
||||||
|
# TODO(thomaswc): This does sampling without replacment. Consider
|
||||||
|
# also allowing sampling with replacement as an option.
|
||||||
|
batch_size = tf.slice(tf.shape(input_data), [0], [1])
|
||||||
|
r = tf.random_uniform(batch_size, seed=seed)
|
||||||
|
mask = tf.less(r, tf.ones_like(r) * self.params.bagging_fraction)
|
||||||
|
gather_indices = tf.squeeze(tf.where(mask), squeeze_dims=[1])
|
||||||
|
# TODO(thomaswc): Calculate out-of-bag data and labels, and store
|
||||||
|
# them for use in calculating statistics later.
|
||||||
|
tree_data = tf.gather(input_data, gather_indices)
|
||||||
|
tree_labels = tf.gather(input_labels, gather_indices)
|
||||||
|
tree_graphs.append(
|
||||||
|
self.trees[i].training_graph(tree_data, tree_labels, seed))
|
||||||
return tf.group(*tree_graphs)
|
return tf.group(*tree_graphs)
|
||||||
|
|
||||||
def inference_graph(self, input_data):
|
def inference_graph(self, input_data):
|
||||||
@ -265,9 +289,23 @@ class RandomForestGraphs(object):
|
|||||||
"""
|
"""
|
||||||
probabilities = []
|
probabilities = []
|
||||||
for i in range(self.params.num_trees):
|
for i in range(self.params.num_trees):
|
||||||
probabilities.append(self.trees[i].inference_graph(input_data))
|
with tf.device(self.device_assigner.get_device(i)):
|
||||||
all_predict = tf.pack(probabilities)
|
probabilities.append(self.trees[i].inference_graph(input_data))
|
||||||
return tf.reduce_sum(all_predict, 0) / self.params.num_trees
|
with tf.device(self.device_assigner.get_device(0)):
|
||||||
|
all_predict = tf.pack(probabilities)
|
||||||
|
return tf.reduce_sum(all_predict, 0) / self.params.num_trees
|
||||||
|
|
||||||
|
def average_size(self):
|
||||||
|
"""Constructs a TF graph for evaluating the average size of a forest.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The average number of nodes over the trees.
|
||||||
|
"""
|
||||||
|
sizes = []
|
||||||
|
for i in range(self.params.num_trees):
|
||||||
|
with tf.device(self.device_assigner.get_device(i)):
|
||||||
|
sizes.append(self.trees[i].size())
|
||||||
|
return tf.reduce_mean(tf.pack(sizes))
|
||||||
|
|
||||||
def average_impurity(self):
|
def average_impurity(self):
|
||||||
"""Constructs a TF graph for evaluating the leaf impurity of a forest.
|
"""Constructs a TF graph for evaluating the leaf impurity of a forest.
|
||||||
@ -277,9 +315,17 @@ class RandomForestGraphs(object):
|
|||||||
"""
|
"""
|
||||||
impurities = []
|
impurities = []
|
||||||
for i in range(self.params.num_trees):
|
for i in range(self.params.num_trees):
|
||||||
impurities.append(self.trees[i].average_impurity(self.variables[i]))
|
with tf.device(self.device_assigner.get_device(i)):
|
||||||
|
impurities.append(self.trees[i].average_impurity())
|
||||||
return tf.reduce_mean(tf.pack(impurities))
|
return tf.reduce_mean(tf.pack(impurities))
|
||||||
|
|
||||||
|
def get_stats(self, session):
|
||||||
|
tree_stats = []
|
||||||
|
for i in range(self.params.num_trees):
|
||||||
|
with tf.device(self.device_assigner.get_device(i)):
|
||||||
|
tree_stats.append(self.trees[i].get_stats(session))
|
||||||
|
return ForestStats(tree_stats, self.params)
|
||||||
|
|
||||||
|
|
||||||
class RandomTreeGraphs(object):
|
class RandomTreeGraphs(object):
|
||||||
"""Builds TF graphs for random tree training and inference."""
|
"""Builds TF graphs for random tree training and inference."""
|
||||||
@ -394,6 +440,7 @@ class RandomTreeGraphs(object):
|
|||||||
with tf.control_dependencies([node_update_op]):
|
with tf.control_dependencies([node_update_op]):
|
||||||
def f1():
|
def f1():
|
||||||
return self.variables.non_fertile_leaf_scores
|
return self.variables.non_fertile_leaf_scores
|
||||||
|
|
||||||
def f2():
|
def f2():
|
||||||
counts = tf.gather(self.variables.node_per_class_weights,
|
counts = tf.gather(self.variables.node_per_class_weights,
|
||||||
self.variables.non_fertile_leaves)
|
self.variables.non_fertile_leaves)
|
||||||
@ -535,3 +582,18 @@ class RandomTreeGraphs(object):
|
|||||||
counts = tf.gather(self.variables.node_per_class_weights, leaves)
|
counts = tf.gather(self.variables.node_per_class_weights, leaves)
|
||||||
impurity = self._weighted_gini(counts)
|
impurity = self._weighted_gini(counts)
|
||||||
return tf.reduce_sum(impurity) / tf.reduce_sum(counts + 1.0)
|
return tf.reduce_sum(impurity) / tf.reduce_sum(counts + 1.0)
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
"""Constructs a TF graph for evaluating the current number of nodes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The current number of nodes in the tree.
|
||||||
|
"""
|
||||||
|
return self.variables.end_of_tree - 1
|
||||||
|
|
||||||
|
def get_stats(self, session):
|
||||||
|
num_nodes = self.variables.end_of_tree.eval(session=session) - 1
|
||||||
|
num_leaves = tf.where(
|
||||||
|
tf.equal(tf.squeeze(tf.slice(self.variables.tree, [0, 0], [-1, 1])),
|
||||||
|
LEAF_NODE)).eval(session=session).shape[0]
|
||||||
|
return TreeStats(num_nodes, num_leaves)
|
||||||
|
@ -27,6 +27,37 @@ from tensorflow.python.platform import googletest
|
|||||||
|
|
||||||
class TensorForestTest(test_util.TensorFlowTestCase):
|
class TensorForestTest(test_util.TensorFlowTestCase):
|
||||||
|
|
||||||
|
def testForestHParams(self):
|
||||||
|
hparams = tensor_forest.ForestHParams(
|
||||||
|
num_classes=2, num_trees=100, max_nodes=1000,
|
||||||
|
num_features=60).fill()
|
||||||
|
self.assertEquals(2, hparams.num_classes)
|
||||||
|
# 2 * ceil(log_2(1000)) = 20
|
||||||
|
self.assertEquals(20, hparams.max_depth)
|
||||||
|
# sqrt(num_features) < 10, so num_splits_to_consider should be 10.
|
||||||
|
self.assertEquals(10, hparams.num_splits_to_consider)
|
||||||
|
# Don't have more fertile nodes than max # leaves, which is 500.
|
||||||
|
self.assertEquals(500, hparams.max_fertile_nodes)
|
||||||
|
# We didn't set either of these, so they should be equal
|
||||||
|
self.assertEquals(hparams.split_after_samples,
|
||||||
|
hparams.valid_leaf_threshold)
|
||||||
|
# split_after_samples is larger than 10
|
||||||
|
self.assertEquals(1, hparams.split_initializations_per_input)
|
||||||
|
self.assertEquals(0, hparams.base_random_seed)
|
||||||
|
|
||||||
|
def testForestHParamsBigTree(self):
|
||||||
|
hparams = tensor_forest.ForestHParams(
|
||||||
|
num_classes=2, num_trees=100, max_nodes=1000000,
|
||||||
|
split_after_samples=25,
|
||||||
|
num_features=1000).fill()
|
||||||
|
self.assertEquals(40, hparams.max_depth)
|
||||||
|
# sqrt(1000) = 31.63...
|
||||||
|
self.assertEquals(32, hparams.num_splits_to_consider)
|
||||||
|
# 1000000 / 32 = 31250
|
||||||
|
self.assertEquals(31250, hparams.max_fertile_nodes)
|
||||||
|
# floor(31.63 / 25) = 1
|
||||||
|
self.assertEquals(1, hparams.split_initializations_per_input)
|
||||||
|
|
||||||
def testTrainingConstruction(self):
|
def testTrainingConstruction(self):
|
||||||
input_data = [[-1., 0.], [-1., 2.], # node 1
|
input_data = [[-1., 0.], [-1., 2.], # node 1
|
||||||
[1., 0.], [1., -2.]] # node 2
|
[1., 0.], [1., -2.]] # node 2
|
||||||
@ -50,6 +81,14 @@ class TensorForestTest(test_util.TensorFlowTestCase):
|
|||||||
graph = graph_builder.inference_graph(input_data)
|
graph = graph_builder.inference_graph(input_data)
|
||||||
self.assertTrue(isinstance(graph, tf.Tensor))
|
self.assertTrue(isinstance(graph, tf.Tensor))
|
||||||
|
|
||||||
|
def testImpurityConstruction(self):
|
||||||
|
params = tensor_forest.ForestHParams(
|
||||||
|
num_classes=4, num_features=2, num_trees=10, max_nodes=1000).fill()
|
||||||
|
|
||||||
|
graph_builder = tensor_forest.RandomForestGraphs(params)
|
||||||
|
graph = graph_builder.average_impurity()
|
||||||
|
self.assertTrue(isinstance(graph, tf.Tensor))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
googletest.main()
|
googletest.main()
|
||||||
|
@ -143,7 +143,6 @@ cc_library(
|
|||||||
"lib/core/bits.h",
|
"lib/core/bits.h",
|
||||||
"lib/core/casts.h",
|
"lib/core/casts.h",
|
||||||
"lib/core/coding.h",
|
"lib/core/coding.h",
|
||||||
"lib/core/command_line_flags.h", # TODO(vrv): Delete.
|
|
||||||
"lib/core/errors.h",
|
"lib/core/errors.h",
|
||||||
"lib/core/notification.h",
|
"lib/core/notification.h",
|
||||||
"lib/core/status.h",
|
"lib/core/status.h",
|
||||||
|
@ -35,6 +35,7 @@ limitations under the License.
|
|||||||
#include "tensorflow/core/framework/types.h"
|
#include "tensorflow/core/framework/types.h"
|
||||||
#include "tensorflow/core/lib/core/coding.h"
|
#include "tensorflow/core/lib/core/coding.h"
|
||||||
#include "tensorflow/core/lib/core/errors.h"
|
#include "tensorflow/core/lib/core/errors.h"
|
||||||
|
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||||
#include "tensorflow/core/lib/gtl/stl_util.h"
|
#include "tensorflow/core/lib/gtl/stl_util.h"
|
||||||
#include "tensorflow/core/lib/strings/str_util.h"
|
#include "tensorflow/core/lib/strings/str_util.h"
|
||||||
#include "tensorflow/core/lib/strings/strcat.h"
|
#include "tensorflow/core/lib/strings/strcat.h"
|
||||||
@ -713,4 +714,36 @@ void Tensor::FillDescription(TensorDescription* description) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gtl::InlinedVector<int64, 5> Tensor::ComputeFlatInnerDims(
|
||||||
|
int64 num_out_dims) const {
|
||||||
|
gtl::InlinedVector<int64, 5> out_dims(num_out_dims, 0);
|
||||||
|
const int64 num_elements = NumElements();
|
||||||
|
if (num_elements != 0) {
|
||||||
|
int64 prod_out_dims = 1;
|
||||||
|
for (int64 out_dim = num_out_dims - 1; out_dim > 0; --out_dim) {
|
||||||
|
const int64 in_dim = out_dim + (dims() - num_out_dims);
|
||||||
|
out_dims[out_dim] =
|
||||||
|
(in_dim >= dims() || in_dim < 0) ? 1 : dim_size(in_dim);
|
||||||
|
prod_out_dims *= out_dims[out_dim];
|
||||||
|
}
|
||||||
|
out_dims[0] = num_elements / prod_out_dims;
|
||||||
|
}
|
||||||
|
return out_dims;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtl::InlinedVector<int64, 5> Tensor::ComputeFlatOuterDims(
|
||||||
|
int64 num_out_dims) const {
|
||||||
|
gtl::InlinedVector<int64, 5> out_dims(num_out_dims, 0);
|
||||||
|
const int64 num_elements = NumElements();
|
||||||
|
if (num_elements != 0) {
|
||||||
|
int64 prod_out_dims = 1;
|
||||||
|
for (int64 out_dim = 0; out_dim < num_out_dims - 1; ++out_dim) {
|
||||||
|
out_dims[out_dim] = out_dim >= dims() ? 1 : dim_size(out_dim);
|
||||||
|
prod_out_dims *= out_dims[out_dim];
|
||||||
|
}
|
||||||
|
out_dims[num_out_dims - 1] = num_elements / prod_out_dims;
|
||||||
|
}
|
||||||
|
return out_dims;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tensorflow
|
} // namespace tensorflow
|
||||||
|
@ -28,6 +28,7 @@ limitations under the License.
|
|||||||
#include "tensorflow/core/lib/core/refcount.h"
|
#include "tensorflow/core/lib/core/refcount.h"
|
||||||
#include "tensorflow/core/lib/core/status.h"
|
#include "tensorflow/core/lib/core/status.h"
|
||||||
#include "tensorflow/core/lib/core/stringpiece.h"
|
#include "tensorflow/core/lib/core/stringpiece.h"
|
||||||
|
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||||
#include "tensorflow/core/platform/logging.h"
|
#include "tensorflow/core/platform/logging.h"
|
||||||
#include "tensorflow/core/platform/macros.h"
|
#include "tensorflow/core/platform/macros.h"
|
||||||
#include "tensorflow/core/platform/types.h"
|
#include "tensorflow/core/platform/types.h"
|
||||||
@ -243,40 +244,28 @@ class Tensor {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename TTypes<T>::Flat flat();
|
typename TTypes<T>::Flat flat() {
|
||||||
|
return shaped<T, 1>({NumElements()});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename TTypes<T>::UnalignedFlat unaligned_flat() {
|
typename TTypes<T>::UnalignedFlat unaligned_flat() {
|
||||||
return unaligned_shaped<T, 1>({NumElements()});
|
return unaligned_shaped<T, 1>({NumElements()});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the data as an Eigen::Tensor with 2 dimensions, collapsing all
|
/// Returns the data as an Eigen::Tensor with NDIMS dimensions, collapsing all
|
||||||
/// Tensor dimensions but the last one into the first dimension of the result.
|
/// Tensor dimensions but the last NDIMS-1 into the first dimension of the
|
||||||
template <typename T>
|
/// result. If NDIMS > dims() then leading dimensions of size 1 will be
|
||||||
typename TTypes<T>::Matrix flat_inner_dims() {
|
/// added to make the output rank NDIMS.
|
||||||
int64 last_size = dims() > 0 ? dim_size(dims() - 1) : 1;
|
template <typename T, size_t NDIMS = 2>
|
||||||
if (last_size == 0) {
|
typename TTypes<T, NDIMS>::Tensor flat_inner_dims();
|
||||||
DCHECK_EQ(NumElements(), 0);
|
|
||||||
// Return something empty, avoiding divide by 0
|
|
||||||
return shaped<T, 2>({0, 0});
|
|
||||||
} else {
|
|
||||||
return shaped<T, 2>({NumElements() / last_size, last_size});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the data as an Eigen::Tensor with 2 dimensions, collapsing all
|
/// Returns the data as an Eigen::Tensor with NDIMS dimensions, collapsing all
|
||||||
/// Tensor dimensions but the first one into the last dimension of the result.
|
/// Tensor dimensions but the first NDIMS-1 into the last dimension of the
|
||||||
template <typename T>
|
/// result. If NDIMS > dims() then trailing dimensions of size 1 will be
|
||||||
typename TTypes<T>::Matrix flat_outer_dims() {
|
/// added to make the output rank NDIMS.
|
||||||
int64 first_size = dims() > 0 ? dim_size(0) : 1;
|
template <typename T, size_t NDIMS = 2>
|
||||||
if (first_size == 0) {
|
typename TTypes<T, NDIMS>::Tensor flat_outer_dims();
|
||||||
DCHECK_EQ(NumElements(), 0);
|
|
||||||
// Return something empty, avoiding divide by 0
|
|
||||||
return shaped<T, 2>({0, 0});
|
|
||||||
} else {
|
|
||||||
return shaped<T, 2>({first_size, NumElements() / first_size});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, size_t NDIMS>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T, NDIMS>::Tensor shaped(gtl::ArraySlice<int64> new_sizes);
|
typename TTypes<T, NDIMS>::Tensor shaped(gtl::ArraySlice<int64> new_sizes);
|
||||||
@ -308,31 +297,19 @@ class Tensor {
|
|||||||
typename TTypes<T, NDIMS>::ConstTensor tensor() const;
|
typename TTypes<T, NDIMS>::ConstTensor tensor() const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename TTypes<T>::ConstFlat flat() const;
|
typename TTypes<T>::ConstFlat flat() const {
|
||||||
|
return shaped<T, 1>({NumElements()});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename TTypes<T>::UnalignedConstFlat unaligned_flat() const {
|
typename TTypes<T>::UnalignedConstFlat unaligned_flat() const {
|
||||||
return unaligned_shaped<T, 1>({NumElements()});
|
return unaligned_shaped<T, 1>({NumElements()});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename TTypes<T>::ConstMatrix flat_inner_dims() const {
|
|
||||||
int64 last_size = dims() > 0 ? dim_size(dims() - 1) : 1;
|
|
||||||
if (last_size == 0) {
|
|
||||||
DCHECK_EQ(NumElements(), 0);
|
|
||||||
// Return something empty, avoiding divide by 0
|
|
||||||
return shaped<T, 2>({0, 0});
|
|
||||||
} else {
|
|
||||||
return shaped<T, 2>({NumElements() / last_size, last_size});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename TTypes<T>::ConstMatrix flat_outer_dims() const;
|
|
||||||
|
|
||||||
template <typename T, size_t NDIMS>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T, NDIMS>::ConstTensor shaped(
|
typename TTypes<T, NDIMS>::ConstTensor shaped(
|
||||||
gtl::ArraySlice<int64> new_sizes) const;
|
gtl::ArraySlice<int64> new_sizes) const;
|
||||||
|
|
||||||
template <typename T, size_t NDIMS>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T, NDIMS>::UnalignedConstTensor unaligned_shaped(
|
typename TTypes<T, NDIMS>::UnalignedConstTensor unaligned_shaped(
|
||||||
gtl::ArraySlice<int64> new_sizes) const;
|
gtl::ArraySlice<int64> new_sizes) const;
|
||||||
@ -340,6 +317,12 @@ class Tensor {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
typename TTypes<T>::ConstScalar scalar() const;
|
typename TTypes<T>::ConstScalar scalar() const;
|
||||||
|
|
||||||
|
template <typename T, size_t NDIMS = 2>
|
||||||
|
typename TTypes<T, NDIMS>::ConstTensor flat_inner_dims() const;
|
||||||
|
|
||||||
|
template <typename T, size_t NDIMS = 2>
|
||||||
|
typename TTypes<T, NDIMS>::ConstTensor flat_outer_dims() const;
|
||||||
|
|
||||||
/// Render the first `max_entries` values in `*this` into a string.
|
/// Render the first `max_entries` values in `*this` into a string.
|
||||||
string SummarizeValue(int64 max_entries) const;
|
string SummarizeValue(int64 max_entries) const;
|
||||||
|
|
||||||
@ -378,6 +361,8 @@ class Tensor {
|
|||||||
void FillDimsAndValidateCompatibleShape(
|
void FillDimsAndValidateCompatibleShape(
|
||||||
gtl::ArraySlice<int64> new_sizes,
|
gtl::ArraySlice<int64> new_sizes,
|
||||||
Eigen::array<Eigen::DenseIndex, NDIMS>* dims) const;
|
Eigen::array<Eigen::DenseIndex, NDIMS>* dims) const;
|
||||||
|
gtl::InlinedVector<int64, 5> ComputeFlatInnerDims(int64 num_out_dims) const;
|
||||||
|
gtl::InlinedVector<int64, 5> ComputeFlatOuterDims(int64 num_out_dims) const;
|
||||||
|
|
||||||
TensorShape shape_;
|
TensorShape shape_;
|
||||||
TensorBuffer* buf_;
|
TensorBuffer* buf_;
|
||||||
@ -534,26 +519,24 @@ typename TTypes<T>::ConstScalar Tensor::scalar() const {
|
|||||||
return typename TTypes<T>::ConstScalar(base<T>());
|
return typename TTypes<T>::ConstScalar(base<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T>::Flat Tensor::flat() {
|
typename TTypes<T, NDIMS>::Tensor Tensor::flat_inner_dims() {
|
||||||
return shaped<T, 1>({NumElements()});
|
return shaped<T, NDIMS>(ComputeFlatInnerDims(NDIMS));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T>::ConstFlat Tensor::flat() const {
|
typename TTypes<T, NDIMS>::Tensor Tensor::flat_outer_dims() {
|
||||||
return shaped<T, 1>({NumElements()});
|
return shaped<T, NDIMS>(ComputeFlatOuterDims(NDIMS));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, size_t NDIMS>
|
||||||
typename TTypes<T>::ConstMatrix Tensor::flat_outer_dims() const {
|
typename TTypes<T, NDIMS>::ConstTensor Tensor::flat_inner_dims() const {
|
||||||
int64 first_size = dims() > 0 ? dim_size(0) : 1;
|
return shaped<T, NDIMS>(ComputeFlatInnerDims(NDIMS));
|
||||||
if (first_size == 0) {
|
}
|
||||||
DCHECK_EQ(NumElements(), 0);
|
|
||||||
// Return something empty, avoiding divide by 0
|
template <typename T, size_t NDIMS>
|
||||||
return shaped<T, 2>({0, 0});
|
typename TTypes<T, NDIMS>::ConstTensor Tensor::flat_outer_dims() const {
|
||||||
} else {
|
return shaped<T, NDIMS>(ComputeFlatOuterDims(NDIMS));
|
||||||
return shaped<T, 2>({first_size, NumElements() / first_size});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tensorflow
|
} // namespace tensorflow
|
||||||
|
@ -224,6 +224,49 @@ TEST(Tensor_Float, Reshape) {
|
|||||||
EXPECT_EQ(flat_inner_dims(0, 0), 0.01f);
|
EXPECT_EQ(flat_inner_dims(0, 0), 0.01f);
|
||||||
EXPECT_EQ(flat_inner_dims(23, 4), 0.02f);
|
EXPECT_EQ(flat_inner_dims(23, 4), 0.02f);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto flat_outer_dims = t.flat_outer_dims<float>();
|
||||||
|
EXPECT_EQ(2, flat_outer_dims.dimension(0));
|
||||||
|
EXPECT_EQ(60, flat_outer_dims.dimension(1));
|
||||||
|
EXPECT_EQ(flat_outer_dims(0, 0), 0.01f);
|
||||||
|
EXPECT_EQ(flat_outer_dims(1, 59), 0.02f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto flat_inner_dims = t.flat_inner_dims<float, 3>();
|
||||||
|
EXPECT_EQ(6, flat_inner_dims.dimension(0));
|
||||||
|
EXPECT_EQ(4, flat_inner_dims.dimension(1));
|
||||||
|
EXPECT_EQ(5, flat_inner_dims.dimension(2));
|
||||||
|
EXPECT_EQ(flat_inner_dims(0, 0, 0), 0.01f);
|
||||||
|
EXPECT_EQ(flat_inner_dims(5, 3, 4), 0.02f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto flat_outer_dims = t.flat_outer_dims<float, 3>();
|
||||||
|
EXPECT_EQ(2, flat_outer_dims.dimension(0));
|
||||||
|
EXPECT_EQ(3, flat_outer_dims.dimension(1));
|
||||||
|
EXPECT_EQ(20, flat_outer_dims.dimension(2));
|
||||||
|
EXPECT_EQ(flat_outer_dims(0, 0, 0), 0.01f);
|
||||||
|
EXPECT_EQ(flat_outer_dims(1, 2, 19), 0.02f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto flat_inner_dims = t.flat_inner_dims<float, 5>();
|
||||||
|
EXPECT_EQ(1, flat_inner_dims.dimension(0));
|
||||||
|
EXPECT_EQ(2, flat_inner_dims.dimension(1));
|
||||||
|
EXPECT_EQ(3, flat_inner_dims.dimension(2));
|
||||||
|
EXPECT_EQ(4, flat_inner_dims.dimension(3));
|
||||||
|
EXPECT_EQ(5, flat_inner_dims.dimension(4));
|
||||||
|
EXPECT_EQ(flat_inner_dims(0, 0, 0, 0, 0), 0.01f);
|
||||||
|
EXPECT_EQ(flat_inner_dims(0, 1, 2, 3, 4), 0.02f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto flat_outer_dims = t.flat_outer_dims<float, 5>();
|
||||||
|
EXPECT_EQ(2, flat_outer_dims.dimension(0));
|
||||||
|
EXPECT_EQ(3, flat_outer_dims.dimension(1));
|
||||||
|
EXPECT_EQ(4, flat_outer_dims.dimension(2));
|
||||||
|
EXPECT_EQ(5, flat_outer_dims.dimension(3));
|
||||||
|
EXPECT_EQ(1, flat_outer_dims.dimension(4));
|
||||||
|
EXPECT_EQ(flat_outer_dims(0, 0, 0, 0, 0), 0.01f);
|
||||||
|
EXPECT_EQ(flat_outer_dims(1, 2, 3, 4, 0), 0.02f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tensor_Scalar, Basics) {
|
TEST(Tensor_Scalar, Basics) {
|
||||||
|
@ -305,6 +305,23 @@ tf_kernel_libraries(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tf_cc_test(
|
||||||
|
name = "batch_norm_op_test",
|
||||||
|
size = "small",
|
||||||
|
deps = [
|
||||||
|
":batch_norm_op",
|
||||||
|
":ops_testutil",
|
||||||
|
":ops_util",
|
||||||
|
"//tensorflow/core:core_cpu",
|
||||||
|
"//tensorflow/core:framework",
|
||||||
|
"//tensorflow/core:lib",
|
||||||
|
"//tensorflow/core:protos_all_cc",
|
||||||
|
"//tensorflow/core:test",
|
||||||
|
"//tensorflow/core:test_main",
|
||||||
|
"//tensorflow/core:testlib",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
tf_cc_test(
|
tf_cc_test(
|
||||||
name = "concat_op_test",
|
name = "concat_op_test",
|
||||||
size = "small",
|
size = "small",
|
||||||
|
62
tensorflow/core/kernels/batch_norm_op_test.cc
Normal file
62
tensorflow/core/kernels/batch_norm_op_test.cc
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "tensorflow/core/framework/allocator.h"
|
||||||
|
#include "tensorflow/core/framework/fake_input.h"
|
||||||
|
#include "tensorflow/core/framework/graph.pb.h"
|
||||||
|
#include "tensorflow/core/framework/node_def_builder.h"
|
||||||
|
#include "tensorflow/core/framework/op_kernel.h"
|
||||||
|
#include "tensorflow/core/framework/tensor.h"
|
||||||
|
#include "tensorflow/core/framework/tensor_testutil.h"
|
||||||
|
#include "tensorflow/core/framework/types.h"
|
||||||
|
#include "tensorflow/core/framework/types.pb.h"
|
||||||
|
#include "tensorflow/core/kernels/ops_testutil.h"
|
||||||
|
#include "tensorflow/core/kernels/ops_util.h"
|
||||||
|
#include "tensorflow/core/lib/core/status_test_util.h"
|
||||||
|
#include "tensorflow/core/platform/test.h"
|
||||||
|
|
||||||
|
namespace tensorflow {
|
||||||
|
|
||||||
|
class BatchNormOpTest : public OpsTestBase {};
|
||||||
|
|
||||||
|
TEST_F(BatchNormOpTest, Simple) {
|
||||||
|
TF_EXPECT_OK(
|
||||||
|
NodeDefBuilder("batch_norm_op", "BatchNormWithGlobalNormalization")
|
||||||
|
.Input(FakeInput(DT_FLOAT))
|
||||||
|
.Input(FakeInput(DT_FLOAT))
|
||||||
|
.Input(FakeInput(DT_FLOAT))
|
||||||
|
.Input(FakeInput(DT_FLOAT))
|
||||||
|
.Input(FakeInput(DT_FLOAT))
|
||||||
|
.Attr("scale_after_normalization", false)
|
||||||
|
.Attr("variance_epsilon", 0.001)
|
||||||
|
.Finalize(node_def()));
|
||||||
|
TF_EXPECT_OK(InitOpWithGraphVersion(8));
|
||||||
|
AddInputFromArray<float>(TensorShape({1, 1, 6, 2}),
|
||||||
|
{1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6});
|
||||||
|
AddInputFromArray<float>(TensorShape({2}), {10, 20});
|
||||||
|
AddInputFromArray<float>(TensorShape({2}), {0.25, 0.5});
|
||||||
|
AddInputFromArray<float>(TensorShape({2}), {0.1, 0.6});
|
||||||
|
AddInputFromArray<float>(TensorShape({2}), {0.0, 0.0});
|
||||||
|
TF_ASSERT_OK(RunOpKernel());
|
||||||
|
|
||||||
|
Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 6, 2}));
|
||||||
|
test::FillValues<float>(
|
||||||
|
&expected, {-17.86, -22.00, -15.87, -20.59, -13.87, -19.18, -21.86,
|
||||||
|
-33.31, -23.85, -34.72, -25.85, -36.13});
|
||||||
|
test::ExpectTensorNear<float>(expected, *GetOutput(0), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tensorflow
|
@ -94,10 +94,13 @@ class OpsTestBase : public ::testing::Test {
|
|||||||
// and output types as output.
|
// and output types as output.
|
||||||
//
|
//
|
||||||
// Returns the status of initialization.
|
// Returns the status of initialization.
|
||||||
Status InitOp() {
|
Status InitOp() { return InitOpWithGraphVersion(TF_GRAPH_DEF_VERSION); }
|
||||||
|
|
||||||
|
// Only use this directly if you have a deprecated op that you need to test.
|
||||||
|
Status InitOpWithGraphVersion(int graph_def_version) {
|
||||||
Status status;
|
Status status;
|
||||||
kernel_ = CreateOpKernel(device_type_, device_.get(), allocator(),
|
kernel_ = CreateOpKernel(device_type_, device_.get(), allocator(),
|
||||||
node_def_, TF_GRAPH_DEF_VERSION, &status);
|
node_def_, graph_def_version, &status);
|
||||||
if (kernel_ != nullptr) input_types_ = kernel_->input_types();
|
if (kernel_ != nullptr) input_types_ = kernel_->input_types();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T MaybeConj(T v) {
|
|||||||
#define MAYBE_CONJ(T) \
|
#define MAYBE_CONJ(T) \
|
||||||
template <> \
|
template <> \
|
||||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T MaybeConj<T>(T v) { \
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T MaybeConj<T>(T v) { \
|
||||||
return std::conj(v); \
|
return Eigen::numext::conj(v); \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
#include "tensorflow/core/lib/core/command_line_flags.h"
|
|
||||||
|
|
||||||
#include "tensorflow/core/lib/strings/str_util.h"
|
|
||||||
#include "tensorflow/core/lib/strings/strcat.h"
|
|
||||||
#include "tensorflow/core/lib/strings/stringprintf.h"
|
|
||||||
|
|
||||||
namespace tensorflow {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Templated function to convert a string to target values.
|
|
||||||
// Return true if the conversion is successful. Otherwise, return false.
|
|
||||||
template <typename T>
|
|
||||||
bool StringToValue(const string& content, T* value);
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool StringToValue<int32>(const string& content, int32* value) {
|
|
||||||
return strings::safe_strto32(content, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool StringToValue<string>(const string& content, string* value) {
|
|
||||||
*value = content;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a single argument by linearly searching through the command table.
|
|
||||||
// The input format is: --argument=value.
|
|
||||||
// Return OK if the argument is used. It store the extracted value into the
|
|
||||||
// matching flag.
|
|
||||||
// Return NOT_FOUND if the argument is not recognized.
|
|
||||||
// Return INVALID_ARGUMENT if the command is recognized, but fails to extract
|
|
||||||
// its value.
|
|
||||||
template <typename T>
|
|
||||||
Status ParseArgument(const string& argument) {
|
|
||||||
for (auto& command :
|
|
||||||
internal::CommandLineFlagRegistry<T>::Instance()->commands) {
|
|
||||||
string prefix = strings::StrCat("--", command.name, "=");
|
|
||||||
if (tensorflow::StringPiece(argument).starts_with(prefix)) {
|
|
||||||
string content = argument.substr(prefix.length());
|
|
||||||
if (StringToValue<T>(content, command.value)) {
|
|
||||||
return Status::OK();
|
|
||||||
}
|
|
||||||
return Status(error::INVALID_ARGUMENT,
|
|
||||||
strings::StrCat("Cannot parse integer in: ", argument));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Status(error::NOT_FOUND,
|
|
||||||
strings::StrCat("Unknown command: ", argument));
|
|
||||||
}
|
|
||||||
|
|
||||||
// A specialization for booleans. The input format is:
|
|
||||||
// "--argument" or "--noargument".
|
|
||||||
// Parse a single argument by linearly searching through the command table.
|
|
||||||
// Return OK if the argument is used. The value is stored in the matching flag.
|
|
||||||
// Return NOT_FOUND if the argument is not recognized.
|
|
||||||
template <>
|
|
||||||
Status ParseArgument<bool>(const string& argument) {
|
|
||||||
for (auto& command :
|
|
||||||
internal::CommandLineFlagRegistry<bool>::Instance()->commands) {
|
|
||||||
if (argument == strings::StrCat("--", command.name)) {
|
|
||||||
*command.value = true;
|
|
||||||
return Status::OK();
|
|
||||||
} else if (argument == strings::StrCat("--no", command.name)) {
|
|
||||||
*command.value = false;
|
|
||||||
return Status::OK();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Status(error::NOT_FOUND,
|
|
||||||
strings::StrCat("Unknown command: ", argument));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Status ParseCommandLineFlags(int* argc, char* argv[]) {
|
|
||||||
int unused_argc = 1;
|
|
||||||
for (int index = 1; index < *argc; ++index) {
|
|
||||||
Status s;
|
|
||||||
// Search bool commands.
|
|
||||||
s = ParseArgument<bool>(argv[index]);
|
|
||||||
if (s.ok()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (s.code() != error::NOT_FOUND) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
// Search int32 commands.
|
|
||||||
s = ParseArgument<int32>(argv[index]);
|
|
||||||
if (s.ok()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Search string commands.
|
|
||||||
s = ParseArgument<string>(argv[index]);
|
|
||||||
if (s.ok()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (s.code() != error::NOT_FOUND) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
// Pointer swap the unused argument to the front.
|
|
||||||
std::swap(argv[unused_argc++], argv[index]);
|
|
||||||
}
|
|
||||||
*argc = unused_argc;
|
|
||||||
return Status::OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tensorflow
|
|
@ -1,80 +0,0 @@
|
|||||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
#ifndef TENSORFLOW_LIB_CORE_COMMAND_LINE_FLAGS_H_
|
|
||||||
#define TENSORFLOW_LIB_CORE_COMMAND_LINE_FLAGS_H_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "tensorflow/core/lib/core/status.h"
|
|
||||||
#include "tensorflow/core/platform/macros.h"
|
|
||||||
#include "tensorflow/core/platform/types.h"
|
|
||||||
|
|
||||||
namespace tensorflow {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct CommandLineFlagRegistry {
|
|
||||||
static CommandLineFlagRegistry* Instance() {
|
|
||||||
static CommandLineFlagRegistry instance_;
|
|
||||||
return &instance_;
|
|
||||||
}
|
|
||||||
struct Command {
|
|
||||||
string name;
|
|
||||||
T* value;
|
|
||||||
string text;
|
|
||||||
};
|
|
||||||
std::vector<Command> commands;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CommandLineFlagRegistry() {}
|
|
||||||
TF_DISALLOW_COPY_AND_ASSIGN(CommandLineFlagRegistry);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct CommandLineFlagRegister {
|
|
||||||
CommandLineFlagRegister(const string& name, T* val, const string& text) {
|
|
||||||
CommandLineFlagRegistry<T>::Instance()->commands.push_back(
|
|
||||||
{name, val, text});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TF_DEFINE_variable(type, name, default_value, text) \
|
|
||||||
type FLAGS_##name = default_value; \
|
|
||||||
namespace TF_flags_internal { \
|
|
||||||
tensorflow::internal::CommandLineFlagRegister<type> \
|
|
||||||
TF_flags_internal_var_##name(#name, &FLAGS_##name, text); \
|
|
||||||
} // namespace TF_flags_internal
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
#define TF_DEFINE_int32(name, default_value, text) \
|
|
||||||
TF_DEFINE_variable(tensorflow::int32, name, default_value, text);
|
|
||||||
|
|
||||||
#define TF_DEFINE_bool(name, default_value, text) \
|
|
||||||
TF_DEFINE_variable(bool, name, default_value, text);
|
|
||||||
|
|
||||||
#define TF_DEFINE_string(name, default_value, text) \
|
|
||||||
TF_DEFINE_variable(string, name, default_value, text);
|
|
||||||
|
|
||||||
// Parse argv[1]..argv[*argc-1] to options. Remove used arguments from the argv.
|
|
||||||
// Returned the number of unused arguments in *argc.
|
|
||||||
// Return error Status if the parsing encounters errors.
|
|
||||||
// TODO(opensource): switch to a command line argument parser that can be
|
|
||||||
// shared with other tests.
|
|
||||||
Status ParseCommandLineFlags(int* argc, char* argv[]);
|
|
||||||
|
|
||||||
} // namespace tensorflow
|
|
||||||
|
|
||||||
#endif // TENSORFLOW_LIB_CORE_COMMAND_LINE_FLAGS_H_
|
|
@ -20,7 +20,7 @@ limitations under the License.
|
|||||||
|
|
||||||
#define TF_MAJOR_VERSION 0
|
#define TF_MAJOR_VERSION 0
|
||||||
#define TF_MINOR_VERSION 8
|
#define TF_MINOR_VERSION 8
|
||||||
#define TF_PATCH_VERSION 0rc0
|
#define TF_PATCH_VERSION 0
|
||||||
|
|
||||||
// TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1",
|
// TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1",
|
||||||
// "-beta", "-rc", "-rc.1")
|
// "-beta", "-rc", "-rc.1")
|
||||||
|
@ -120,9 +120,12 @@ variable to its initial value.
|
|||||||
##### Args:
|
##### Args:
|
||||||
|
|
||||||
|
|
||||||
* <b>`initial_value`</b>: A `Tensor`, or Python object convertible to a `Tensor`.
|
* <b>`initial_value`</b>: A `Tensor`, or Python object convertible to a `Tensor`,
|
||||||
The initial value for the Variable. Must have a shape specified unless
|
which is the initial value for the Variable. The initial value must have
|
||||||
`validate_shape` is set to False.
|
a shape specified unless `validate_shape` is set to False. Can also be a
|
||||||
|
callable with no argument that returns the initial value when called. In
|
||||||
|
that case, `dtype` must be specified. (Note that initializer functions
|
||||||
|
from init_ops.py must first be bound to a shape before being used here.)
|
||||||
* <b>`trainable`</b>: If `True`, the default, also adds the variable to the graph
|
* <b>`trainable`</b>: If `True`, the default, also adds the variable to the graph
|
||||||
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
||||||
the default list of variables to use by the `Optimizer` classes.
|
the default list of variables to use by the `Optimizer` classes.
|
||||||
|
@ -1955,6 +1955,7 @@ on the parameters to the constructor and may include:
|
|||||||
##### Raises:
|
##### Raises:
|
||||||
|
|
||||||
|
|
||||||
|
* <b>`RuntimeError`</b>: If called with a non-chief Supervisor.
|
||||||
* <b>`ValueError`</b>: If not `logdir` was passed to the constructor as the
|
* <b>`ValueError`</b>: If not `logdir` was passed to the constructor as the
|
||||||
services need a log directory.
|
services need a log directory.
|
||||||
|
|
||||||
@ -2182,6 +2183,7 @@ on the parameters to the constructor and may include:
|
|||||||
##### Raises:
|
##### Raises:
|
||||||
|
|
||||||
|
|
||||||
|
* <b>`RuntimeError`</b>: If called with a non-chief Supervisor.
|
||||||
* <b>`ValueError`</b>: If not `logdir` was passed to the constructor as the
|
* <b>`ValueError`</b>: If not `logdir` was passed to the constructor as the
|
||||||
services need a log directory.
|
services need a log directory.
|
||||||
|
|
||||||
@ -2409,7 +2411,7 @@ Start threads for `QueueRunners`.
|
|||||||
|
|
||||||
#### `tf.train.Supervisor.summary_op` {#Supervisor.summary_op}
|
#### `tf.train.Supervisor.summary_op` {#Supervisor.summary_op}
|
||||||
|
|
||||||
Return the Summary Tensor used by the supervisor.
|
Return the Summary Tensor used by the chief supervisor.
|
||||||
|
|
||||||
##### Returns:
|
##### Returns:
|
||||||
|
|
||||||
@ -2420,7 +2422,7 @@ Return the Summary Tensor used by the supervisor.
|
|||||||
|
|
||||||
#### `tf.train.Supervisor.summary_writer` {#Supervisor.summary_writer}
|
#### `tf.train.Supervisor.summary_writer` {#Supervisor.summary_writer}
|
||||||
|
|
||||||
Return the SummaryWriter used by the supervisor.
|
Return the SummaryWriter used by the chief supervisor.
|
||||||
|
|
||||||
##### Returns:
|
##### Returns:
|
||||||
|
|
||||||
|
@ -7,8 +7,10 @@ github source.
|
|||||||
|
|
||||||
The TensorFlow Python API supports Python 2.7 and Python 3.3+.
|
The TensorFlow Python API supports Python 2.7 and Python 3.3+.
|
||||||
|
|
||||||
The GPU version (Linux only) requires the Cuda Toolkit >= 7.0 and cuDNN >=
|
The GPU version (Linux only) works best with Cuda Toolkit 7.5 and
|
||||||
v2. Please see [Cuda installation](#optional-install-cuda-gpus-on-linux)
|
cuDNN v4. other versions are supported (Cuda toolkit >= 7.0 and
|
||||||
|
cuDNN 6.5(v2), 7.0(v3), v5) only when installing from sources.
|
||||||
|
Please see [Cuda installation](#optional-install-cuda-gpus-on-linux)
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@ -20,10 +22,13 @@ We support different ways to install TensorFlow:
|
|||||||
Python programs on your machine.
|
Python programs on your machine.
|
||||||
* [Virtualenv install](#virtualenv-installation): Install TensorFlow in its own
|
* [Virtualenv install](#virtualenv-installation): Install TensorFlow in its own
|
||||||
directory, not impacting any existing Python programs on your machine.
|
directory, not impacting any existing Python programs on your machine.
|
||||||
|
* [Anaconda install](#anaconda-environment-installation): Install TensorFlow in its own
|
||||||
|
environment for those running the Anaconda Python distribution. Does not
|
||||||
|
impact existing Python programs on your machine.
|
||||||
* [Docker install](#docker-installation): Run TensorFlow in a Docker container
|
* [Docker install](#docker-installation): Run TensorFlow in a Docker container
|
||||||
isolated from all other programs on your machine.
|
isolated from all other programs on your machine.
|
||||||
|
|
||||||
If you are familiar with Pip, Virtualenv, or Docker, please feel free to adapt
|
If you are familiar with Pip, Virtualenv, Anaconda, or Docker, please feel free to adapt
|
||||||
the instructions to your particular needs. The names of the pip and Docker
|
the instructions to your particular needs. The names of the pip and Docker
|
||||||
images are listed in the corresponding installation sections.
|
images are listed in the corresponding installation sections.
|
||||||
|
|
||||||
@ -53,28 +58,30 @@ Install TensorFlow:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ubuntu/Linux 64-bit, CPU only:
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, GPU enabled:
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
# other versions, see "Install from sources" below.
|
||||||
|
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Mac OS X, CPU only:
|
# Mac OS X, CPU only:
|
||||||
$ sudo easy_install --upgrade six
|
$ sudo easy_install --upgrade six
|
||||||
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0rc0-py2-none-any.whl
|
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py2-none-any.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
For python3:
|
For python3:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ubuntu/Linux 64-bit, CPU only:
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl
|
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, GPU enabled:
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl
|
# other versions, see "Install from sources" below.
|
||||||
|
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
# Mac OS X, CPU only:
|
# Mac OS X, CPU only:
|
||||||
$ sudo easy_install --upgrade six
|
$ sudo easy_install --upgrade six
|
||||||
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0rc0-py3-none-any.whl
|
$ sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py3-none-any.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: If you are upgrading from a previous installation of TensorFlow < 0.7.1,
|
NOTE: If you are upgrading from a previous installation of TensorFlow < 0.7.1,
|
||||||
@ -126,13 +133,14 @@ $ source ~/tensorflow/bin/activate.csh # If using csh
|
|||||||
(tensorflow)$ # Your prompt should change
|
(tensorflow)$ # Your prompt should change
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, CPU only:
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, GPU enabled:
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
# other versions, see "Install from sources" below.
|
||||||
|
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Mac OS X, CPU only:
|
# Mac OS X, CPU only:
|
||||||
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0rc0-py2-none-any.whl
|
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py2-none-any.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
and again for python3:
|
and again for python3:
|
||||||
@ -143,13 +151,14 @@ $ source ~/tensorflow/bin/activate.csh # If using csh
|
|||||||
(tensorflow)$ # Your prompt should change
|
(tensorflow)$ # Your prompt should change
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, CPU only:
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl
|
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
# Ubuntu/Linux 64-bit, GPU enabled:
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0rc0-cp34-cp34m-linux_x86_64.whl
|
# other versions, see "Install from sources" below.
|
||||||
|
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
# Mac OS X, CPU only:
|
# Mac OS X, CPU only:
|
||||||
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0rc0-py3-none-any.whl
|
(tensorflow)$ pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py3-none-any.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
With the Virtualenv environment activated, you can now
|
With the Virtualenv environment activated, you can now
|
||||||
@ -175,6 +184,95 @@ $ source ~/tensorflow/bin/activate.csh # If using csh.
|
|||||||
(tensorflow)$ deactivate
|
(tensorflow)$ deactivate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Anaconda environment installation
|
||||||
|
|
||||||
|
[Anaconda](https://www.continuum.io/why-anaconda) is a Python distribution that
|
||||||
|
includes a large number of standard numeric and scientific computing packages.
|
||||||
|
Anaconda uses a package manager called "conda" that has its own
|
||||||
|
[environment system](http://conda.pydata.org/docs/using/envs.html) similar to Virtualenv.
|
||||||
|
|
||||||
|
As with Virtualenv, conda environments keep the dependencies required by
|
||||||
|
different Python projects in separate places. The Anaconda environment
|
||||||
|
installation of TensorFlow will not override pre-existing version of the Python
|
||||||
|
packages needed by TensorFlow.
|
||||||
|
|
||||||
|
* Install Anaconda.
|
||||||
|
* Create a conda environment.
|
||||||
|
* Activate the conda environment and install TensorFlow in it.
|
||||||
|
* After the install you will activate the conda environment each time you
|
||||||
|
want to use TensorFlow.
|
||||||
|
|
||||||
|
Install Anaconda:
|
||||||
|
|
||||||
|
Follow the instructions on the [Anaconda download site](https://www.continuum.io/downloads)
|
||||||
|
|
||||||
|
Create a conda environment called `tensorflow`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python 2.7
|
||||||
|
$ conda create -n tensorflow python=2.7
|
||||||
|
|
||||||
|
# Python 3.5
|
||||||
|
$ conda create -n tensorflow python=3.5
|
||||||
|
```
|
||||||
|
|
||||||
|
Activate the environment and use pip to install TensorFlow inside it.
|
||||||
|
Use the `--ignore-installed` flag to prevent errors about `easy_install`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ source activate tensorflow
|
||||||
|
(tensorflow)$ # Your prompt should change
|
||||||
|
|
||||||
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
|
# other versions, see "Install from sources" below.
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
|
# Mac OS X, CPU only:
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py2-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
and again for Python 3:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ source activate tensorflow
|
||||||
|
(tensorflow)$ # Your prompt should change
|
||||||
|
|
||||||
|
# Ubuntu/Linux 64-bit, CPU only:
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
|
# Ubuntu/Linux 64-bit, GPU enabled. Requires CUDA toolkit 7.5 and CuDNN v4. For
|
||||||
|
# other versions, see "Install from sources" below.
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.0-cp34-cp34m-linux_x86_64.whl
|
||||||
|
|
||||||
|
# Mac OS X, CPU only:
|
||||||
|
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py3-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
With the conda environment activated, you can now
|
||||||
|
[test your installation](#test-the-tensorflow-installation).
|
||||||
|
|
||||||
|
When you are done using TensorFlow, deactivate the environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
(tensorflow)$ source deactivate
|
||||||
|
|
||||||
|
$ # Your prompt should change back
|
||||||
|
```
|
||||||
|
|
||||||
|
To use TensorFlow later you will have to activate the conda environment again:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ source activate tensorflow
|
||||||
|
(tensorflow)$ # Your prompt should change.
|
||||||
|
# Run Python programs that use TensorFlow.
|
||||||
|
...
|
||||||
|
# When you are done using TensorFlow, deactivate the environment.
|
||||||
|
(tensorflow)$ source deactivate
|
||||||
|
```
|
||||||
|
|
||||||
## Docker installation
|
## Docker installation
|
||||||
|
|
||||||
[Docker](http://docker.com/) is a system to build self contained versions of a
|
[Docker](http://docker.com/) is a system to build self contained versions of a
|
||||||
@ -191,7 +289,7 @@ code.
|
|||||||
* `gcr.io/tensorflow/tensorflow:latest-devel-gpu`: GPU Binary image plus source
|
* `gcr.io/tensorflow/tensorflow:latest-devel-gpu`: GPU Binary image plus source
|
||||||
code.
|
code.
|
||||||
|
|
||||||
We also have tags with `latest` replaced by a released version (e.g., `0.8.0rc0-gpu`).
|
We also have tags with `latest` replaced by a released version (e.g., `0.8.0-gpu`).
|
||||||
|
|
||||||
With Docker the installation is as follows:
|
With Docker the installation is as follows:
|
||||||
|
|
||||||
@ -229,7 +327,7 @@ You can now [test your installation](#test-the-tensorflow-installation) within t
|
|||||||
### (Optional, Linux) Enable GPU Support
|
### (Optional, Linux) Enable GPU Support
|
||||||
|
|
||||||
If you installed the GPU version of TensorFlow, you must also install the Cuda
|
If you installed the GPU version of TensorFlow, you must also install the Cuda
|
||||||
Toolkit 7.0 and cuDNN v2. Please see [Cuda installation](#optional-install-cuda-gpus-on-linux).
|
Toolkit 7.5 and cuDNN v4. Please see [Cuda installation](#optional-install-cuda-gpus-on-linux).
|
||||||
|
|
||||||
You also need to set the `LD_LIBRARY_PATH` and `CUDA_HOME` environment
|
You also need to set the `LD_LIBRARY_PATH` and `CUDA_HOME` environment
|
||||||
variables. Consider adding the commands below to your `~/.bash_profile`. These
|
variables. Consider adding the commands below to your `~/.bash_profile`. These
|
||||||
@ -370,20 +468,25 @@ Supported cards include but are not limited to:
|
|||||||
|
|
||||||
https://developer.nvidia.com/cuda-downloads
|
https://developer.nvidia.com/cuda-downloads
|
||||||
|
|
||||||
|
Install version 7.5 if using our binary releases.
|
||||||
|
|
||||||
Install the toolkit into e.g. `/usr/local/cuda`
|
Install the toolkit into e.g. `/usr/local/cuda`
|
||||||
|
|
||||||
##### Download and install cuDNN
|
##### Download and install cuDNN
|
||||||
|
|
||||||
https://developer.nvidia.com/cudnn
|
https://developer.nvidia.com/cudnn
|
||||||
|
|
||||||
|
Download cuDNN v4 (v5 is currently a release candidate and is only supported when
|
||||||
|
installing TensorFlow from sources).
|
||||||
|
|
||||||
Uncompress and copy the cuDNN files into the toolkit directory. Assuming the
|
Uncompress and copy the cuDNN files into the toolkit directory. Assuming the
|
||||||
toolkit is installed in `/usr/local/cuda`, run the following commands (edited
|
toolkit is installed in `/usr/local/cuda`, run the following commands (edited
|
||||||
to reflect the cuDNN version you downloaded):
|
to reflect the cuDNN version you downloaded):
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
tar xvzf cudnn-6.5-linux-x64-v2.tgz
|
tar xvzf cudnn-7.5-linux-x64-v4.tgz
|
||||||
sudo cp cudnn-6.5-linux-x64-v2/cudnn.h /usr/local/cuda/include
|
sudo cp cudnn-7.5-linux-x64-v4/cudnn.h /usr/local/cuda/include
|
||||||
sudo cp cudnn-6.5-linux-x64-v2/libcudnn* /usr/local/cuda/lib64
|
sudo cp cudnn-7.5-linux-x64-v4/libcudnn* /usr/local/cuda/lib64
|
||||||
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*
|
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -517,7 +620,7 @@ $ bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_pack
|
|||||||
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
|
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
|
||||||
|
|
||||||
# The name of the .whl file will depend on your platform.
|
# The name of the .whl file will depend on your platform.
|
||||||
$ pip install /tmp/tensorflow_pkg/tensorflow-0.8.0rc0-py2-none-linux_x86_64.whl
|
$ pip install /tmp/tensorflow_pkg/tensorflow-0.8.0-py2-none-linux_x86_64.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting up TensorFlow for Development
|
## Setting up TensorFlow for Development
|
||||||
|
@ -8,7 +8,7 @@ writing TensorFlow programs.
|
|||||||
## Hello distributed TensorFlow!
|
## Hello distributed TensorFlow!
|
||||||
|
|
||||||
This tutorial assumes that you are using a TensorFlow nightly build. You
|
This tutorial assumes that you are using a TensorFlow nightly build. You
|
||||||
can test your installation by starting a local server as follows:
|
can test your installation by starting and using a local server as follows:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Start a TensorFlow server as a single-process "cluster".
|
# Start a TensorFlow server as a single-process "cluster".
|
||||||
@ -16,29 +16,34 @@ $ python
|
|||||||
>>> import tensorflow as tf
|
>>> import tensorflow as tf
|
||||||
>>> c = tf.constant("Hello, distributed TensorFlow!")
|
>>> c = tf.constant("Hello, distributed TensorFlow!")
|
||||||
>>> server = tf.train.Server.create_local_server()
|
>>> server = tf.train.Server.create_local_server()
|
||||||
>>> sess = tf.Session(server.target)
|
>>> sess = tf.Session(server.target) # Create a session on the server.
|
||||||
>>> sess.run(c)
|
>>> sess.run(c)
|
||||||
'Hello, distributed TensorFlow!'
|
'Hello, distributed TensorFlow!'
|
||||||
```
|
```
|
||||||
|
|
||||||
The
|
The
|
||||||
[`tf.train.Server.create_local_server()`](../../api_docs/train.md#Server.create_local_server)
|
[`tf.train.Server.create_local_server()`](../../api_docs/train.md#Server.create_local_server)
|
||||||
method creates a single-process cluster.
|
method creates a single-process cluster, with an in-process server.
|
||||||
|
|
||||||
## Create a cluster
|
## Create a cluster
|
||||||
|
|
||||||
Most clusters have multiple tasks, divided into one or more jobs. To create a
|
A TensorFlow "cluster" is a set of "tasks" that participate in the distributed
|
||||||
cluster with multiple processes or machines:
|
execution of a TensorFlow graph. Each task is associated with a TensorFlow
|
||||||
|
"server", which contains a "master" that can be used to create sessions, and a
|
||||||
|
"worker" that executes operations in the graph. A cluster can also be divided
|
||||||
|
into one or more "jobs", where each job contains one or more tasks.
|
||||||
|
|
||||||
1. **For each process or machine** in the cluster, run a TensorFlow program to
|
To create a cluster, you start one TensorFlow server per task in the cluster.
|
||||||
do the following:
|
Each task typically runs on a different machine, but you can run multiple tasks
|
||||||
|
on the same machine (e.g. to control different GPU devices). In each task, do
|
||||||
|
the following:
|
||||||
|
|
||||||
1. **Create a `tf.train.ClusterSpec`**, which describes all of the tasks
|
1. **Create a `tf.train.ClusterSpec`** that describes all of the tasks
|
||||||
in the cluster. This should be the same in each process.
|
in the cluster. This should be the same for each task.
|
||||||
|
|
||||||
1. **Create a `tf.train.Server`**, passing the `tf.train.ClusterSpec` to
|
2. **Create a `tf.train.Server`**, passing the `tf.train.ClusterSpec` to
|
||||||
the constructor, and identifying the local process with a job name
|
the constructor, and identifying the local task with a job name
|
||||||
and task index.
|
and task index.
|
||||||
|
|
||||||
|
|
||||||
### Create a `tf.train.ClusterSpec` to describe the cluster
|
### Create a `tf.train.ClusterSpec` to describe the cluster
|
||||||
@ -71,28 +76,29 @@ tf.train.ClusterSpec({
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
### Create a `tf.train.Server` instance in each process
|
### Create a `tf.train.Server` instance in each task
|
||||||
|
|
||||||
A [`tf.train.Server`](../../api_docs/python/train.md#Server) object contains a
|
A [`tf.train.Server`](../../api_docs/python/train.md#Server) object contains a
|
||||||
set of local devices, and a
|
set of local devices, a set of connections to other tasks in its
|
||||||
[`tf.Session`](../../api_docs/python/client.md#Session) target that can
|
`tf.train.ClusterSpec`, and a
|
||||||
participate in a distributed computation. Each server belongs to a particular
|
["session target"](../../api_docs/python/client.md#Session) that can use these
|
||||||
cluster (specified by a `tf.train.ClusterSpec`), and corresponds to a particular
|
to perform a distributed computation. Each server is a member of a specific
|
||||||
task in a named job. The server can communicate with any other server in the
|
named job and has a task index within that job. A server can communicate with
|
||||||
same cluster.
|
any other server in the cluster.
|
||||||
|
|
||||||
For example, to define and instantiate servers running on `localhost:2222` and
|
For example, to launch a cluster with two servers running on `localhost:2222`
|
||||||
`localhost:2223`, run the following snippets in different processes:
|
and `localhost:2223`, run the following snippets in two different processes on
|
||||||
|
the local machine:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# In task 0:
|
# In task 0:
|
||||||
cluster = tf.ClusterSpec({"local": ["localhost:2222", "localhost:2223"]})
|
cluster = tf.train.ClusterSpec({"local": ["localhost:2222", "localhost:2223"]})
|
||||||
server = tf.GrpcServer(cluster, job_name="local", task_index=0)
|
server = tf.train.Server(cluster, job_name="local", task_index=0)
|
||||||
```
|
```
|
||||||
```python
|
```python
|
||||||
# In task 1:
|
# In task 1:
|
||||||
cluster = tf.ClusterSpec({"local": ["localhost:2222", "localhost:2223"]})
|
cluster = tf.train.ClusterSpec({"local": ["localhost:2222", "localhost:2223"]})
|
||||||
server = tf.GrpcServer(cluster, job_name="local", task_index=1)
|
server = tf.train.Server(cluster, job_name="local", task_index=1)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Manually specifying these cluster specifications can be tedious,
|
**Note:** Manually specifying these cluster specifications can be tedious,
|
||||||
@ -137,45 +143,44 @@ applying gradients).
|
|||||||
|
|
||||||
## Replicated training
|
## Replicated training
|
||||||
|
|
||||||
A common training configuration ("data parallel training") involves multiple
|
A common training configuration, called "data parallelism," involves multiple
|
||||||
tasks in a `worker` job training the same model, using shared parameters hosted
|
tasks in a `worker` job training the same model on different mini-batches of
|
||||||
in a one or more tasks in a `ps` job. Each task will typically run on a
|
data, updating shared parameters hosted in a one or more tasks in a `ps`
|
||||||
different machine. There are many ways to specify this structure in TensorFlow,
|
job. All tasks typically run on different machines. There are many ways to
|
||||||
and we are building libraries that will simplify the work of specifying a
|
specify this structure in TensorFlow, and we are building libraries that will
|
||||||
replicated model. Possible approaches include:
|
simplify the work of specifying a replicated model. Possible approaches include:
|
||||||
|
|
||||||
* Building a single graph containing one set of parameters (in `tf.Variable`
|
* **In-graph replication.** In this approach, the client builds a single
|
||||||
nodes pinned to `/job:ps`), and multiple copies of the "model" pinned to
|
`tf.Graph` that contains one set of parameters (in `tf.Variable` nodes pinned
|
||||||
different tasks in `/job:worker`. Each copy of the model can have a different
|
to `/job:ps`); and multiple copies of the compute-intensive part of the model,
|
||||||
`train_op`, and one or more client threads can call `sess.run(train_ops[i])`
|
each pinned to a different task in `/job:worker`.
|
||||||
for each worker `i`. This implements *asynchronous* training.
|
|
||||||
|
|
||||||
This approach uses a single `tf.Session` whose target is one of the workers in
|
* **Between-graph replication.** In this approach, there is a separate client
|
||||||
the cluster.
|
for each `/job:worker` task, typically in the same process as the worker
|
||||||
|
task. Each client builds a similar graph containing the parameters (pinned to
|
||||||
|
`/job:ps` as before using
|
||||||
|
[`tf.train.replica_device_setter()`](../../api_docs/train.md#replica_device_setter)
|
||||||
|
to map them deterministically to the same tasks); and a single copy of the
|
||||||
|
compute-intensive part of the model, pinned to the local task in
|
||||||
|
`/job:worker`.
|
||||||
|
|
||||||
* As above, but where the gradients from all workers are averaged. See the
|
* **Asynchronous training.** In this approach, each replica of the graph has an
|
||||||
[CIFAR-10 multi-GPU trainer](https://www.tensorflow.org/code/tensorflow/models/image/cifar10/cifar10_multi_gpu_train.py)
|
independent training loop that executes without coordination. It is compatible
|
||||||
for an example of this form of replication. This implements *synchronous*
|
with both forms of replication above.
|
||||||
training.
|
|
||||||
|
|
||||||
* The "distributed trainer" approach uses multiple graphs—one per
|
* **Synchronous training.** In this approach, all of the replicas read the same
|
||||||
worker—where each graph contains one set of parameters (pinned to
|
values for the current parameters, compute gradients in parallel, and then
|
||||||
`/job:ps`) and one copy of the model (pinned to a particular
|
apply them together. It is compatible with in-graph replication (e.g. using
|
||||||
`/job:worker/task:i`). The "container" mechanism is used to share variables
|
gradient averaging as in the
|
||||||
between different graphs: when each variable is constructed, the optional
|
[CIFAR-10 multi-GPU trainer](https://www.tensorflow.org/code/tensorflow/models/image/cifar10/cifar10_multi_gpu_train.py)),
|
||||||
`container` argument is specified with the same value in each copy of the
|
and between-graph replication (e.g. using the
|
||||||
graph. For large models, this can be more efficient, because the overall graph
|
`tf.train.SyncReplicasOptimizer`).
|
||||||
is smaller.
|
|
||||||
|
|
||||||
This approach uses multiple `tf.Session` objects: one per worker process,
|
|
||||||
where the `target` of each is the address of a different worker. The
|
|
||||||
`tf.Session` objects can all be created in a single Python client, or you can
|
|
||||||
use multiple Python clients to better distribute the trainer load.
|
|
||||||
|
|
||||||
### Putting it all together: example trainer program
|
### Putting it all together: example trainer program
|
||||||
|
|
||||||
The following code shows the skeleton of a distributed trainer program. It
|
The following code shows the skeleton of a distributed trainer program,
|
||||||
includes the code for the parameter server and worker processes.
|
implementing **between-graph replication** and **asynchronous training**. It
|
||||||
|
includes the code for the parameter server and worker tasks.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
@ -197,10 +202,13 @@ def main(_):
|
|||||||
ps_hosts = FLAGS.ps_hosts.split(",")
|
ps_hosts = FLAGS.ps_hosts.split(",")
|
||||||
worker_hosts = FLAGS.worker_hosts(",")
|
worker_hosts = FLAGS.worker_hosts(",")
|
||||||
|
|
||||||
|
# Create a cluster from the parameter server and worker hosts.
|
||||||
cluster = tf.train.ClusterSpec({"ps": ps_hosts, "worker": worker_hosts})
|
cluster = tf.train.ClusterSpec({"ps": ps_hosts, "worker": worker_hosts})
|
||||||
|
|
||||||
|
# Create and start a server for the local task.
|
||||||
server = tf.train.Server(cluster,
|
server = tf.train.Server(cluster,
|
||||||
job_name=FLAGS.job_name,
|
job_name=FLAGS.job_name,
|
||||||
task_index=task_index)
|
task_index=FLAGS.task_index)
|
||||||
|
|
||||||
if FLAGS.job_name == "ps":
|
if FLAGS.job_name == "ps":
|
||||||
server.join()
|
server.join()
|
||||||
@ -290,10 +298,10 @@ $ python trainer.py \
|
|||||||
</dd>
|
</dd>
|
||||||
<dt>Cluster</dt>
|
<dt>Cluster</dt>
|
||||||
<dd>
|
<dd>
|
||||||
A TensorFlow cluster comprises one or more TensorFlow servers, divided into
|
A TensorFlow cluster comprises a one or more "jobs", each divided into lists
|
||||||
a set of named jobs, which in turn comprise lists of tasks. A cluster is
|
of one or more "tasks". A cluster is typically dedicated to a particular
|
||||||
typically dedicated to a particular high-level objective, such as training a
|
high-level objective, such as training a neural network, using many machines
|
||||||
neural network, using many machines in parallel.
|
in parallel. A cluster is defined by a `tf.train.ClusterSpec` object.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Job</dt>
|
<dt>Job</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@ -301,20 +309,22 @@ $ python trainer.py \
|
|||||||
purpose. For example, a job named `ps` (for "parameter server") typically
|
purpose. For example, a job named `ps` (for "parameter server") typically
|
||||||
hosts nodes that store and update variables; while a job named `worker`
|
hosts nodes that store and update variables; while a job named `worker`
|
||||||
typically hosts stateless nodes that perform compute-intensive tasks.
|
typically hosts stateless nodes that perform compute-intensive tasks.
|
||||||
The tasks in a job typically run on different machines.
|
The tasks in a job typically run on different machines. The set of job roles
|
||||||
|
is flexible: for example, a `worker` may maintain some state.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Master service</dt>
|
<dt>Master service</dt>
|
||||||
<dd>
|
<dd>
|
||||||
An RPC service that provides remote access to a set of distributed
|
An RPC service that provides remote access to a set of distributed devices,
|
||||||
devices. The master service implements the <code>tensorflow::Session</code>
|
and acts as a session target. The master service implements the
|
||||||
interface, and is responsible for coordinating work across one or more
|
<code>tensorflow::Session</code> interface, and is responsible for
|
||||||
"worker services".
|
coordinating work across one or more "worker services". All TensorFlow
|
||||||
|
servers implement the master service.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Task</dt>
|
<dt>Task</dt>
|
||||||
<dd>
|
<dd>
|
||||||
A task typically corresponds to a single TensorFlow server process,
|
A task corresponds to a specific TensorFlow server, and typically
|
||||||
belonging to a particular "job" and with a particular index within that
|
corresponds to a single process. A task belongs to a particular "job" and is
|
||||||
job's list of tasks.
|
identified by its index within that job's list of tasks.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>TensorFlow server</dt>
|
<dt>TensorFlow server</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@ -326,6 +336,7 @@ $ python trainer.py \
|
|||||||
An RPC service that executes parts of a TensorFlow graph using its local
|
An RPC service that executes parts of a TensorFlow graph using its local
|
||||||
devices. A worker service implements <a href=
|
devices. A worker service implements <a href=
|
||||||
"https://www.tensorflow.org/code/tensorflow/core/protobuf/worker_service.proto"
|
"https://www.tensorflow.org/code/tensorflow/core/protobuf/worker_service.proto"
|
||||||
><code>worker_service.proto</code></a>.
|
><code>worker_service.proto</code></a>. All TensorFlow servers implement the
|
||||||
|
worker service.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -114,4 +114,4 @@ Building on the Inception recognition model, we will release a TensorFlow
|
|||||||
version of the [Deep Dream](https://github.com/google/deepdream) neural network
|
version of the [Deep Dream](https://github.com/google/deepdream) neural network
|
||||||
visual hallucination software.
|
visual hallucination software.
|
||||||
|
|
||||||
[View Tutorial](https://www.tensorflow.org/code/tensorflow/examples/tutorials/deepdream/deepdream.ipynb)
|
[View Tutorial](https://www.tensorflow.org/code/tensorflow/examples/tutorials/deepdream/README.md)
|
||||||
|
@ -19,6 +19,7 @@ from __future__ import absolute_import
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import functools
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
|
|
||||||
@ -208,5 +209,59 @@ class RNNCellTest(tf.test.TestCase):
|
|||||||
0.13248, 0.13248]])
|
0.13248, 0.13248]])
|
||||||
|
|
||||||
|
|
||||||
|
class SlimRNNCellTest(tf.test.TestCase):
|
||||||
|
|
||||||
|
def testBasicRNNCell(self):
|
||||||
|
with self.test_session() as sess:
|
||||||
|
with tf.variable_scope("root", initializer=tf.constant_initializer(0.5)):
|
||||||
|
x = tf.zeros([1, 2])
|
||||||
|
m = tf.zeros([1, 2])
|
||||||
|
my_cell = functools.partial(basic_rnn_cell, num_units=2)
|
||||||
|
g, _ = tf.nn.rnn_cell.SlimRNNCell(my_cell)(x, m)
|
||||||
|
sess.run([tf.initialize_all_variables()])
|
||||||
|
res = sess.run([g], {x.name: np.array([[1., 1.]]),
|
||||||
|
m.name: np.array([[0.1, 0.1]])})
|
||||||
|
self.assertEqual(res[0].shape, (1, 2))
|
||||||
|
|
||||||
|
def testBasicRNNCellMatch(self):
|
||||||
|
batch_size = 32
|
||||||
|
input_size = 100
|
||||||
|
num_units = 10
|
||||||
|
with self.test_session() as sess:
|
||||||
|
with tf.variable_scope("root", initializer=tf.constant_initializer(0.5)):
|
||||||
|
inputs = tf.random_uniform((batch_size, input_size))
|
||||||
|
_, initial_state = basic_rnn_cell(inputs, None, num_units)
|
||||||
|
my_cell = functools.partial(basic_rnn_cell, num_units=num_units)
|
||||||
|
slim_cell = tf.nn.rnn_cell.SlimRNNCell(my_cell)
|
||||||
|
slim_outputs, slim_state = slim_cell(inputs, initial_state)
|
||||||
|
rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units)
|
||||||
|
outputs, state = rnn_cell(inputs, initial_state)
|
||||||
|
self.assertEqual(slim_outputs.get_shape(), outputs.get_shape())
|
||||||
|
self.assertEqual(slim_state.get_shape(), state.get_shape())
|
||||||
|
sess.run([tf.initialize_all_variables()])
|
||||||
|
res = sess.run([slim_outputs, slim_state, outputs, state])
|
||||||
|
self.assertAllClose(res[0], res[2])
|
||||||
|
self.assertAllClose(res[1], res[3])
|
||||||
|
|
||||||
|
|
||||||
|
def basic_rnn_cell(inputs, state, num_units, scope=None):
|
||||||
|
if state is None:
|
||||||
|
if inputs is not None:
|
||||||
|
batch_size = inputs.get_shape()[0]
|
||||||
|
dtype = inputs.dtype
|
||||||
|
else:
|
||||||
|
batch_size = 0
|
||||||
|
dtype = tf.float32
|
||||||
|
init_output = tf.zeros(tf.pack([batch_size, num_units]), dtype=dtype)
|
||||||
|
init_state = tf.zeros(tf.pack([batch_size, num_units]), dtype=dtype)
|
||||||
|
init_output.set_shape([batch_size, num_units])
|
||||||
|
init_state.set_shape([batch_size, num_units])
|
||||||
|
return init_output, init_state
|
||||||
|
else:
|
||||||
|
with tf.variable_op_scope([inputs, state], scope, "BasicRNNCell"):
|
||||||
|
output = tf.tanh(tf.nn.rnn_cell.linear([inputs, state],
|
||||||
|
num_units, True))
|
||||||
|
return output, output
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
tf.test.main()
|
tf.test.main()
|
||||||
|
@ -302,6 +302,53 @@ class VariablesTestCase(tf.test.TestCase):
|
|||||||
self.assertEqual(var.op.device, init_op.device)
|
self.assertEqual(var.op.device, init_op.device)
|
||||||
sess.run(init_op)
|
sess.run(init_op)
|
||||||
|
|
||||||
|
def testInitializerFunction(self):
|
||||||
|
value = [[-42], [133.7]]
|
||||||
|
shape = [2, 1]
|
||||||
|
with self.test_session():
|
||||||
|
initializer = lambda: tf.constant(value)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
# Checks that dtype must be specified.
|
||||||
|
tf.Variable(initializer)
|
||||||
|
|
||||||
|
v1 = tf.Variable(initializer, dtype=tf.float32)
|
||||||
|
self.assertEqual(shape, v1.get_shape())
|
||||||
|
self.assertAllClose(value, v1.initial_value.eval())
|
||||||
|
with self.assertRaises(tf.errors.FailedPreconditionError):
|
||||||
|
v1.eval()
|
||||||
|
|
||||||
|
v2 = tf.Variable(tf.neg(v1.initialized_value()), dtype=tf.float32)
|
||||||
|
self.assertEqual(v1.get_shape(), v2.get_shape())
|
||||||
|
self.assertAllClose(np.negative(value), v2.initial_value.eval())
|
||||||
|
|
||||||
|
# Once v2.initial_value.eval() has been called, v1 has effectively been
|
||||||
|
# initialized.
|
||||||
|
self.assertAllClose(value, v1.eval())
|
||||||
|
|
||||||
|
with self.assertRaises(tf.errors.FailedPreconditionError):
|
||||||
|
v2.eval()
|
||||||
|
tf.initialize_all_variables().run()
|
||||||
|
self.assertAllClose(np.negative(value), v2.eval())
|
||||||
|
|
||||||
|
def testInitializerFunctionDevicePlacement(self):
|
||||||
|
with self.test_session():
|
||||||
|
initializer = lambda: tf.constant(42.0)
|
||||||
|
with tf.device("/cpu:100"):
|
||||||
|
v1 = tf.Variable(initializer, dtype=tf.float32, name="v1")
|
||||||
|
expected_device = "/device:CPU:100"
|
||||||
|
expected_group_v1 = [b"loc:@v1"]
|
||||||
|
self.assertEqual(expected_device, v1.op.device)
|
||||||
|
self.assertEqual(expected_group_v1, v1.op.colocation_groups())
|
||||||
|
for i in v1.initializer.inputs:
|
||||||
|
self.assertEqual(expected_device, i.op.device)
|
||||||
|
self.assertEqual(expected_group_v1, i.op.colocation_groups())
|
||||||
|
|
||||||
|
v2 = tf.Variable(initializer, dtype=tf.float32, name="v2")
|
||||||
|
expected_group_v2 = [b"loc:@v2"]
|
||||||
|
self.assertEqual(expected_group_v2, v2.op.colocation_groups())
|
||||||
|
for i in v2.initializer.inputs:
|
||||||
|
self.assertEqual(expected_group_v2, i.op.colocation_groups())
|
||||||
|
|
||||||
|
|
||||||
class IsInitializedTest(tf.test.TestCase):
|
class IsInitializedTest(tf.test.TestCase):
|
||||||
|
|
||||||
|
@ -167,19 +167,22 @@ def create_partitioned_variables(
|
|||||||
slice_offset[slice_dim] += var_shape[slice_dim]
|
slice_offset[slice_dim] += var_shape[slice_dim]
|
||||||
|
|
||||||
if callable(initializer):
|
if callable(initializer):
|
||||||
init_val = initializer(var_shape, dtype=dtype)
|
init = initializer
|
||||||
init_val = ops.convert_to_tensor(init_val, dtype=dtype)
|
init_shape = var_shape
|
||||||
elif isinstance(initializer, ops.Tensor):
|
elif isinstance(initializer, ops.Tensor):
|
||||||
init_val = array_ops.slice(initializer, var_offset, var_shape)
|
init = array_ops.slice(initializer, var_offset, var_shape)
|
||||||
# Use the dtype of the given tensor.
|
# Use the dtype of the given tensor.
|
||||||
dtype = init_val.dtype.base_dtype
|
dtype = init.dtype.base_dtype
|
||||||
|
init_shape = None
|
||||||
else:
|
else:
|
||||||
init_val = ops.convert_to_tensor(initializer, dtype=dtype)
|
init = ops.convert_to_tensor(initializer, dtype=dtype)
|
||||||
init_val = array_ops.slice(init_val, var_offset, var_shape)
|
init = array_ops.slice(init, var_offset, var_shape)
|
||||||
|
init_shape = None
|
||||||
|
|
||||||
var = variable_scope.get_variable(name="part_%d" % i,
|
var = variable_scope.get_variable(name="part_%d" % i,
|
||||||
|
shape=init_shape,
|
||||||
dtype=dtype,
|
dtype=dtype,
|
||||||
initializer=init_val,
|
initializer=init,
|
||||||
trainable=trainable,
|
trainable=trainable,
|
||||||
collections=collections)
|
collections=collections)
|
||||||
|
|
||||||
|
@ -661,6 +661,42 @@ class MultiRNNCell(RNNCell):
|
|||||||
return cur_inp, array_ops.concat(1, new_states)
|
return cur_inp, array_ops.concat(1, new_states)
|
||||||
|
|
||||||
|
|
||||||
|
class SlimRNNCell(RNNCell):
|
||||||
|
"""A simple wrapper for slim.rnn_cells."""
|
||||||
|
|
||||||
|
def __init__(self, cell_fn):
|
||||||
|
"""Create a SlimRNNCell from a cell_fn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cell_fn: a function which takes (inputs, state, scope) and produces the
|
||||||
|
outputs and the new_state. Additionally when called with inputs=None and
|
||||||
|
state=None it should return (initial_outputs, initial_state).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TypeError: if cell_fn is not callable
|
||||||
|
ValueError: if cell_fn cannot produce a valid initial state.
|
||||||
|
"""
|
||||||
|
if not callable(cell_fn):
|
||||||
|
raise TypeError("cell_fn %s needs to be callable", cell_fn)
|
||||||
|
self._cell_fn = cell_fn
|
||||||
|
self._cell_name = cell_fn.func.__name__
|
||||||
|
_, init_state = self._cell_fn(None, None)
|
||||||
|
state_shape = init_state.get_shape()
|
||||||
|
self._state_size = state_shape.with_rank(2)[1].value
|
||||||
|
if self._state_size is None:
|
||||||
|
raise ValueError("Initial state created by %s has invalid shape %s",
|
||||||
|
self._cell_name, state_shape)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state_size(self):
|
||||||
|
return self._state_size
|
||||||
|
|
||||||
|
def __call__(self, inputs, state, scope=None):
|
||||||
|
scope = scope or self._cell_name
|
||||||
|
output, state = self._cell_fn(inputs, state, scope=scope)
|
||||||
|
return output, state
|
||||||
|
|
||||||
|
|
||||||
def linear(args, output_size, bias, bias_start=0.0, scope=None):
|
def linear(args, output_size, bias, bias_start=0.0, scope=None):
|
||||||
"""Linear map: sum_i(args[i] * W[i]), where W[i] is a variable.
|
"""Linear map: sum_i(args[i] * W[i]), where W[i] is a variable.
|
||||||
|
|
||||||
|
@ -144,14 +144,19 @@ class _VariableStore(object):
|
|||||||
with ops.control_dependencies(None):
|
with ops.control_dependencies(None):
|
||||||
if initializing_from_value:
|
if initializing_from_value:
|
||||||
init_val = initializer
|
init_val = initializer
|
||||||
|
variable_dtype = None
|
||||||
else:
|
else:
|
||||||
with ops.name_scope(name + "/Initializer/"):
|
init_val = lambda: initializer(shape.as_list(), dtype=dtype)
|
||||||
init_val = initializer(shape.as_list(), dtype=dtype)
|
variable_dtype = dtype.base_dtype
|
||||||
|
|
||||||
# Create the variable.
|
# Create the variable.
|
||||||
v = variables.Variable(init_val, name=name, trainable=trainable,
|
v = variables.Variable(initial_value=init_val,
|
||||||
|
name=name,
|
||||||
|
trainable=trainable,
|
||||||
collections=collections,
|
collections=collections,
|
||||||
caching_device=caching_device)
|
caching_device=caching_device,
|
||||||
|
dtype=variable_dtype)
|
||||||
|
|
||||||
self._vars[name] = v
|
self._vars[name] = v
|
||||||
logging.info("Created variable %s with shape %s and init %s", v.name,
|
logging.info("Created variable %s with shape %s and init %s", v.name,
|
||||||
format(shape), initializer)
|
format(shape), initializer)
|
||||||
|
@ -156,9 +156,12 @@ class Variable(object):
|
|||||||
variable to its initial value.
|
variable to its initial value.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
initial_value: A `Tensor`, or Python object convertible to a `Tensor`.
|
initial_value: A `Tensor`, or Python object convertible to a `Tensor`,
|
||||||
The initial value for the Variable. Must have a shape specified unless
|
which is the initial value for the Variable. The initial value must have
|
||||||
`validate_shape` is set to False.
|
a shape specified unless `validate_shape` is set to False. Can also be a
|
||||||
|
callable with no argument that returns the initial value when called. In
|
||||||
|
that case, `dtype` must be specified. (Note that initializer functions
|
||||||
|
from init_ops.py must first be bound to a shape before being used here.)
|
||||||
trainable: If `True`, the default, also adds the variable to the graph
|
trainable: If `True`, the default, also adds the variable to the graph
|
||||||
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
||||||
the default list of variables to use by the `Optimizer` classes.
|
the default list of variables to use by the `Optimizer` classes.
|
||||||
@ -211,9 +214,12 @@ class Variable(object):
|
|||||||
"""Creates a new variable from arguments.
|
"""Creates a new variable from arguments.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
initial_value: A `Tensor`, or Python object convertible to a `Tensor`.
|
initial_value: A `Tensor`, or Python object convertible to a `Tensor`,
|
||||||
The initial value for the Variable. Must have a shape specified unless
|
which is the initial value for the Variable. The initial value must have
|
||||||
`validate_shape` is set to False.
|
a shape specified unless `validate_shape` is set to False. Can also be a
|
||||||
|
callable with no argument that returns the initial value when called. In
|
||||||
|
that case, `dtype` must be specified. (Note that initializer functions
|
||||||
|
from init_ops.py must first be bound to a shape before being used here.)
|
||||||
trainable: If `True`, the default, also adds the variable to the graph
|
trainable: If `True`, the default, also adds the variable to the graph
|
||||||
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as
|
||||||
the default list of variables to use by the `Optimizer` classes.
|
the default list of variables to use by the `Optimizer` classes.
|
||||||
@ -240,25 +246,62 @@ class Variable(object):
|
|||||||
"""
|
"""
|
||||||
if initial_value is None:
|
if initial_value is None:
|
||||||
raise ValueError("initial_value must be specified.")
|
raise ValueError("initial_value must be specified.")
|
||||||
|
init_from_fn = callable(initial_value)
|
||||||
|
if init_from_fn and dtype is None:
|
||||||
|
raise ValueError(
|
||||||
|
"dtype must also be specified when initial_value is callable.")
|
||||||
|
|
||||||
if collections is None:
|
if collections is None:
|
||||||
collections = [ops.GraphKeys.VARIABLES]
|
collections = [ops.GraphKeys.VARIABLES]
|
||||||
if trainable and ops.GraphKeys.TRAINABLE_VARIABLES not in collections:
|
if trainable and ops.GraphKeys.TRAINABLE_VARIABLES not in collections:
|
||||||
collections = list(collections) + [ops.GraphKeys.TRAINABLE_VARIABLES]
|
collections = list(collections) + [ops.GraphKeys.TRAINABLE_VARIABLES]
|
||||||
with ops.control_dependencies(None):
|
with ops.control_dependencies(None):
|
||||||
with ops.op_scope([initial_value], name, "Variable") as name:
|
with ops.op_scope(
|
||||||
self._initial_value = ops.convert_to_tensor(initial_value,
|
[] if init_from_fn else [initial_value], name, "Variable") as name:
|
||||||
name="initial_value",
|
|
||||||
dtype=dtype)
|
|
||||||
initial_value_shape = self._initial_value.get_shape()
|
|
||||||
if validate_shape and not initial_value_shape.is_fully_defined():
|
|
||||||
raise ValueError("initial_value must have a shape specified: %s"
|
|
||||||
% self._initial_value)
|
|
||||||
shape_to_set = initial_value_shape if validate_shape else []
|
|
||||||
|
|
||||||
self._variable = state_ops.variable_op(
|
# Get the initial value from a callable function. The real shape of the
|
||||||
shape_to_set, self._initial_value.dtype.base_dtype,
|
# variable will be set later, since under the init_from_fn case, the
|
||||||
set_shape=validate_shape, name=name)
|
# shape won't be known until after the function is invoked.
|
||||||
|
if init_from_fn:
|
||||||
|
self._variable = state_ops.variable_op(
|
||||||
|
[],
|
||||||
|
dtype.base_dtype,
|
||||||
|
set_shape=False,
|
||||||
|
name=name)
|
||||||
|
with ops.colocate_with(self._variable.op):
|
||||||
|
with ops.name_scope("Initializer"):
|
||||||
|
# Colocate the tensors created by the initial_value() function
|
||||||
|
# with the variable itself.
|
||||||
|
self._initial_value = ops.convert_to_tensor(initial_value(),
|
||||||
|
name="initial_value",
|
||||||
|
dtype=dtype)
|
||||||
|
|
||||||
|
# Or get the initial value from a Tensor or Python object.
|
||||||
|
else:
|
||||||
|
self._initial_value = ops.convert_to_tensor(initial_value,
|
||||||
|
name="initial_value",
|
||||||
|
dtype=dtype)
|
||||||
|
# In this case, the variable op can't be created until after the
|
||||||
|
# initial_value has been converted to a Tensor with a known type.
|
||||||
|
self._variable = state_ops.variable_op(
|
||||||
|
[],
|
||||||
|
self._initial_value.dtype.base_dtype,
|
||||||
|
set_shape=False,
|
||||||
|
name=name)
|
||||||
|
|
||||||
|
# Manually overrides the variable's shape with the initial value's.
|
||||||
|
if validate_shape:
|
||||||
|
initial_value_shape = self._initial_value.get_shape()
|
||||||
|
if not initial_value_shape.is_fully_defined():
|
||||||
|
raise ValueError("initial_value must have a shape specified: %s"
|
||||||
|
% self._initial_value)
|
||||||
|
self._variable.set_shape(initial_value_shape)
|
||||||
|
# TODO(b/28152992): Remove the below hack modifying the node_def shape
|
||||||
|
# directly once set_shape() handles it.
|
||||||
|
self._variable.op.node_def.attr["shape"].shape.CopyFrom(
|
||||||
|
initial_value_shape.as_proto())
|
||||||
|
|
||||||
|
# Assigns initial value.
|
||||||
with ops.colocate_with(self._variable.op):
|
with ops.colocate_with(self._variable.op):
|
||||||
self._initializer_op = state_ops.assign(
|
self._initializer_op = state_ops.assign(
|
||||||
self._variable, self._initial_value,
|
self._variable, self._initial_value,
|
||||||
|
@ -79,3 +79,7 @@ def get_path_to_datafile(path):
|
|||||||
"""
|
"""
|
||||||
data_files_path = os.path.dirname(inspect.getfile(sys._getframe(1)))
|
data_files_path = os.path.dirname(inspect.getfile(sys._getframe(1)))
|
||||||
return os.path.join(data_files_path, path)
|
return os.path.join(data_files_path, path)
|
||||||
|
|
||||||
|
def readahead_file_path(path, unused_readahead=None):
|
||||||
|
"""Readahead files not implemented; simply returns given path."""
|
||||||
|
return path
|
||||||
|
@ -22,6 +22,7 @@ from tensorflow.core.util import event_pb2
|
|||||||
from tensorflow.python import pywrap_tensorflow
|
from tensorflow.python import pywrap_tensorflow
|
||||||
from tensorflow.python.platform import app
|
from tensorflow.python.platform import app
|
||||||
from tensorflow.python.platform import logging
|
from tensorflow.python.platform import logging
|
||||||
|
from tensorflow.python.platform import resource_loader
|
||||||
from tensorflow.python.util import compat
|
from tensorflow.python.util import compat
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ class EventFileLoader(object):
|
|||||||
def __init__(self, file_path):
|
def __init__(self, file_path):
|
||||||
if file_path is None:
|
if file_path is None:
|
||||||
raise ValueError('A file path is required')
|
raise ValueError('A file path is required')
|
||||||
|
file_path = resource_loader.readahead_file_path(file_path)
|
||||||
logging.debug('Opening a record reader pointing at %s', file_path)
|
logging.debug('Opening a record reader pointing at %s', file_path)
|
||||||
self._reader = pywrap_tensorflow.PyRecordReader_New(
|
self._reader = pywrap_tensorflow.PyRecordReader_New(
|
||||||
compat.as_bytes(file_path), 0)
|
compat.as_bytes(file_path), 0)
|
||||||
|
@ -238,6 +238,7 @@ class ClusterSpec(object):
|
|||||||
elif isinstance(cluster, ClusterSpec):
|
elif isinstance(cluster, ClusterSpec):
|
||||||
self._cluster_def = tensorflow_server_pb2.ClusterDef()
|
self._cluster_def = tensorflow_server_pb2.ClusterDef()
|
||||||
self._cluster_def.MergeFrom(cluster.as_cluster_def())
|
self._cluster_def.MergeFrom(cluster.as_cluster_def())
|
||||||
|
self._cluster_spec = {}
|
||||||
for job_def in self._cluster_def.job:
|
for job_def in self._cluster_def.job:
|
||||||
self._cluster_spec[job_def.name] = [t for t in job_def.tasks.values()]
|
self._cluster_spec[job_def.name] = [t for t in job_def.tasks.values()]
|
||||||
else:
|
else:
|
||||||
@ -306,4 +307,3 @@ class ClusterSpec(object):
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Task address %r must be bytes or unicode" % task_address)
|
"Task address %r must be bytes or unicode" % task_address)
|
||||||
job_def.tasks[i] = task_address
|
job_def.tasks[i] = task_address
|
||||||
|
|
||||||
|
@ -146,6 +146,29 @@ class ServerDefTest(tf.test.TestCase):
|
|||||||
cluster_spec = tf.train.ClusterSpec(cluster_def)
|
cluster_spec = tf.train.ClusterSpec(cluster_def)
|
||||||
self.assertProtoEquals(cluster_def, cluster_spec.as_cluster_def())
|
self.assertProtoEquals(cluster_def, cluster_spec.as_cluster_def())
|
||||||
|
|
||||||
|
def testClusterSpec(self):
|
||||||
|
cluster_spec = tf.train.ClusterSpec(
|
||||||
|
{"ps": ["ps0:2222", "ps1:2222"],
|
||||||
|
"worker": ["worker0:2222", "worker1:2222", "worker2:2222"]})
|
||||||
|
|
||||||
|
expected_proto = """
|
||||||
|
job { name: 'ps' tasks { key: 0 value: 'ps0:2222' }
|
||||||
|
tasks { key: 1 value: 'ps1:2222' } }
|
||||||
|
job { name: 'worker' tasks { key: 0 value: 'worker0:2222' }
|
||||||
|
tasks { key: 1 value: 'worker1:2222' }
|
||||||
|
tasks { key: 2 value: 'worker2:2222' } }
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.assertProtoEquals(expected_proto, cluster_spec.as_cluster_def())
|
||||||
|
self.assertProtoEquals(
|
||||||
|
expected_proto, tf.train.ClusterSpec(cluster_spec).as_cluster_def())
|
||||||
|
self.assertProtoEquals(
|
||||||
|
expected_proto,
|
||||||
|
tf.train.ClusterSpec(cluster_spec.as_cluster_def()).as_cluster_def())
|
||||||
|
self.assertProtoEquals(
|
||||||
|
expected_proto,
|
||||||
|
tf.train.ClusterSpec(cluster_spec.as_dict()).as_cluster_def())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
tf.test.main()
|
tf.test.main()
|
||||||
|
@ -326,19 +326,29 @@ class Supervisor(object):
|
|||||||
self._init_global_step(global_step=global_step)
|
self._init_global_step(global_step=global_step)
|
||||||
self._graph = graph
|
self._graph = graph
|
||||||
self._is_chief = is_chief
|
self._is_chief = is_chief
|
||||||
self._logdir = logdir
|
|
||||||
self._save_summaries_secs = save_summaries_secs
|
|
||||||
self._save_model_secs = save_model_secs
|
|
||||||
self._recovery_wait_secs = recovery_wait_secs
|
|
||||||
self._coord = coordinator.Coordinator()
|
self._coord = coordinator.Coordinator()
|
||||||
if logdir:
|
self._started_threads = []
|
||||||
|
self._recovery_wait_secs = recovery_wait_secs
|
||||||
|
|
||||||
|
# Only chief supervisors write event files, so only chief supervisors
|
||||||
|
# should have event-writing properties. Set to None for non-chiefs.
|
||||||
|
if self._is_chief:
|
||||||
|
self._logdir = logdir
|
||||||
|
self._save_summaries_secs = save_summaries_secs
|
||||||
|
self._save_model_secs = save_model_secs
|
||||||
|
else:
|
||||||
|
self._logdir = None
|
||||||
|
self._save_summaries_secs = None
|
||||||
|
self._save_model_secs = None
|
||||||
|
|
||||||
|
if self._is_chief and self._logdir:
|
||||||
self._save_path = os.path.join(self._logdir, checkpoint_basename)
|
self._save_path = os.path.join(self._logdir, checkpoint_basename)
|
||||||
self._summary_writer = summary_io.SummaryWriter(self._logdir)
|
self._summary_writer = summary_io.SummaryWriter(self._logdir)
|
||||||
else:
|
else:
|
||||||
self._save_path = None
|
self._save_path = None
|
||||||
self._summary_writer = None
|
self._summary_writer = None
|
||||||
|
|
||||||
self._init_session_manager(session_manager=session_manager)
|
self._init_session_manager(session_manager=session_manager)
|
||||||
self._started_threads = []
|
|
||||||
self._verify_setup()
|
self._verify_setup()
|
||||||
# The graph is not allowed to change anymore.
|
# The graph is not allowed to change anymore.
|
||||||
graph.finalize()
|
graph.finalize()
|
||||||
@ -520,7 +530,7 @@ class Supervisor(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def summary_writer(self):
|
def summary_writer(self):
|
||||||
"""Return the SummaryWriter used by the supervisor.
|
"""Return the SummaryWriter used by the chief supervisor.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A SummaryWriter.
|
A SummaryWriter.
|
||||||
@ -529,7 +539,7 @@ class Supervisor(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def summary_op(self):
|
def summary_op(self):
|
||||||
"""Return the Summary Tensor used by the supervisor.
|
"""Return the Summary Tensor used by the chief supervisor.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A string Tensor for the summary or `None`.
|
A string Tensor for the summary or `None`.
|
||||||
@ -583,8 +593,7 @@ class Supervisor(object):
|
|||||||
|
|
||||||
def _write_graph(self):
|
def _write_graph(self):
|
||||||
"""Writes graph_def to `logdir` and adds it to summary if applicable."""
|
"""Writes graph_def to `logdir` and adds it to summary if applicable."""
|
||||||
if not self._is_chief:
|
assert self._is_chief
|
||||||
return
|
|
||||||
if self._logdir:
|
if self._logdir:
|
||||||
training_util.write_graph(self._graph.as_graph_def(),
|
training_util.write_graph(self._graph.as_graph_def(),
|
||||||
self._logdir, "graph.pbtxt")
|
self._logdir, "graph.pbtxt")
|
||||||
@ -610,11 +619,13 @@ class Supervisor(object):
|
|||||||
sv.coord.Join(<list of threads>)
|
sv.coord.Join(<list of threads>)
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
|
RuntimeError: If called with a non-chief Supervisor.
|
||||||
ValueError: If not `logdir` was passed to the constructor as the
|
ValueError: If not `logdir` was passed to the constructor as the
|
||||||
services need a log directory.
|
services need a log directory.
|
||||||
"""
|
"""
|
||||||
if not self._is_chief:
|
if not self._is_chief:
|
||||||
return
|
raise RuntimeError("Only chief supervisor can start standard services. "
|
||||||
|
"Because only cheif supervisors can write events.")
|
||||||
if not self._logdir:
|
if not self._logdir:
|
||||||
logging.warning("Standard services need a 'logdir' "
|
logging.warning("Standard services need a 'logdir' "
|
||||||
"passed to the SessionManager")
|
"passed to the SessionManager")
|
||||||
@ -812,14 +823,18 @@ class Supervisor(object):
|
|||||||
TypeError: if 'summary' is not a Summary proto or a string.
|
TypeError: if 'summary' is not a Summary proto or a string.
|
||||||
RuntimeError: if the Supervisor was created without a `logdir`.
|
RuntimeError: if the Supervisor was created without a `logdir`.
|
||||||
"""
|
"""
|
||||||
if not self._logdir:
|
if not self._summary_writer:
|
||||||
raise RuntimeError("summary_computed() requires a logdir")
|
raise RuntimeError("Writing a summary requires a summary writer.")
|
||||||
if global_step is None and self.global_step is not None:
|
if global_step is None and self.global_step is not None:
|
||||||
global_step = training_util.global_step(sess, self.global_step)
|
global_step = training_util.global_step(sess, self.global_step)
|
||||||
if self._summary_writer:
|
self._summary_writer.add_summary(summary, global_step)
|
||||||
self._summary_writer.add_summary(summary, global_step)
|
|
||||||
|
|
||||||
def _default_global_step_tensor(self):
|
def _default_global_step_tensor(self):
|
||||||
|
"""Returns the global_step from the default graph.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The global step `Tensor` or `None`.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
gs = ops.get_default_graph().get_tensor_by_name("global_step:0")
|
gs = ops.get_default_graph().get_tensor_by_name("global_step:0")
|
||||||
if gs.dtype.base_dtype in [dtypes.int32, dtypes.int64]:
|
if gs.dtype.base_dtype in [dtypes.int32, dtypes.int64]:
|
||||||
|
@ -73,12 +73,11 @@ class SupervisorTest(tf.test.TestCase):
|
|||||||
sess.close()
|
sess.close()
|
||||||
sv.stop()
|
sv.stop()
|
||||||
|
|
||||||
def testSummary(self):
|
def testChiefCanWriteEvents(self):
|
||||||
logdir = self._TestDir("basics")
|
logdir = self._TestDir("basics")
|
||||||
with tf.Graph().as_default():
|
with tf.Graph().as_default():
|
||||||
const = tf.constant([1.0, 2.0, 3.0])
|
summ = tf.scalar_summary(["c1", "c2", "c3"], tf.constant([1.0, 2.0, 3.0]))
|
||||||
summ = tf.scalar_summary(["c1", "c2", "c3"], const)
|
sv = tf.train.Supervisor(is_chief=True, logdir=logdir, summary_op=None)
|
||||||
sv = tf.train.Supervisor(logdir=logdir, summary_op=None)
|
|
||||||
sess = sv.prepare_or_wait_for_session("")
|
sess = sv.prepare_or_wait_for_session("")
|
||||||
sv.summary_computed(sess, sess.run(summ))
|
sv.summary_computed(sess, sess.run(summ))
|
||||||
sess.close()
|
sess.close()
|
||||||
@ -113,13 +112,31 @@ class SupervisorTest(tf.test.TestCase):
|
|||||||
# We should be done.
|
# We should be done.
|
||||||
self.assertRaises(StopIteration, lambda: next(rr))
|
self.assertRaises(StopIteration, lambda: next(rr))
|
||||||
|
|
||||||
|
def testNonChiefCannotWriteEvents(self):
|
||||||
|
|
||||||
|
def _summary_computed():
|
||||||
|
with tf.Graph().as_default():
|
||||||
|
sv = tf.train.Supervisor(is_chief=False)
|
||||||
|
sess = sv.prepare_or_wait_for_session("")
|
||||||
|
summ = tf.scalar_summary(["c1", "c2"], tf.constant([1.0, 2.0]))
|
||||||
|
sv.summary_computed(sess, sess.run(summ))
|
||||||
|
|
||||||
|
def _start_standard_services():
|
||||||
|
with tf.Graph().as_default():
|
||||||
|
sv = tf.train.Supervisor(is_chief=False)
|
||||||
|
sess = sv.prepare_or_wait_for_session("")
|
||||||
|
sv.start_standard_services(sess)
|
||||||
|
|
||||||
|
self.assertRaises(RuntimeError, _summary_computed)
|
||||||
|
self.assertRaises(RuntimeError, _start_standard_services)
|
||||||
|
|
||||||
def testNoLogdirButWantSummary(self):
|
def testNoLogdirButWantSummary(self):
|
||||||
with tf.Graph().as_default():
|
with tf.Graph().as_default():
|
||||||
const = tf.constant([1.0, 2.0, 3.0])
|
const = tf.constant([1.0, 2.0, 3.0])
|
||||||
summ = tf.scalar_summary(["c1", "c2", "c3"], const)
|
summ = tf.scalar_summary(["c1", "c2", "c3"], const)
|
||||||
sv = tf.train.Supervisor(logdir="", summary_op=None)
|
sv = tf.train.Supervisor(logdir="", summary_op=None)
|
||||||
sess = sv.prepare_or_wait_for_session("")
|
sess = sv.prepare_or_wait_for_session("")
|
||||||
with self.assertRaisesRegexp(RuntimeError, "requires a logdir"):
|
with self.assertRaisesRegexp(RuntimeError, "requires a summary writer"):
|
||||||
sv.summary_computed(sess, sess.run(summ))
|
sv.summary_computed(sess, sess.run(summ))
|
||||||
|
|
||||||
def testNoLogdirSucceeds(self):
|
def testNoLogdirSucceeds(self):
|
||||||
|
@ -12,9 +12,10 @@ filegroup(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"dist/index.html",
|
"dist/index.html",
|
||||||
"dist/tf-tensorboard.html",
|
"dist/tf-tensorboard.html",
|
||||||
"//tensorflow/tensorboard/bower:bower",
|
|
||||||
"TAG",
|
"TAG",
|
||||||
] + glob(["lib/**/*"]),
|
"//tensorflow/tensorboard/bower:bower",
|
||||||
|
"//tensorflow/tensorboard/lib:all_files",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
py_binary(
|
py_binary(
|
||||||
|
@ -5,7 +5,7 @@ TensorFlow runs and graphs. TensorBoard currently supports four visualizations:
|
|||||||
scalars, images, histograms, and the graph.
|
scalars, images, histograms, and the graph.
|
||||||
|
|
||||||
You can play with an interactive demo TensorBoard at
|
You can play with an interactive demo TensorBoard at
|
||||||
[tensorflow.org/tensorboard/cifar.html](https://www.tensorflow.org/tensorboard/cifar.html).
|
[tensorflow.org/tensorboard](https://www.tensorflow.org/tensorboard).
|
||||||
|
|
||||||
This README gives an overview of key concepts in TensorBoard, as well as how to
|
This README gives an overview of key concepts in TensorBoard, as well as how to
|
||||||
interpret the visualizations TensorBoard provides. For an in-depth example of
|
interpret the visualizations TensorBoard provides. For an in-depth example of
|
||||||
|
66
tensorflow/tools/benchmark/BUILD
Normal file
66
tensorflow/tools/benchmark/BUILD
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Description:
|
||||||
|
# Benchmark utility that can run on desktop and Android.
|
||||||
|
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
|
load("//tensorflow:tensorflow.bzl", "tf_copts")
|
||||||
|
|
||||||
|
exports_files(["LICENSE"])
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "benchmark_model_lib",
|
||||||
|
srcs = [
|
||||||
|
"benchmark_model.cc",
|
||||||
|
],
|
||||||
|
copts = tf_copts(),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = select({
|
||||||
|
"//tensorflow:android": [
|
||||||
|
"//tensorflow/core:android_tensorflow_lib",
|
||||||
|
],
|
||||||
|
"//conditions:default": [
|
||||||
|
"//tensorflow/core:core_cpu",
|
||||||
|
"//tensorflow/core:lib",
|
||||||
|
"//tensorflow/core:framework",
|
||||||
|
"//tensorflow/core:framework_internal",
|
||||||
|
"//tensorflow/core:protos_all_cc",
|
||||||
|
"//tensorflow/core:tensorflow",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
# This binary may be built for either desktop or Android.
|
||||||
|
# A typical Android build command will look like the following:
|
||||||
|
# bazel build -c opt tensorflow/core:android_tensorflow_lib \
|
||||||
|
# --crosstool_top=//external:android/crosstool \
|
||||||
|
# --cpu=armeabi-v7a \
|
||||||
|
# --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
|
||||||
|
#
|
||||||
|
# NOTE: currently '-pthread' must be removed from the LINK_OPTS variable
|
||||||
|
# in google/protobuf/BUILD to sucessfully build for Android. This is temporary
|
||||||
|
# pending an update of the version of the protobuf library that Tensorflow
|
||||||
|
# uses.
|
||||||
|
cc_binary(
|
||||||
|
name = "benchmark_model",
|
||||||
|
copts = tf_copts(),
|
||||||
|
linkopts = select({
|
||||||
|
"//tensorflow:android": [
|
||||||
|
"-pie",
|
||||||
|
"-s",
|
||||||
|
"-landroid",
|
||||||
|
"-ljnigraphics",
|
||||||
|
"-llog",
|
||||||
|
"-lm",
|
||||||
|
"-z defs",
|
||||||
|
"-s",
|
||||||
|
"-Wl,--icf=all", # Identical Code Folding
|
||||||
|
"-Wl,--exclude-libs,ALL", # Exclude syms in all libs from auto export
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
linkstatic = 1,
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [":benchmark_model_lib"],
|
||||||
|
)
|
57
tensorflow/tools/benchmark/README.md
Normal file
57
tensorflow/tools/benchmark/README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Tensorflow Model Benchmark Tool
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
A simple C++ binary to benchmark a compute graph and its individual operators,
|
||||||
|
both on desktop machines and on Android.
|
||||||
|
|
||||||
|
## To build/install/run
|
||||||
|
|
||||||
|
### On Android:
|
||||||
|
|
||||||
|
(1) build for your specific platform, e.g.:
|
||||||
|
```bash
|
||||||
|
$bazel build -c opt \
|
||||||
|
--crosstool_top=//external:android/crosstool \
|
||||||
|
--cpu=armeabi-v7a \
|
||||||
|
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
|
||||||
|
tensorflow/tools/benchmark:benchmark_model
|
||||||
|
```
|
||||||
|
|
||||||
|
(2) Connect your phone. Push the binary to your phone with adb push
|
||||||
|
(make the directory if required):
|
||||||
|
```bash
|
||||||
|
$adb push bazel-bin/tensorflow/tools/benchmark/benchmark_model /data/local/tmp
|
||||||
|
```
|
||||||
|
|
||||||
|
(3) Push the compute graph that you need to test. For example:
|
||||||
|
adb push tensorflow_inception_graph.pb /data/local/tmp
|
||||||
|
|
||||||
|
(4) Run the benchmark. For example:
|
||||||
|
```bash
|
||||||
|
$adb shell "/data/local/tmp/benchmark_model \
|
||||||
|
--graph=/data/local/tmp/tensorflow_inception_graph.pb \
|
||||||
|
--input_layer="input:0" \
|
||||||
|
--input_layer_shape="1,224,224,3" \
|
||||||
|
--input_layer_type="float" \
|
||||||
|
--output_layer="output:0"
|
||||||
|
```
|
||||||
|
### On desktop:
|
||||||
|
(1) build the binary
|
||||||
|
```bash
|
||||||
|
$bazel build -c opt tensorflow/tools/benchmark:benchmark_model
|
||||||
|
```
|
||||||
|
|
||||||
|
(2) Run on your compute graph, similar to the Android case but without the need of adb shell.
|
||||||
|
For example:
|
||||||
|
```bash
|
||||||
|
$bazel-bin/tensorflow/tools/benchmark/benchmark_model \
|
||||||
|
--graph=tensorflow_inception_graph.pb \
|
||||||
|
--input_layer="input:0" \
|
||||||
|
--input_layer_shape="1,224,224,3" \
|
||||||
|
--input_layer_type="float" \
|
||||||
|
--output_layer="output:0"
|
||||||
|
```
|
||||||
|
|
||||||
|
The Inception graph used as an example here may be downloaded from
|
||||||
|
https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip
|
225
tensorflow/tools/benchmark/benchmark_model.cc
Normal file
225
tensorflow/tools/benchmark/benchmark_model.cc
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
|
// A C++ binary to benchmark a compute graph and its individual operators,
|
||||||
|
// both on desktop machines and on Android.
|
||||||
|
//
|
||||||
|
// See README.md for usage instructions.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "tensorflow/core/framework/graph.pb.h"
|
||||||
|
#include "tensorflow/core/framework/tensor.h"
|
||||||
|
#include "tensorflow/core/graph/algorithm.h"
|
||||||
|
#include "tensorflow/core/graph/graph.h"
|
||||||
|
#include "tensorflow/core/graph/graph_constructor.h"
|
||||||
|
#include "tensorflow/core/lib/strings/str_util.h"
|
||||||
|
#include "tensorflow/core/lib/strings/strcat.h"
|
||||||
|
#include "tensorflow/core/platform/env.h"
|
||||||
|
#include "tensorflow/core/platform/init_main.h"
|
||||||
|
#include "tensorflow/core/platform/logging.h"
|
||||||
|
#include "tensorflow/core/platform/types.h"
|
||||||
|
#include "tensorflow/core/public/session.h"
|
||||||
|
#include "tensorflow/core/util/command_line_flags.h"
|
||||||
|
#include "tensorflow/core/util/stat_summarizer.h"
|
||||||
|
|
||||||
|
namespace tensorflow {
|
||||||
|
|
||||||
|
// Global variables that holds the Tensorflow classifier.
|
||||||
|
static std::unique_ptr<tensorflow::Session> session;
|
||||||
|
|
||||||
|
static StatSummarizer g_stats;
|
||||||
|
|
||||||
|
struct Flags {
|
||||||
|
string graph = "/data/local/tmp/tensorflow_inception_graph.pb";
|
||||||
|
string input_layer = "input:0";
|
||||||
|
string input_layer_shape = "1,224,224,3";
|
||||||
|
string input_layer_type = "float";
|
||||||
|
string output_layer = "output:0";
|
||||||
|
int num_runs = 50;
|
||||||
|
string run_delay = "-1.0";
|
||||||
|
int num_threads = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Flags* flags; // Filled in by main()
|
||||||
|
|
||||||
|
static bool InitializeBenchmark() {
|
||||||
|
g_stats.Reset();
|
||||||
|
|
||||||
|
LOG(INFO) << "Loading Tensorflow.";
|
||||||
|
|
||||||
|
tensorflow::SessionOptions options;
|
||||||
|
tensorflow::ConfigProto& config = options.config;
|
||||||
|
if (flags->num_threads > 0) {
|
||||||
|
config.set_intra_op_parallelism_threads(flags->num_threads);
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Got config, " << config.device_count_size() << " devices";
|
||||||
|
|
||||||
|
session.reset(tensorflow::NewSession(options));
|
||||||
|
tensorflow::GraphDef tensorflow_graph;
|
||||||
|
Status s = ReadBinaryProto(Env::Default(), flags->graph, &tensorflow_graph);
|
||||||
|
if (!s.ok()) {
|
||||||
|
LOG(ERROR) << "Could not create Tensorflow Graph: " << s;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = session->Create(tensorflow_graph);
|
||||||
|
if (!s.ok()) {
|
||||||
|
LOG(ERROR) << "Could not create Tensorflow Session: " << s;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the proto to save memory space.
|
||||||
|
tensorflow_graph.Clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RunBenchmark() {
|
||||||
|
DataType input_data_type;
|
||||||
|
CHECK(DataTypeFromString(flags->input_layer_type, &input_data_type))
|
||||||
|
<< flags->input_layer_type << " was an invalid type";
|
||||||
|
|
||||||
|
std::vector<int32> sizes;
|
||||||
|
CHECK(str_util::SplitAndParseAsInts(flags->input_layer_shape, ',', &sizes))
|
||||||
|
<< "Incorrect size string specified: " << flags->input_layer_shape;
|
||||||
|
TensorShape input_shape;
|
||||||
|
for (int i = 0; i < sizes.size(); ++i) {
|
||||||
|
input_shape.AddDim(sizes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tensor input_tensor(input_data_type, input_shape);
|
||||||
|
|
||||||
|
switch (input_data_type) {
|
||||||
|
case DT_INT32: {
|
||||||
|
auto int_tensor = input_tensor.flat<int32>();
|
||||||
|
int_tensor = int_tensor.constant(0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DT_FLOAT: {
|
||||||
|
auto float_tensor = input_tensor.flat<float>();
|
||||||
|
float_tensor = float_tensor.constant(0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DT_QUINT8: {
|
||||||
|
auto int_tensor = input_tensor.flat<quint8>();
|
||||||
|
int_tensor = int_tensor.constant(0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG(FATAL) << "Unsupported input type: " << flags->input_layer_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<string, tensorflow::Tensor> > input_tensors(
|
||||||
|
{{flags->input_layer, input_tensor}});
|
||||||
|
|
||||||
|
std::vector<tensorflow::Tensor> output_tensors;
|
||||||
|
std::vector<string> output_names({flags->output_layer});
|
||||||
|
|
||||||
|
tensorflow::Status s;
|
||||||
|
|
||||||
|
RunOptions run_options;
|
||||||
|
run_options.set_trace_level(RunOptions::FULL_TRACE);
|
||||||
|
RunMetadata run_metadata;
|
||||||
|
|
||||||
|
s = session->Run(run_options, input_tensors, output_names, {},
|
||||||
|
&output_tensors, &run_metadata);
|
||||||
|
|
||||||
|
assert(run_metadata.has_step_stats());
|
||||||
|
|
||||||
|
const StepStats& stats = run_metadata.step_stats();
|
||||||
|
|
||||||
|
g_stats.ProcessStepStats(stats);
|
||||||
|
|
||||||
|
if (!s.ok()) {
|
||||||
|
LOG(ERROR) << "Error during inference: " << s;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tensorflow
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
tensorflow::flags = new tensorflow::Flags();
|
||||||
|
|
||||||
|
const bool parse_result = tensorflow::ParseFlags(
|
||||||
|
&argc, argv,
|
||||||
|
{
|
||||||
|
tensorflow::Flag("graph", &tensorflow::flags->graph),
|
||||||
|
tensorflow::Flag("input_layer", &tensorflow::flags->input_layer),
|
||||||
|
tensorflow::Flag("input_layer_shape",
|
||||||
|
&tensorflow::flags->input_layer_shape),
|
||||||
|
tensorflow::Flag("input_layer_type",
|
||||||
|
&tensorflow::flags->input_layer_type),
|
||||||
|
tensorflow::Flag("output_layer", &tensorflow::flags->output_layer),
|
||||||
|
tensorflow::Flag("num_runs", &tensorflow::flags->num_runs),
|
||||||
|
tensorflow::Flag("run_delay", &tensorflow::flags->run_delay),
|
||||||
|
tensorflow::Flag("num_threads", &tensorflow::flags->num_threads),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!parse_result) {
|
||||||
|
LOG(ERROR) << "Error parsing command-line flags.";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::tensorflow::port::InitMain(argv[0], &argc, &argv);
|
||||||
|
if (argc > 1) {
|
||||||
|
LOG(ERROR) << "Unknown argument " << argv[1];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Graph: [" << tensorflow::flags->graph << "]";
|
||||||
|
LOG(INFO) << "Input layer: [" << tensorflow::flags->input_layer << "]";
|
||||||
|
LOG(INFO) << "Input shape: [" << tensorflow::flags->input_layer_shape << "]";
|
||||||
|
LOG(INFO) << "Input type: [" << tensorflow::flags->input_layer_type << "]";
|
||||||
|
LOG(INFO) << "Output layer: [" << tensorflow::flags->output_layer << "]";
|
||||||
|
LOG(INFO) << "Num runs: [" << tensorflow::flags->num_runs << "]";
|
||||||
|
LOG(INFO) << "Inter-run delay (seconds): [" << tensorflow::flags->run_delay
|
||||||
|
<< "]";
|
||||||
|
LOG(INFO) << "Num threads: [" << tensorflow::flags->num_threads << "]";
|
||||||
|
|
||||||
|
if (!tensorflow::InitializeBenchmark()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the run_delay string into a timespec.
|
||||||
|
const double sleep_seconds =
|
||||||
|
std::strtod(tensorflow::flags->run_delay.c_str(), nullptr);
|
||||||
|
timespec req;
|
||||||
|
req.tv_sec = static_cast<time_t>(sleep_seconds);
|
||||||
|
req.tv_nsec = (sleep_seconds - req.tv_sec) * 1000000000;
|
||||||
|
|
||||||
|
LOG(INFO) << "Running benchmark";
|
||||||
|
for (int i = 0; i < tensorflow::flags->num_runs; ++i) {
|
||||||
|
if (!tensorflow::RunBenchmark()) {
|
||||||
|
LOG(INFO) << "Failed on run " << i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If requested, sleep between runs for an arbitrary amount of time.
|
||||||
|
// This can be helpful to determine the effect of mobile processor
|
||||||
|
// scaling and thermal throttling.
|
||||||
|
if (sleep_seconds > 0.0) {
|
||||||
|
nanosleep(&req, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tensorflow::g_stats.PrintStepStats();
|
||||||
|
return 0;
|
||||||
|
}
|
@ -139,6 +139,16 @@ else
|
|||||||
# Assume: PYTHON_BIN_PATH is exported by the script above
|
# Assume: PYTHON_BIN_PATH is exported by the script above
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Obtain the path to head/ghead binary (for log file printing)
|
||||||
|
HEAD_BIN="ghead"
|
||||||
|
if [[ -z $(which "${HEAD_BIN}") ]]; then
|
||||||
|
# This is not Mac (which uses coreutils/ghead), use head.
|
||||||
|
HEAD_BIN="head"
|
||||||
|
if [[ -z $(which "${HEAD_BIN}") ]]; then
|
||||||
|
die "Unable to obtain path to head or ghead"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z "${PYTHON_BIN_PATH}" ]]; then
|
if [[ -z "${PYTHON_BIN_PATH}" ]]; then
|
||||||
die "PYTHON_BIN_PATH was not provided. If this is not virtualenv, "\
|
die "PYTHON_BIN_PATH was not provided. If this is not virtualenv, "\
|
||||||
"did you run configure?"
|
"did you run configure?"
|
||||||
@ -371,7 +381,7 @@ while true; do
|
|||||||
|
|
||||||
echo " Log @: ${TEST_LOGS[K]}"
|
echo " Log @: ${TEST_LOGS[K]}"
|
||||||
echo "============== BEGINS failure log content =============="
|
echo "============== BEGINS failure log content =============="
|
||||||
head --lines=-1 "${TEST_LOGS[K]}"
|
"${HEAD_BIN}" --lines=-1 "${TEST_LOGS[K]}"
|
||||||
echo "============== ENDS failure log content =============="
|
echo "============== ENDS failure log content =============="
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
@ -21,7 +21,7 @@ RUN /var/gcloud/google-cloud-sdk/bin/gcloud components install kubectl
|
|||||||
# Install nightly TensorFlow pip
|
# Install nightly TensorFlow pip
|
||||||
# TODO(cais): Should we build it locally instead?
|
# TODO(cais): Should we build it locally instead?
|
||||||
RUN pip install \
|
RUN pip install \
|
||||||
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Copy test files
|
# Copy test files
|
||||||
COPY scripts /var/tf-dist-test/scripts
|
COPY scripts /var/tf-dist-test/scripts
|
||||||
|
@ -36,7 +36,7 @@ RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
|
|||||||
|
|
||||||
# Install TensorFlow CPU version from nightly build
|
# Install TensorFlow CPU version from nightly build
|
||||||
RUN pip --no-cache-dir install \
|
RUN pip --no-cache-dir install \
|
||||||
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Copy files, including the GRPC server binary at
|
# Copy files, including the GRPC server binary at
|
||||||
# server/grpc_tensorflow_server.py
|
# server/grpc_tensorflow_server.py
|
||||||
|
@ -38,7 +38,7 @@ RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
|
|||||||
|
|
||||||
# Install TensorFlow CPU version.
|
# Install TensorFlow CPU version.
|
||||||
RUN pip --no-cache-dir install \
|
RUN pip --no-cache-dir install \
|
||||||
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0rc0-cp27-none-linux_x86_64.whl
|
http://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.8.0-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
# Copy files, including the GRPC server binary at
|
# Copy files, including the GRPC server binary at
|
||||||
# server/grpc_tensorflow_server.py
|
# server/grpc_tensorflow_server.py
|
||||||
|
@ -29,7 +29,7 @@ RUN pip --no-cache-dir install \
|
|||||||
python -m ipykernel.kernelspec
|
python -m ipykernel.kernelspec
|
||||||
|
|
||||||
# Install TensorFlow CPU version.
|
# Install TensorFlow CPU version.
|
||||||
ENV TENSORFLOW_VERSION 0.8.0rc0
|
ENV TENSORFLOW_VERSION 0.8.0
|
||||||
RUN pip --no-cache-dir install \
|
RUN pip --no-cache-dir install \
|
||||||
http://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-${TENSORFLOW_VERSION}-cp27-none-linux_x86_64.whl
|
http://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-${TENSORFLOW_VERSION}-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ RUN pip --no-cache-dir install \
|
|||||||
python -m ipykernel.kernelspec
|
python -m ipykernel.kernelspec
|
||||||
|
|
||||||
# Install TensorFlow GPU version.
|
# Install TensorFlow GPU version.
|
||||||
ENV TENSORFLOW_VERSION 0.8.0rc0
|
ENV TENSORFLOW_VERSION 0.8.0
|
||||||
RUN pip --no-cache-dir install \
|
RUN pip --no-cache-dir install \
|
||||||
http://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-${TENSORFLOW_VERSION}-cp27-none-linux_x86_64.whl
|
http://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-${TENSORFLOW_VERSION}-cp27-none-linux_x86_64.whl
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ from setuptools import find_packages, setup, Command, Extension
|
|||||||
from setuptools.command.install import install as InstallCommandBase
|
from setuptools.command.install import install as InstallCommandBase
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
_VERSION = '0.8.0rc0'
|
_VERSION = '0.8.0'
|
||||||
|
|
||||||
numpy_version = "1.8.2"
|
numpy_version = "1.8.2"
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
@ -183,6 +183,7 @@ setup(
|
|||||||
'tensorboard/dist/index.html',
|
'tensorboard/dist/index.html',
|
||||||
'tensorboard/dist/tf-tensorboard.html',
|
'tensorboard/dist/tf-tensorboard.html',
|
||||||
'tensorboard/lib/css/global.css',
|
'tensorboard/lib/css/global.css',
|
||||||
|
'tensorboard/TAG',
|
||||||
] + matches,
|
] + matches,
|
||||||
},
|
},
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
Loading…
Reference in New Issue
Block a user